This article will be useful for juniors as well as experienced developers who have encountered application support problems. We will cover design steps that can be applied to an existing project as well.
Difficulties of project architecture
When developing an application, a programmer is faced with a question: what architecture or pattern is the best for developing a new application? There is no definite answer because there is no ideal architecture that fits 100% to any project. But choosing an architecture right away is a bad decision. There are many aspects you need to consider when choosing or creating an architecture. To convert existing code into a new efficient architecture, there’s even more to do than to do it from scratch.
The whole process is divided into three steps: Analysis, Design and Programming.
The article deals with the object-oriented approach to programming. There are others, for example you may have heard of structural or procedural approaches. The choice depends only on the developer or the customer, but in practice the customer rarely has a preference and is limited to the choice of specific technologies.
Step 1: Project Analysis
Analyzing the project as a whole gives an understanding of the problem you are solving. It will be great if the customer provides this to the development team, otherwise you will need to do the analysis yourself. Developing a model allows you to plan and diagram the operation of your system, identify the main actors who interact with the system, and define the objects with which the actors interact. And the programming stage is the process of implementing the project or system itself.
For a clear analysis, you must first define the requirements of the desired product. You can ask elementary questions: what should the created application do, what problem should it solve and why do we make it in the first place. Then we define what the application should do, what features and functionality it should contain. There may be non-functional requirements, they describe how the application should work.
As mentioned before, a good architecture is the basic foundation which directly influences the success of the application and the project as a whole, with a properly laid out architecture you or your team will find it easy to fix bugs and extend the functionality of the application without much risk and often without too much time spent.
The primary goal of application architecture is to maximize team productivity and program code quality. In addition, good architectural practices can help prevent tight software/hardware lock-in. For a more detailed analysis, you can compile FURPS+ requirements for the system. This is essentially a classification of requirements.
The abbreviation is formed from the following words:
- Functionality – functional requirements (properties, capabilities).
- Usability – the requirements for usability (UX).
- Reliability – reliability requirements.
- Performance – performance requirements.
- Supportability – support requirements.
The only requirement is that the phrases should be short and not describe the implementation.
Step 2: Design
The next important step is to write the Use Cases. They describe the interaction of the actor with the system, the actor in our case can be a separate system or a user. The prepared document with the use cases will be needed at all the stages of development, from agreement with the client to testing.
The user cases can be described by UML diagrams or in tabular form. Although UML diagrams do a great job of describing the main actor and secondary actors. For ease of understanding, I always start and emphasize the tabular representation. In practice, UML diagrams and usecase tables complement each other, not replace each other. This is important to understand and remember.
Do not try to anticipate all possible situations, describe only typical ones. But remember: the phrases or sentences used should be as short, clear and understandable as possible. Actor denotes an actor, which can be a specific user, system or other external actor.
There is no strict usecase maintenance. Developers can make their own changes and thus achieve maximum effect.
Next, we create CRC cards (Class-responsibility-collaboration cards). They help discover classes and their interactions. They usually include the name of the class, the responsibility or duties, and the other classes that are related.
A CRC card can include additional fields such as parent class, subclass, and so on. There are no strict restrictions here either.
This tool allows you to highlight classes and their responsibilities. It’s not necessary to describe the clear names of the classes in the cards; you can name them later; the main thing is to understand the nature of the future classes. You must complete the stage of the object-oriented design process, at least with names and basic responsibilities for the first set of classes you intend to program.
After the analysis, the requirements, the usecases, the SRC-maps, the conceptual model, we can start the design, namely the creation of the UML diagrams of the classes. We are not going to look at the process of creating UML diagrams. Martin Fowler’s book “UML Distilled” covers this topic in detail, it will be useful for those who are not familiar with the UML language. You will need this book if you want to go beyond the Junior developer level.
Basically, you can choose one approach or use a combination. But the more detailed you break down your project into diagrams, the easier it will be to build an application architecture close to perfect.
This tool allows you to highlight classes and their responsibilities. It is not necessary to describe the clear names of the classes in the cards, you can give them names later, the main thing is to understand the essence of the future classes. You must complete the step of the object-oriented design process, at least with names and basic responsibilities for the first set of classes you intend to program.
After the analysis, the requirements, the usecases, the SRC-maps, the conceptual model, we can start the design, namely the creation of the UML diagrams of the classes. We are not going to look at the process of creating UML diagrams. Martin Fowler’s book “UML Distilled” covers this topic in detail, it will be useful for those who are not familiar with the UML language. You will need this book if you want to go beyond the Junior developer level.
Step 3: Implementing the program code
In the last programming step, the developer implements the program code. There are different aspects of the project to consider. As I see it, a good architecture is not subject to errors when developing new functionality, requires little effort from the developer to make changes, is well covered by unit-tests and works consistently. This notion is very subjective, and you may encounter different interpretations in your lifetime, but they will all have common features.
In contrast, a bad architecture will slow down your work and the work of your team. Any changes, even small ones, can cause errors throughout the project and disrupt the work of an existing project. Based on my experience, I’ll highlight these common signs:
- The application is unstable and often produces errors.
- Your code base is difficult to understand.
- Your code is impossible or difficult to reuse. Or a lot of duplicate code.
- Constant conflicts in your code with other developers.
- Edits made to the code generate major code refactorings.
- Difficulties in writing unit tests.
- Your code takes a long time to compile.
- Adding new functionality slows down the entire team.
- Minor changes require regression tests.
- Program code implicitly affects other processes.
These are all reasons that can be solved, most often simply by applying different architecture concepts. For the most part, they have common causes. Once you are aware of them, you can protect yourself from their influence later on, which will greatly improve the quality of the code.
Also, to avoid the reasons given, you should study and understand SOLID principles, architectural patterns and design patterns. Usually all the sources only touch superficially on the various patterns, and you have to figure out the details yourself. And you can find articles on the Internet that classify some patterns as bad. In fact, there are no bad patterns, many of them are very similar to each other and have almost no differences. The accumulated baggage of knowledge will help you to achieve maximum efficiency in development. I can assert from my own practice that blindly using ready-made patterns is not always the best solution. A programmer must understand them and use their approach to solve specific tasks and modify them to the needs of the project.