Flutter with SOLID Principle
At this moment I am going to discuss the SOLID Principle which developers must understand. 🤩
What is SOLID Principle? 🤔
S.O.L.I.D Principle was published by Robert J. Martin (a.k.a Uncle Bob) on paper he published in 2000 Design Principles and Design Patterns. In the last 20 years, these five principles changed the programming world in Object Oriented Programming (OOP), changed how we write the code.
SOLID help to develop software with a high level of rigidity.
SOLID principle is :
- S → Single Responsibility Principle
- O → Open Closed Principle
- L → Liskov Substitution Principle
- I → Interface Segregation principle
- D → Dependency Inversion Principle
SOLID Purpose
What we get from SOLID Principle in your Programming
- Understandable and readable code
- Changes tolerance
- Basic components can be reused as other software system
- Testabled by developers collaboratively
SOLID Principles
🔥 Warning
”You have to understand Object Orientation Programming and Software Design Principle first before understanding SOLID Principles”
Single Responsibility Principle (SRP)
“A module should be responsible to one, and only one, reason to be changed” (Robert J. Martin)
Single Responsibility Principle (SRP) is a principle which is used to manage the responsibility from an entity in a project. It is a module or class to fulfill a user’s needs.
Responsibility means a class has 2 functionalities which have no correlation to make a change. So the functionalities are divided by two.
Study case
🚫 Wrong Example
Based on the example above, there are a lot of responsibilities. It is possible to affect the other related functionalities and responsibilities in the class.
✅ Correct Example
Based on the example above, we can see that the responsibilities are divided by two and there are some functionalities. The strength of SRP is the code can be managed and identified much more easily.
Open Closed Principle (OCP)
“Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification” (Robert J. Martin)
Open Closed Principle (OCP) is a software manager (class, module, function, etc.) it must be opened to add but closed for modifying.
The main purpose of OCP is to avoid bugs occurring when implementing the existing code.
OCP implementation uses interface and abstract in class, so it can be easy to change after developing without affecting the inherited class and it becomes easier to make new functionalities.
Study case
🚫 Wrong Example
From the example above, the Human class contains a functional character in which there are conditions to take walk, eat, drink. If you do this, it is very possible to create new bugs when you change code that was previously running normally.
✅ Correct Example
From the class above, Human is class abstract to use as a trait that will we create.
Class WalkHuman, EatHuman dan DrinkHuman ini adalah tempat untuk memproses sifat dari manusia. Class WalkHuman, EatHuman and DrinkHuman are the place for the process of class humans.
For example, if we create a new SleepHuman trait, we just need to extend it from the Human class.
Liskov Substitution Principle (LSP)
Subtypes must be substitutable for their base types. (Robert J. Martin)
Liskov Substitution Principle (LSP) is a rule for inheritance. This allows us to design the classes we have, so the dependence between Clients can be distributed without the Client knowing about the changes. Therefore, the SubClass should run in the same way like the SuperClass.
Study case
🚫 Wrong Example
In the Bird class we find swim(). Is it the Bird’s characteristic? OF COURSE NOT!.
Every time we add or modify a SubClass, we have to go through our base codes and change it in some places, it will be difficult to do and sensitive to mistakes.
✅ Correct Example
Based on the code above, Bird class has no swim() function. It’s because we have made the relevant substitution function swim() the characteristic of Fish. We don’t add swim() function in Bird class anymore because Bird can not swim. Fish Class still gets inheritance from Character class.
Interface Segregation Principle (ISP)
“Clients should not be forced to depend upon interfaces that they do not use” (Robert J. Martin)
Interface Segregation principle (ISP) is principle has a purpose to reduce the dependence of class to the other unimportant interface classes.
In interface making, we are better at making a lot of interfaces with specific functions. The purpose of separating interfaces is not to force clients to use unimportant codes.
Study case
🚫 Wrong Example
On the codes that Vehicle interface has run(), stop() and charger(). Does a Bicycle need a charger? OF COURSE NOT, but when you create that such code, you should implement that code, right?
✅ Correct Example
Based on the codes above, we divide the class interface into 2, VehicleInterface and ElectricInterface. VehicleInterface has a common function, and ElectricInterface has only a charger() function.
For example, we need Tesla features, Tesla needs electric power charging. Therefore we have to implement VehicleInterface and ElectricInterface.
When we want to make a new feature, it is Bicycle, we need only to implement VehicleInterface.
We have separated the interface into smaller parts, the function and the responsibility itself. This will also make it easier if we need new features and understandable for developers.
Dependency Inversion Principle (DIP)
”High-level modules should not depend on low-level modules. Both should depend on abstractions”. (Robert J. Martin)
Dependency Inversion Principle (DIP) depends on the interface class rather than the direct references from other classes.
There are some rules in DIP :
- High-level modules are not allowed to depend on low-level modules. Both of them must depend on Abstractions.
- Abstractions are not allowed to depend on Details. Details must depend on Abstractions.
HIGH LEVEL → a class deals with a bunch of functionalities.
LOW LEVEL → a class deals with the responsibilities of detailed operation. Such as writing on a database.
Study case
On class EngineInterface use the function run(), the function to showing name of engine from multiple engine.
We make constructor parameters In the Bike class where each class implements the interface Engine. The Bike and EngineInterface are High Level. And the EngineDiesel and ElectricEngine are Low Level.
To run those codes, we just need to register the engine we want to run. Dependency Inversion makes the system flexible. The dependence between dependencies on the codes just refer to the abstractions, not from a class.
Dependency Inversion for Flutter you can use packages get_it.
Conclusion
S.O.L.I.D is helpful to make a system, but it’s just a principle, not a rule one must obey. S.O.L.I.D principle can be used in any programming language.
Benefits of using SOLID principle :
- Understandable and readable code
- Changes tolerance
- Basic components can be reused as other software system
- Testabled by developers collaboratively
You can see the examples of the Flutter project I have made.
If you have the desire to learn Flutter, please click the button below to contact us: