Test-Driven Development (TDD)
Before defining what TDD is, we should emphasize the importance of writing tests for your software. Even though it may sound very intuitive that tests are essential for any program, developers tend to avoid writing them claiming that they trust their work and that testing it manually is enough to ensure that is working "just fine".
Another problem that arises when writing tests, is the quality of these tests. If your test suite (and this is a name often called on your test set) doesn't make you feel comfortable changing anything in the code with certainty that you haven't broken any of it, then these tests are not enough.
This is where TDD Comes in hand. Test-Driven Development is the behavior of writing the tests first; i.e. before writing the code! As strange as it might sound, TDD is a well-known and well-used behavior, and it is effective to reach a high-quality set of tests.
The idea of writing tests first goes as follows:
- you write the minimum amount of tests needed to make it fail (and compilation error is considered a failure here)
- you then write the minimum amount of code needed to make the tests pass
You simply keep on repeating steps 1 and 2 until the development is done. Then you'll end up with the following:
- code that is fully tested
- high-quality test suite by ensuring that your tests cover all the possible scenarios of execution
- tests that qualify as a documented entry point for the reader to understand what your code does
What the last is about is that your tests will eventually cover things as simple as how to create an instance of a class, growing up in complexity to reach the most sophisticated operations done by the program.
Domain-Driven Design (DDD)
The motivation behind DDD is that the architecture of your project should reflect the domain of the project rather than the tools or frameworks you used to develop it. For instance, let's take the following solution structure:
This photo shouts saying "I am a .NET project. I am a web project. I use MVC architecture..." well, yeah, but what are you about? no idea...
What DDD suggests is the following:
- the framework you are using is just a tool, which your project should not be dependent on
- the structure of your project should be reflective of what the project does and is about
- separation of concerns can be achieved through the Onion Architecture
The Onion Architecture
It is a layered software architecture that implies separation of concerns through a clean distributed vision. There are different versions of it, however, they don't differ at the level of the core principles behind it. A simple version of the onion architecture is shown in the figure below:
As you can see, the architecture diagram shows a layered structure similar to the one of the onion, thus the name: onion architecture. This architecture states the following:
The domain level
- it is where you define your models and domain-related classes; e.g. if you are working on software for a library, here is where you add the classes that represent books, copies, shelves, etc.
- it doesn't depend, at compile-time, on any other part of the project.
- it doesn't contain any details related to other levels, such as databases, presentation infrastructure (web, mobile application, etc.). This ensures ease of modification in the future.
The application level
- it is where you define the core logic related to the operations to be acted on the domain; i.e. creation of instances, updating objects states, etc.
- it depends directly on the domain level only. Notice that this layer is agnostic on what type of persistence mechanism is being used.
The infrastructure level
- this is where you implement your persistence mechanism if needed.
- it only depends on the application layer
- it should be isolated enough to make it easy in the future for modification; e.g. if you want to replace a DB vendor with another one.
The presentation level
- this defines how you will be presenting the data to the user. It can be a web application, desktop application, etc. Notice here how this became a minor detail, as opposed to how it was the core of the project in the structure shown earlier
Here is another project structure following the onion architecture:
As you can see:
- the domain project contains our core classes
- the application project contains services that act on the objects' state, and it defines the interfaces expected from the persistence layer to implement, they are located in the Persistence folder.
- the persistence project contains the repositories and the entities representations of the core classes. These entities can be coupled to the DB vendor being used, as it is easy to replace.
- the presentation project, in this case, is a web application, which is a minor detail that doesn't need to be under the spotlight.
- the main project is where we connect it all together.
Containerization
Another important tool to become independent from your infrastructure is containerization, but before digging into its concepts, let's go over some scenarios. When working on a new project, you will need to consider shipping it and making it available for production. Developers often choose their tech stack based on what is available in the market for hosting servers and whatsoever, and this is wrong behavior. By doing so, you are coupling yourself to a service offered by a third party! What you should be doing is choosing your tools based on what most fits your solution, then worry about finding a good hosting service that fits what you chose. However, the problem might be that you may not find something in your budget range. Here is where containerization comes into action.
Containerization is the concept of running your project in a container (similar to a virtual machine); i.e. when you need to ship it, you deploy the whole container containing your project and all that it needs to run, such as OS, infrastructure, and other dependencies. This way, you only worry about finding a hosting service that supports deploying containers, and there are many.
Containerization also solves many other issues, such as having the same experience when running the project in development mode or in production, since in all cases, the container is agnostic of the physical machine's infrastructure.
Docker is one of the best active solutions to achieve containerization, so learning it early in your career will help you a lot with your future work.