What is SOLID principles

SOLID is a mnemon­ic for five design prin­ci­ples intend­ed to make soft­ware designs more under­stand­able, flex­i­ble and maintainable.

As with every­thing in life, using these prin­ci­ples mind­less­ly can cause more harm than good. The cost of apply­ing these prin­ci­ples into a pro­gram’s archi­tec­ture might be mak­ing it more com­pli­cat­ed than it should be. I doubt that there’s a suc­cess­ful soft­ware prod­uct in which all of these prin­ci­ples are applied at the same time. Striv­ing for these prin­ci­ples is good, but always try to be prag­mat­ic and don’t take every­thing writ­ten here as dogma.

SOLID first principle: Single Responsibility Principle

A class should have just one rea­son to change.
Try to make every class respon­si­ble for a sin­gle part of the func­tion­al­i­ty pro­vid­ed by the soft­ware, and make that respon­si­bil­i­ty entire­ly encap­su­lat­ed by (you can also say hid­den with­in) the class

SOLID second principle: Open/Closed Principle

Class­es should be open for exten­sion but closed for modification.
The main idea of this prin­ci­ple is to keep exist­ing code from break­ing when you imple­ment new features.

A class is open if you can extend it, pro­duce a sub­class and do what­ev­er you want with it—add new meth­ods or fields, over­ride base behav­ior, etc. Some pro­gram­ming lan­guages let you restrict fur­ther exten­sion of a class with spe­cial key­words, such as final. After this, the class is no longer open. At the same time, the class is closed (you can also say com­plete) if it’s 100% ready to be used by other class­es—its inter­face is clear­ly defined and won’t be changed in the future.

SOLID third principle: Liskov Sub­sti­tu­tion Prin­ci­ple

When extend­ing a class, remem­ber that you should be able to pass objects of the sub­class in place of objects of the par­ent class with­out break­ing the client code.
This means that the sub­class should remain com­pat­i­ble with the behav­ior of the super­class. When over­rid­ing a method, extend the base behav­ior rather than replac­ing it with some­thing else entirely.

The sub­sti­tu­tion prin­ci­ple is a set of checks that help pre­dict whether a sub­class remains com­pat­i­ble with the code that was able to work with objects of the super­class. This con­cept is crit­i­cal when devel­op­ing libraries and frame­works because your class­es are going to be used by other peo­ple whose code you can’t direct­ly access and change.

SOLID fourth principle: Interface Segregation Principle

Clients shouldn’t be forced to depend on meth­ods they do not use.
Try to make your inter­faces nar­row enough that client class­es don’t have to imple­ment behav­iors they don’t need.

Accord­ing to the inter­face seg­re­ga­tion prin­ci­ple, you should break down “fat” inter­faces into more gran­u­lar and spe­cif­ic ones. Clients should imple­ment only those meth­ods that they real­ly need. Oth­er­wise, a change to a “fat” inter­face would break even clients that don’t use the changed methods.

Class inher­i­tance lets a class have just one super­class, but it doesn’t limit the num­ber of inter­faces that the class can imple­ment at the same time. Hence, there’s no need to cram tons of unre­lat­ed meth­ods to a sin­gle inter­face. Break it down into sev­er­al more refined inter­faces—you can imple­ment them all in a sin­gle class if need­ed. How­ev­er, some class­es may be fine with imple­ment­ing just one of them.

SOLID fifth principle: Dependency Inversion Principle

High-level class­es shouldn’t depend on low-level class­es. Both should depend on abstrac­tions. Abstrac­tions shouldn’t depend on details. Details should depend on abstractions.
Usu­al­ly when design­ing soft­ware, you can make a dis­tinc­tion between two lev­els of classes.

Low-level class­es imple­ment basic oper­a­tions such as work­ing with a disk, trans­fer­ring data over a net­work, con­nect­ing to a data­base, etc.
High-level class­es con­tain com­plex busi­ness logic that directs low-level class­es to do something.

Some­times peo­ple design low-level class­es first and only then start work­ing on high-level ones. This is very com­mon when you start devel­op­ing a pro­to­type on a new sys­tem, and you’re not even sure what’s pos­si­ble at the high­er level because low-level stuff isn’t yet imple­ment­ed or clear. With such an approach busi­ness logic class­es tend to become depen­dent on prim­i­tive low-level classes.

The depen­den­cy inver­sion prin­ci­ple sug­gests chang­ing the direc­tion of this dependency.

For starters, you need to describe inter­faces for low-level oper­a­tions that high-level class­es rely on, prefer­ably in busi­ness terms. For instance, busi­ness logic should call a method openReport(file) rather than a series of meth­ods openFile(x), readBytes(n), closeFile(x). These inter­faces count as high-level ones.
Now you can make high-level class­es depen­dent on those inter­faces, instead of on con­crete low-level class­es. This depen­den­cy will be much soft­er than the orig­i­nal one.
Once low-level class­es imple­ment these inter­faces, they become depen­dent on the busi­ness logic level, revers­ing the direc­tion of the orig­i­nal dependency.
The depen­den­cy inver­sion prin­ci­ple often goes along with the open/closed prin­ci­ple: you can extend low-level class­es to use with dif­fer­ent

REF

https://barryvanveen.nl/articles/51-8-resources-to-learn-about-solid-design-principles

Bài viết khác

Unit Testing – Kiểm thử đơn vị trong lập trình

Unit Testing – Kiểm thử đơn vị trong lập trình 1. Tổng quan về Unit Testing Unit Testing (kiểm thử đơn vị) là một kỹ thuật kiểm thử phần mềm nhằm xác minh tính chính xác của những đơn vị nhỏ nhất trong chương trình, chẳng hạn như một hàm, một phương thức hoặc một […]

API Error Handling

API Error Handling 1. Tổng quan về API Error Handling API Error Handling là kỹ thuật xử lý lỗi trong quá trình giao tiếp giữa các thành phần của hệ thống thông qua API (Application Programming Interface). Kỹ thuật này bao gồm việc phát hiện lỗi, phân loại nguyên nhân, trả về thông tin phù […]

Responsive UI – Responsive Navigation và bố cục ứng dụng trong Flutter

Responsive Navigation và bố cục ứng dụng trong Flutter Responsive Navigation và Responsive Layout là hai thành phần quan trọng trong quá trình xây dựng ứng dụng Flutter có khả năng hoạt động tốt trên nhiều kích thước màn hình. Một ứng dụng hiện đại không chỉ cần hiển thị giao diện đẹp trên điện […]

Responsive UI – Responsive Typography và nội dung trong Flutter

Responsive Typography và nội dung trong Flutter 1. Responsive Typography 1.1. Khái niệm Responsive Typography Responsive Typography là kỹ thuật thiết kế và điều chỉnh cách trình bày văn bản để nội dung luôn dễ đọc, dễ hiểu và phù hợp với không gian hiển thị trên nhiều loại thiết bị. Trong Flutter, kỹ thuật […]

Build for global scale: AFK scale cube and basic rule to build an application for global scale

REF https://akfpartners.com/growth-blog/scale-cube

Clean code in writing Go program

When writing code in Go, it is important to follow good coding practices to ensure that your code is clean, maintainable, and scalable. Here are some clean code and clean architecture practices to follow: Go coding style: Follow the official Go coding style guide, which includes recommendations for naming conventions, formatting, and documentation. Consistent coding […]