Hello everyone!
We've been spending a lot of time in the last blog posts understanding what bad code is, how to objectively measure it, and even more, how to refactor a committed crime.
And now, the time comes to understand how we can brilliantly craft a well-designed (hopefully?) greenfield project that is easy to maintain, to read, and to extend in the future.
The purpose of software engineering is to control complexity not to create it
When developing software, the complexity lies in many areas, such as:
- Understanding the business requirements and using unified communication language. That is, what are the different players we have across various business domains? What is, do our customers speak? Why team A and team B have different names to the same things?
- How are we going to architect and separate different application layers? How should each project reference the other?
- How to make our code more object-oriented, clean, and reusable?
To resolve the previously mentioned challenges, we are going to discuss three things that aim to face them, respectively:
- Understanding the application domain using Domain-Driven Design
- Understanding how to architect and distinguish different parts of the application
- Doing the actual work and crafting a well-designed code based on best practices
Welcome to domain-driven design
Briding the business jargon and technical jargon are already discussed in a well-established methodology called Domain-Driven Design (DDD). In his book (Domain-Driven Design: Tackling Complexity in the Heart of Software), Eric Evans defines Domain-Driven Design as a software approach to complex needs by connecting the implementation to an evolving model. The words complex and evolving are vital traits that we see in our daily software requirements.
The main objective of DDD is to set the focus on the domain logic, which is considered the core logic. It also aims to base the software design on the business domain. And most importantly, it seeks to bridge the gap between the business domain jargon and the technology domain jargon by introducing ubiquitous language.
If you feel too lazy to read Eric Evan's book, I would like to point you to this fantastic Pluralsight course by Steve Smith and Julie Lerman.
Architecting Your Application
Another aspect that profoundly influences the maintainability and extendability of our software solution is how do we architect different decoupled layers of our application.
By saying different layers, I mean different parts of the software that have particular responsibilities. For example, the UI layer is used to designate what the user sees (Web Pages, Desktop Forms, or Mobile App). In contrast, the Infrastructure layer is used to designated external dependencies to the software such as File Systems and Drivers.
You will hear the term abstractions to refer to the fact that a specific piece of the software introduces a general level of separation that makes it possible to replace it with other components. For example, when we say that the user interface should be abstracted, that means it should be easy to replace a web page interface with a mobile interface without much changes to other parts of the code. The antonym of abstract is concrete and is used to describe a piece of software that is highly specialized in doing only one thing.
A well-architected software is abstracted just enough to be general to all foreseen business scenarios. Yet, it is concrete enough to be understandable and fast to develop. An excellent architect is always striking a balance between abstraction and concretion to develop the software according to the business strategy and forecasted product demands.
Architecting Applications for the Real World in .NET is an excellent course by Cory House that teaches how to think about your application layering. He discusses different architectural styles and presents common software layers. I would highly recommend it.
Writing well-designed code
After we knew how to understand the business jargon and map it to the technical jargon using DDD and how to architect our application to different layers, now comes the time to get into the details and learn how to design our code correctly. And by code, I do not mean application layers but rather how to ensure proper OOP (object-oriented programming) and, most importantly, adequate OOD (object-oriented design).
I would recommend two courses by Zoran Horvat to develop object programming skills
Making Your C# Code More Object-oriented by Zoran Horvat
Mastering Iterative Object-oriented Development in C#
That is it! This concludes our series on Code Quality, tell me what do you think!