"When we are asked to carry out the software design, the thing that immediately strikes to some of us is - a big picture of Design Patterns, Block Diagrams, UML Diagrams, CASE tools etc. And this is where some of us either shy away from or misinterpret the design job. But design is mainly about our approach to the problem and all the above are merely tools and means that may complement the job."
Let us look into why is that so?
In the article “What is TDD made for?”, we discussed the approach to TDD by doing a small exercise on “building an elevator system”.
Let me copy & paste some text from that article for our quick reference:
What are the different requests and how they need to be processed?
(External Request) Elevator has to go to a floor if there is User request from that floor.
----Elevator has to move UP if the request is from an upper floor.
----Elevator has to move DOWN if the request is from a lower floor.
(Internal Request) Elevator has to go to a floor if there is User(inside elevator) request to go to that floor.
----Elevator has to move UP if the request is to an upper floor.
----Elevator has to move DOWN if the request is to a lower floor.
When does the elevator stop?
----Elevator has to STOP at a floor if there is an external request or internal request to stop at that floor?
What happens when the elevator stops at a floor?
---- Open the Door
---- Update the internal request as DONE or DISCARD.
---- Allow time for passenger to Get-In and Get-Out
---- Handle max-load checking, if any
---- Close the door
---- Update the external request as DONE or DISCARD.
---- (Well, I am not writing all other features (light, fan, displays etc.) of our modern elevators as we are not really going to write the software here)
Well, this has also ended up as a TODO for us but we have added very good set of testcases coming up in the form of “executable specifications”, and what do good “executable specifications” do? They feed to the design and that’s what has happened now – we need another Black Box((a decision-making method) to decide whether to move up or move down. Also, we have identified the parameters(variables) that these decision-making methods need.
Along with this, we have identified different actions (Just execute them – moveUp, moveDown, Open, Close). Also, we have, almost, identified the Data Structures to store the User Requests (Internal and External). Overall, our skeleton code is pretty much visible now.
Now, let us analyze what we have done purely from a design point of view.
The first step in design is problem analysis - Get it Right in Plain Text.
If we look at the above example, Software Design can be seen as a hidden characteristic of a given problem. The more we try to understand the problem behavior and its constraints (may be you can formally call it as analysis), the better input for the design comes out. Thus the design is discovered than applied.
--Let us not try to solve the problem before understanding it. A problem that is well understood is half-solved.
--Problem analysis doesn’t have a language or technology associated with it. It is merely to do with our cognitive (analytical and reasoning) approach which is always of paramount importance.
--A good problem analysis would give us better requirements for the design.
Here, in this example, we have derived the following design requirements in a plain text like this:
---- We need "decision making" mechanisms for:
------- Deciding the Direction the Elevator moves
------- Deciding whether the Elevator stops at a Floor
---- We need "action" mechanisms for:
(Please note that the list above is conceptual, not complete)
The next step is program analysis - Get it Right with your technology.
Now that we know what is expected out of the design, it is the stage for the program analysis - how do we implement the design in our programming language or with our technology, and this is where our technical skillset comes into picture.
For example, once we have understood the basic in-built design of the above elevator problem...
---- If we are implementing in a procedural language, we would probably be passing different datastructures from method to method or probably handle them as global variables or something similar, and read and manipulate them from different methods.
---- If it is OOAD, all the above actions would be encapsulated in an Elevator Object and with our problem analysis, it has already come out as a State Machine Model for us.
So, the design has to be seen as a problem analysis followed by program analysis. Merely knowing a set of design patterns or frameworks cannot make someone good at design.
It’s about a smooth transition of a business problem into technical problem and then to a technical solution by applying analytical and reasoning skills.
Of course, there might be requirements that are technical in nature where our problem analysis and technical analysis may overlap to some extent but our logical approach would be the same. Same goes with the requirements that are high-level where the design decisions would be of the nature like - which WebService to use or which XML Library to use etc.
What if a proper Problem Analysis is NOT done?
--If a proper (I'm not saying perfect) problem analysis is not done, we are adding more variables to the equation. We are mixing up number of business logic variables and programming logic variables. And I don't need to explain further on what it costs.
--There would be considerable refactoring and rework done adding to longer implementation cycles.
Has your team discussed the problem enough before discussing the solution(design)?
Are you ensuring that your team is doing enough exercise to get the 'design requirements' in plain text?
Is your team doing a smooth transition of problem to technology, than jumping straight on to a technical solution?
(Attribution: Images on this post are downloaded from FreeDigitalPhotos.Net)