This is the first article of Software Architecture series that I'm planning, focusing on Unity.
The concept of Software Architecture is for me a magical one. It is unfortunately hard to define and often misunderstood. I will try to define it by how it applies to my own projects.
It is a tough concept to grasp but when looking at your own projects is easier to get the idea. Think about how your classes were described, written, separated and how the components communicate. How hard is it to maintain or expand them?
Within SA we have a lot of different architectures, patterns and principles. All kinds of ways to organize your system or to solve specific structural problems. In the middle of all these is the fantastic SOLID principles.
Have you ever heard about SOLID? Basically, it is an acronym containing 5 principles first coined by Robert C. Martin (a.k.a Uncle Bob) and popularized by Michael Feathers.
They are a series of principles to help developers create quality object oriented software.It focuses on ways to produce maintainable and flexible code.
Each letter of SOLID represents a different principle, their definition may sound complicated, but in the following chapters of this series I am going to explain each of them using real world examples in unity. The principles are as follows:
• Single Responsibility Principle: A class should have one and only one reason to change, meaning it should have only one responsability;
• Open Closed Principle: A class should be open for be extension but closed for modification;
• Liskov Substitution Principle: A subclass should be substitutable for its base class;
• Interface Segregation Principle: A client should never be forced to implement an interface that it doesn't use;
• Dependency Inversion Principle: Depend on abstractions not on concrete implementations.
As a lover of software craftsmanship, I am always looking for ways to improve my architecture, learn new patterns and practices. In this process I can honestly
say SOLID has fundamentally changed the way I develop code for the better. They give me a new way to think about my code, I can clearly see how my software skills have grown thanks to them. They are not required to write object oriented code, you can finish your game without them, but imagine finishing a game that not only works, but one where you have less headaches when maintaining it or making changes. Even better, right?
You may be wondering what exactly "Quality Code" means. What benefits do you get from applying these principles? Well, in a nutshell quality code has the below characteristics:
• Flexibility: It is easier to adapt and change, add new features;
• Modularity: The functionality of your project is well divided, making the code easier to reuse (using Monobehaviour Components is very related to that);
• Testable: Because the code is modular you can easily replace elements with mocks and have an easier time testing functionality;
• Less fragile: With less coupling your code is easier to change, then one small change does not spread through your code base, requiring you to alter a lot of functions or values;
• More human readable: Your code is easier for others to understand (and for yourself too!)
As you can see, having well written code brings a lot of advantages, it may look hard in the beginning to write code using these concepts, but with practice, using these techniques will become automatic. Eventually you will be starting each new project already dividing your application into small modular parts where you can reuse scripts from other projects, extracting interfaces from functionalities, etc.
You can be sure that writting a good code will make your future maintances 10 times easier, avoiding headaches every time you need for example add a new mechanic or to solve some bug. Let's have a look at some examples:
• You have developed an FPS game and the players have asked for new weapon types. If player shooting functionality depends of an abstraction you can simply create a new implementation and add new functionality without changing anything, everything is still working fine;
• You have found a bug when players jump. A player has a lot of functionality: Jumping, shooting, interacting with objects etc. No problem, you can just go straight to the jumping code and make changes without having to worry how those changes will affect the rest of the player;
• You realize there is an issue with both the walking and the running hability of a character. Because you reused code for both, you only have to fix it in one place and both are fixed!!
We can imagine a lot more examples that can happen in real life. In general, studying and applying these kinds of principles (not only SOLID, but others like DRY, KISS etc) will naturally make you write better code. It does not matter whether it is a racing game, an FPS or an RPG, it can be applied for every kind of game. Remember: games are still just software. The same rules and principles used in high quality enterprise software can apply in unity too.
Using SOLID won't be a miracle solution for your projects, you will still have dilemmas, indecision and questions about your architecture. Things like "Is this class divided enough?", "Should I extract an interface from this class?", "Does this derived class represent it's base class?" etc. Though asking these questions is a good thing, as you get used to solving these kinds of problems, you will save time from having to implement changes and solve problems by architecting for the future.
In the next articles, I’m going to detail each of these principles by explaining them and giving real world examples within Unity and C#.
If you liked this article or have some complaints, please let me know, your opinion is very important for the future articles of this series, specially because that’s my first article ever. Have a nice day o/