The document discusses the SOLID design principles for writing maintainable and extensible code. It defines each principle - Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. For each principle, it provides an explanation of what the principle means and how to apply it. It also warns that SOLID principles are guidelines, not rules, and to use common sense over rigidly following the principles. The overall goal of SOLID is to create code that is easy to maintain, extend and understand.
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Becoming a better developer by using the SOLID design principles
1. Becoming a better developer by using
the SOLID design principles
How to write code that’s easy to maintain, extend and understand
2. Katerina
Trajchevska
● Senior Software Engineer & co-
founder of Adeva
● Remote Work Advocate
● Community Volunteer
● Consultant with startups and
Fortune 500 companies
Software Engineer and co-
founder of Adeva
3. @ktrajchevska
Working on legacy code
● Re-reading code multiple times to get to the part you need to change
● Hard to understand what a method does
● Spending a lot of time to fix a minor bug
● You spend more time reading than writing code.
4.
5. @ktrajchevska
Working on a startup product
● In charge of the development process
● Constantly adding new features
● No formal process
● Very dynamic environment, no time to worry about code structure
● What is it like to go back to your code after 2 years?
6. @ktrajchevska
What will we talk about today?
● What is SOLID and how it can make our lives easier
● What’s the purpose of each of the SOLID design principles
● How to not use SOLID
7. @ktrajchevska
The purpose of SOLID design principles
● To make the code more maintainable.
● To make it easier to quickly extend the system with new functionality without
breaking the existing ones.
● To make the code easier to read and understand, thus spend less time figuring
out what it does and more time actually developing the solution.
● Introduced by Robert Martin (Uncle Bob), named by Michael Feathers.
10. @ktrajchevska
Single Responsibility Principle
● A class should only be responsible for one thing.
● There’s a place for everything and everything is in its place.
● Find one reason to change and take everything else out of the class.
● Very precise names for many small classes > generic names for large classes.
16. @ktrajchevska
Open/Closed Principle
● An entity should be open for extension but closed for modification.
● Extend functionality by adding new code instead of changing existing code.
● Separate the behaviors, so the system can easily be extended, but never
broken.
● Goal: get to a point where you can never break the core of your system.
17.
18.
19.
20.
21.
22.
23.
24. Liskov Substitution Principle
Let φ(x) be a property provable about objects x of type T.
Then φ(y) should be true for objects y of type S where S is
a subtype of T.
25. @ktrajchevska
Liskov Substitution Principle
● Any derived class should be able to substitute its parent class without the
consumer knowing it.
● Every class that implements an interface, must be able to substitute any
reference throughout the code that implements that same interface.
● Every part of the code should get the expected result no matter what instance
of a class you send to it, given it implements the same interface.
32. @ktrajchevska
Interface Segregation Principle
● A client should never be forced to depend on methods it doesn't use.
● Or, a client should never depend on anything more than the method it’s calling.
● Changing one method in a class shouldn’t affect classes that don’t depend on
it.
● Replace fat interfaces with many small, specific interfaces.
38. @ktrajchevska
Dependency Inversion Principle
● Never depend on anything concrete, only depend on abstractions.
● High level modules should not depend on low level modules. They should
depend on abstractions.
● Able to change an implementation easily without altering the high level code.
39.
40.
41.
42.
43. @ktrajchevska
⚠️ Don’t get trapped by SOLID
● SOLID design principles are principles, not rules.
● Always use common sense when applying SOLID.
● Avoid over-fragmenting your code for the sake of SRP or SOLID.
● Don’t try to achieve SOLID, use SOLID to achieve maintainability.
44.
45.
46. @ktrajchevska
Final Thoughts
● The purpose of SOLID principles is to make your code more maintainable, easy
to extend and reason about.
● It requires spending more time writing code, so you can spend less reading it
later.
● SOLID principles are principles, not rules.
● Always know your trade-offs and use common sense.
● SOLID is your tool, not your goal.
SRP is very similar to the concept of a clean organized room. There’s a place for everything in your room and everything should be in its place.
Similarly, there should be a place for everything in your code and everything should be in its place.
We can go further, by creating a mutator for the password, so the repository doesn’t need to care about what is used for password encryption.
Has the most confusing name, but it could save most on development time once you understand it.
A good example here is an open source library. When you install a composer package, it goes to your vendors folder and you don't touch its code - you write separate code around it that will make it compatible with your own app. After many downloads, open source libraries get tested that much that they become almost error resistant.
That's your goal with OCP - to never change the core of your system, so it can get tested so much that it can never be broken.
So how do we add new payment types now? Say, CouponPayment or CashOnDeliveryPayment. We simply add a new class for the new payment type, implement the pay method and tell the factory how to instantiate it. Nothing more - it should now work out of the box.
Imagine this scenario, you’re working on your app and instead of creating your database structure since the beginning you use a file system just for testing purposes. Now, you have some repository that communicates with that file system - reads through the files and prepares them, so it can return the data to your program in an array format. You use it and don’t care how it’s handled in the background. That’s great. Now, you complete the development process, everything is great and now you want to replace the file system with a database. You change your repository to implement all the same methods for working with the database. But they now return a collection instead of array, which fails your program.
The best way to comply to LSP in PHP right now is programing with intent.
PHP, interpreted language
This is a red alert!The main purpose of SOLID design principles is to make our lives easier. To make our apps more easily maintainable and extendable. If you find yourself over-fragmenting your code or doing things for the sake of the SOLID design principles that don’t actually help you maintain your app or code faster - that is a red alert
OK, I know as software engineers this index.php movement probably makes you sick in the stomach :) But, it has an excellent point. Never ever overcomplicate! If you have an app that is so basic and will never need to be extended, there’s no point to over-engineer and write more code than necessary. In those cases, tying to comply with SOLID will complicate things for you instead of simplifying them. Perhaps a convenient, but not so drastic example here would be Laravel models. You can abstract the database layer with the Repository pattern and architect everything beautifully, but if it’s a simple app you’re probably better off using Eloquent models directly. SOLID requires writing more code, so you can read less. In simple apps you need to think whether it’s worth it.
Again, use SOLID as a tool to make your life as a developer easier. Common sense principle is sometimes the best one to follow.