Software design - With flow design to clean code
No Big Design Upfront
Software systems are quite complex entities these days. Simply programming away during development quickly leads to problems: you no longer understand your own code. Only code that complies with the Clean Code Developer principles enables developers to continue developing the software in the long term. The requirements of today's software systems can only be implemented with proper planning. This means that a Solution must be designedbefore you can start implementing them. The clean code principles are fundamental. But there is always the question of how to come up with an idea to build the code in such a way that the principles are adhered to.
To avoid going back to the waterfall where we tried to plan everything in advance, a lightweight methodology is required. The design must be agile and therefore iterative and incremental. This is exactly what Flow Design does. In each individual iteration, a small section of the system is designed and then implemented. This makes Flow Design a perfect fit for the recommendation: No Big Design Upfront.
Flow Design
The notation is simple and consists of only a few symbols.ย Flow Design was developed by Ralf Westphal and Stefan Lieser.ย The procedure is independent of a specific programming language.ย In particular, it is not designed for functional programming,ย The aim in developing Flow Design was to define a simple type of diagram that makes it easy to design solutions.
The basis of a design with Flow Design are functional units. In the subsequent implementation, these are implemented as methods or classes. The core idea of flow design is to define functional units and work out which data flows connect them. It is therefore a bottom-up approachwhere we first think about which steps are required to solve a problem. This results in the functional units and the connecting data flows. Only shortly before implementation do we consider whether and how to combine methods into classes or files.
In the following, I will only use the term class. In programming languages or paradigms in which these are not required, methods must at least be summarized in files. In this respect, class is also synonymous with file.
ย
The core idea of flow design is to define functional units and work out which data flows connect them.
With flow design to clean code
Thinking specifically about a solution before implementing it will improve the quality of the code. At the same time, we can observe that there is a clear difference between top-down and bottom-up approaches. For example, if you use UML in the usual top-down methodology, you start with a class diagram. But how can I seriously come up with good class candidates without knowing which individual steps are required to solve the problem at hand? If, on the other hand, you take a bottom-up approach and think about the individual steps first, the structure results in a very natural way virtually by itself. It is now possible to decide whether methods have such a high cohesion that it makes sense to keep them in a common class. This results in a class structure that is based on cohesion from the outset and therefore the Single Responsibility Principle (SRP) is designed. Furthermore, this creates classes that are definitely clear that they are actually needed. With the top-down approach, you have to fish in the dark because it is not yet clear which functionality is required in detail. If you think about the functionality first, it is easier to discover the structure.
Dependencies
Another challenge with a top-down approach lies in the dependency structure. Not only is it difficult to come up with good candidates for classes, they also have to be packed into a structure. As the solution to the problem at hand is not really understood at this stage, code structures are created that often prove difficult to implement later on. And this is primarily due to the dependencies between the classes.
In software development Dependencies one of the main problems represent. If the dependencies are not well chosen, large Challenges in automated testing. Often nothing works at all, or dummies are used and the tests are extensively formulated and difficult to understand.
The Dependency Inversion Principle (DIP) offers an initial solution here. With the Integration Operation Segregation Principle (IOSP) is a further development with many advantages. I have written about this in detail elsewhere and I don't want to repeat myself here. However, I would like to point out that the design with flow design leads quite naturally to structures that comply with the IOSP. The result of such a design is therefore an optimal structure of dependencies: easy testability and good readability are easily achieved.
In terms of IOSP, the design with flow design ensures that the methods contain logic that was not further refined in the design. At the same time, these methods do not call any other methods of the solution, so that they can be regarded asย Operation can be designated. Functional units that have been refined in the design, on the other hand, contain no logic. Their task is to create the data flow that results from the refinement. These are therefore methods whose task is to Integration is. This results in compliance with the IOSP naturally from the design. You save yourself a lot of refactoring because you have thought about it beforehand. The code structure is therefore easy to understand and easy to test. Once a solution has been designed, coding is quick and easy, as classes and methods and their interactions have already emerged from the design.
TDD is dead - maybe design is too
In my opinion, Test Driven Development is completely outdated. Kent Beck has published his Book about TDD Published at the end of 2002. The idea of testing a program before implementing it sounds clever. But it quickly became apparent, that TDD alone does not result in optimal software structures. The approach may work for manageable problems. It is not possible to set up an entire application with it.
ChatGPT and other AIs are currently creating a completely different challenge: if we as developers specify the tests, the AI can deliver the implementation. Nobody has to read, understand and change this generated code. As long as the tests are green, everything is ok. If new requirements arise, the corresponding tests are added and the code is regenerated by the AI. This can be described as test-first, with the difference that the implementation is carried out by the AI instead of the developer.
In my opinion, it is not yet possible to predict what AI will mean for design. Design may also become superfluous in the future if we manage to make the requirements and the associated tests clear to the AI and the code is generated from this. As long as developers have to do most of the implementation or at least provide the structure, there is no way around the design.
An example
You can find our classic example of a CSV viewer on the Flow Design Website.
Conclusion
Flow Design is a lightweight design method. Anyone who has struggled with UML should definitely give Flow Design a try. You can find a good overview of the procedure in the introductory chapter of my book "With flow design to clean code". I would be happy to send you the introductory chapter. To familiarize yourself with the procedure, it is helpful to watch one of our Exercises with a flow design concept.