Blue degree
Principles
Design and Implementation don't overlap
You'll see this very often in long running projects: the implementation is a chaos.
- Your programming language/platform supports having multiple projects in one solution but instead of isolating parts in separate projects, everything is located in a single project.
- Your programming language/platform supports namespaces, but all files are placed in a single namespace such as yourcompany.yourproject.
- Your programming language/platform supports partial files, but all methods of a type are in a single file.
- Your application requires local resources for development, but you have to install them manually before you can effectively start with your development work.
- You find well structured design documents in a wiki or in a docs folder, but the implementation seems to be for a different project.
All of these points describes the same problem, that the developers lost track at some point of how the project was planned/designed in the beginning and how it was done in the end.
It is in the nature of software development that the project has to adjust to reality. This explains minor differences between design and implementation, but not the usual chaos.
To understand how this can be improved, we have to do a root cause analysis. What might caused the mess we find in some projects?
- There was no design in the beginning at all.
- Team members left/joined during development.
- The developers had to rush due to pressure of deadlines / of the product manager.
- The developers rushed on their own in the beginning of the project to quickly show the first results but never cleaned up the mess and just continued.
You can guess what's the usual cause: the developers rushed on their own without any time pressure and simply did not work clean. In the later stages of a project is usually no time to cleanup the project due to deadlines or time pressure of the product manager.
It is a trap a lot of projects run into. A new project is small and and every extra structure seems like over-engineering it. Later, when the project grew for a while, it became a big amount of work to restructure the project. That work is postponed due to other priorities. In the end you get the mess as described above.
So, how can this be improved?
- Do not start implementing something before you have a design.
- Your design should specify at least the major architectural decisions, such as layers, modules, component (groups), etc.
- Your design should specify which external dependencies it will have and how to access them locally.
- The design should consider features of the used programming language/platform.
A good design focuses on the high-level overview and does not go too deep into the details.
Implementation Reflects Design
As we have seen above, a clear design is already required in the beginning of a project.
What can be done to have the implementation aligned with the design?
- The structure of your solution should represent the architecture.
- Isolate layers as projects. Isolate modules as projects. Isolate component (groups) as projects.
- Keep an eye on the project dependencies. The less dependencies a single project has, the better.
- Use namespaces/folders to structure the files in a project.
- Avoid using a project name as namespace. You should be able to use the same namespace in different projects.
- Use partial classes/interfaces to structure files, i.e. MyClass, MyClass.Commands, MyClass.Validation
- Provide all required dependencies in a way that your application can run locally, i.e. by using infrastructure as code.
- Have a clean architecture right from the start - avoid quick-and-dirty greenfield mess.
Planning and recurring architecture reviews are a must.
You Ain't Gonna Need It
Don't repeat yourself (DRY), but also don't implement things you might not need later - you ain't gonna need it (YAGNI) anyway.
These two principles are the most often violated principles.
- DRY because of copy & paste
- YAGNI because of passionate developers
Developers who love what they do want to provide the best code possible. That kind of dedication often leads to too advanced solutions, or better: to early advanced solution. A simpler solution for a problem might be enough for the state a project is in at that time. A very advanced solution adds complexity which might never be used.
You can try following these advices:
- The product owner specifies the requirements of features and prioritizes them.
- Implement features with clear requirements only.
- Split features into small chunks of work which can be done in a time that can be reasonably estimated.
A good team show patience with their passionate developers.
Practices
Design before Implementation
Before writing code, the requirements of the feature to implement must be clear. Have refinements with the team and the product owner to clarify the requirements and specify acceptance criteria. Create a design document if needed.
Plan this as a weekly routine in your team.
Continuous Delivery
Previously we talked about continuous integration to identify integration issues as soon as possible in the process.
Continuous delivery is to provide running deployments at different stages to the customer.
Depending on the kind of your application, this can mean to provide:
- installable software to the customer (i.e. for air-gaped environments)
- container images
- update to one or more Dev/Test/UAT/Production environments
A deployment shall be automated and not require more than an approval of authorized persons.
A Dev environment is for developers to test their latest version and to run integration tests.
A Test/UAT environment is for the customer and QA to test the latest pre-release version.
A Production environment is for the customer to run the latest release version.
Iterative Development
Modern software development follows agile methods. Despite the waterfall-process, an agile process works in iterations by repeating the same process over and over again until the product is finished. Usually this means that there is a feedback loop of planning, implementing and testing. A project starts with an idea of what the product shall do in the end and a rough plan of how to achieve that goal. In a continuous process of learning and improving the project gets closer in meeting the expectations every performed iteration.
An iteration can be a time frame of one, two or three weeks or calendar months, whatever the customer and developer team prefers. Working in iterations following an agile process creates some time overhead. Due to that fact, a cycle should not be too short. A cycle should not the too long either, to get feedback from the user/customer frequently.
At the beginning of an iteration, features/requirements are selected for that iteration and a goal for that iteration is specified. The team aims to reach that goal until the end of the iteration. This makes it so important to specify acceptance criteria for features/requirements, so that the team knows what is good enough. If the goal can't be reached, the iteration is declared as failed and a new iteration should be started with a new planning. The results of an iteration are presented to the users/customer at the end of the iteration.
Incremental Development
Incremental Development means, to provide usable/working results of the software to the customer as soon as possible and to not work until the entire project is done to then handover everything at once.
As described above for continuous delivery, the customer/user should have access to parts of the application to be able to give feedback to the developers.
The goal is to keep the feedback interval short.
Component Orientation
Most of the time we talked about small parts of code, such as classes and methods. From a high-level perspective, designing (reusable, independent) components should be the goal.
But what is a component?
A component is an independent part of your project which could be reused. A component can consist of a single class or a group of classes and interfaces which work together. An example would be the way how your application does logging, track and publish metrics or components of your user interface. Those parts might be generic and not specific for your application. Due to that, you can refactor them to make them a separate component.
Modern programming languages/platforms support package management systems. Your components can then be deployed and used as packages. This reduces the complexity in your application but also for the created package.

The composition is the organized sum
of the interior functions of every part of the work.
Test First
Test-Driven-Design (TDD) is maybe the best way of developing software. Its major goal is to identify issues as soon as possible, which means during development. By implementing the tests while you're implementing your component also builds this safety-net for refactorings and later changes as mentioned before.
Similar to the 5-Why?s, Test First! seems to be a good statement to keep in mind during the entire software development phase.

Ask Why? at least five times.
Test first could also mean, to add a red-test when you investigate a reported bug. Red-Test means, that you implement a unit test which reproduces the reported bug and fails - the test status turns red. Then you fix the bug and the test status turns green. Keep that unit test to avoid the the bug appear again later.
Test first could also mean, to evaluate and test new frameworks and new techniques before you use them in your projects.