# THE S.O.L.I.D Principles

S.O.L.I.D principle တွေကို Classes, Functions, methods, modules တွေမှာလည်း apply လို့ရပါတယ်။ ဒီ post မှာတော့ရှင်းလင်းရလွယ်ကူအောင် class ကိုနမူနာထားပြီးရှင်းပြသွားပါမယ်

### S - Single Responsibility

Class တစ်ခုမှာ တာ၀န်တစ်ခုပဲရှိသင့်ပါတယ်။

**ဥပမာ**: ကျနော်တို့ လစဥ်ရောင်းရငွေတွေကိုတွက်ပြီး report တစ်ခု print ထုတ်ပေးရမယ်ဆိုပါစို့။ ရောင်းရငွေကိုတွက်ဖို့က class တစ်ခု၊ report ကိုထုတ်ဖို့က class တစ်ခု သပ်သပ်ဆီရှိသင့်ပါတယ်။ သပ်သပ်စီမရှိခဲ့ရင် ရောင်းရငွေကိုတွက်တဲ့ code တွေကို ပြင်တဲ့အခါမှာ မလိုအပ်ပဲ print ထုတ်တဲ့အပိုင်းမှာပါ bugs တွေတက်လာတာဖြစ်ကောင်းဖြစ်နိုင်ပါတယ်။

**ရည်ရွယ်ချက်**: ကိုယ်က class တစ်ခုကို ပြင်လိုက်လို့အဲ့ဒီ class က ပြသနာတွေတက်လာရင်တောာင် တခြားသူနဲ့မဆိုင်တဲ့ အပိုင်း တွေကို မထိခိုက်စေဖို့ရည်ရွယ်ပါတယ်။

### O - Open-Closed

Class တစ်ခုကို တိုးချဲ့ပြီးရေးလို့ရသင့်တယ်။ ရှိပြီးသားတွေကို ပြင်ဆင်လို့မရသင့်ဘူး။ wiki က မူရင်း english လိုက အဓိပ္ပယ်ပြည့်စုံပါတယ်။ တချက်ကြည့်ကြည့်ပါ။ "\*software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"\*လို့ရေးးထားပါတယ်

**ဥပမာ**: class တစ်ခုက အဖြူရောင်နောက်ခံနဲ့ print ထုတ်နိုင်တယ်။ အဲ့တာကို အပြာရောင်နောက်ခံနဲ့လည်းထုတ်ချင်တယ်။ ဒါဆို class က အဖြူရောင်နောက်ခံနဲ့လည်းထုတ်လို့ရတယ်, အပြာရောင်နောက်ခံနဲ့လည်းထုတ်လို့ရတယ်(extension) ဆိုတာ ဖြစ်သင့်ပါတယ်။ print ထုတ်ရင်အပြာရောင်နဲ့ပဲထွက်တော့တယ်(modification) ဆိုတာမဖြစ်သင့်ပါဘူး။

**ရည်ရွယ်ချက်**: class တစ်ခုကို လုပ်နိုင်တာတွေပိုတိုးလာအောင်လုပ်မယ်။ ဒါပေမယ့် အရင်ထဲကလုပ်နိုင်ပြီးသားတွေကိုလည်းမထိခိုက်စေရန်ရည်ရွယ်ပါတယ်။ ဒါဆို အဲ့ဒီ class ကို ယူသုံးထားတဲ့ ဘယ်နေရာမှာမှ bug မတက်တော့ပါဘူး။

### L - Liskov Substitution

Dog class က Pet class ရဲ့ child ဖြစ်မယ်ဆိုရင် Pet class ကိုသုံးပြီးတည်ဆောက်ထားတဲ့ objects တွေကို Dog class နဲ့ဘာပြသနာမှမရှိပဲအစားထိုးလို့ရနိုင်သင့်တယ်။

**ဥပမာ**: Pet class က move ဆိုတဲ့အလုပ်လုပ်နိုင်တယ်။ ဒါဆို Dog class ကို move ခိုင်းရင် walk နိုင်တယ်ဆိုတာဖြစ်သင့်တယ်(parent ကလုပ်နိုင်တဲ့အလုပ်ကို child ကလည်းလုပ်နိုင်)။ Dog class ကို move ခိုင်းရင် move တော့မလုပ်နိုင်ဘူး eat လိုက်မယ်ဆိုတာမဖြစ်သင့်ဘူး(parent ကလုပ်နိုင်တဲ့အလုပ်ကို child ကမလုပ်နိုင်တော့ဘူး။ behaviour ပြောင်းသွားပြီ)။

**ရည်ရွယ်ချက်**: parent class ရော child class ရောကို consistency ရှိဖို့ရည်ရွယ်တယ်။ parent class ကိုသုံးရမယ့်ပုံကတစ်မျိုး child class ကိုသုံးရမယ့်ပုံကတစ်မျိုးမဖြစ်အောင်ကာကွယ်ဖို့ရည်ရွယ်တယ်။

### I - Interface Segregation

class တစ်ခုမှာ သူ့ရဲ့ ရည်ရွယ်ချက် ပြီးမြောက်အောင်လုပ်ဖို့လိုတဲ့ actions တွေပဲရှိသင့်တယ်။ မလိုအပ်တဲ့ action တွေမရှိသင့်ဘူး။ မလိုအပ်တဲ့ action တွေပါနေရင် အပြီးဖျက်ပစ်ရင် ဖျက်ပစ်၊ မဖျက်ပစ်ရင် တခြားတစ်နေရာကိုရွေ့ပစ်ရမယ်။

**ဥပမာ**: အောက်က code ကိုကြည့်ကြည့်ပါ။

```php
interface UserInterface {
    public function buyProduct();
    public function editProduct();
    public function addProduct();
}
```

အဲ့ဒီမှာဆို UserInterface မှာ method 3 ခုပါတယ်။ buyProduct က customer တွေအတွက်လိုအပ်တဲ့ action ဖြစ်ပြီး editProduct, addProduct က admin တွေအတွက်လိုအပ်တဲ့ action တွေဖြစ်တယ်။

အဲ့ဒီ interface ကို Customer class ရော Admin class ရောက implement ပြီဆိုပါစို့။ Customer ကလည်း editProduct, addProduct အတွက် method တွေရေးပေးရတော့မယ်။ Admin ကလည်း buyProduct အတွက် method ရေးပေးရတော့မယ်။ အဲ့လိုမဖြစ်သင့်ဘူး။ အဲ့ဒီအစား

```php
interface CustomerInterface {
    public function buyProduct();
}

interface AdminInterface {
    public function editProduct();
    public function addProduct();
}
```

ဆိုပြီး interface ၂ ခုခွဲ၊ သက်ဆိုင်ရာ interface ကိုပဲ implement တာဖြစ်သင့်တယ်။

**ရည်ရွယ်ချက်**: refactor, change, extend လုပ်တဲ့အချိန်မှာ လွယ်ကူစေဖို့ရည်ရွယ်ပါတယ်။

### D - Dependency Inversion

High level class တစ်ခုက low level class ရဲ့ implementation အပေါ်မမှီခိုရဘူး။ high level class ရော low level class ရောက ဘုံ abstraction တစ်ခုအပေါ်ပဲမှီခိုရမယ်။

**ဥပမာ**: Db class ရယ် User class ရယ်ရှိတယ်ဆိုပါစို့။ User class က high level class ဖြစ်လိမ့်မယ်။ Db class က low level class ဖြစ်လိမ့်မယ်။ (Database နဲ့ချိတ်ဆက်အလုပ်လုပ်တာ၊ disk နဲ့အလုပ်လုပ်တာ၊ network နဲ့အလုပ်လုပ်တာ အစရှိတာတွေကို low level class တွေလို့ခေါ်ကြလေ့ရှိပါတယ်)

```php
class Db 
{
    public function connect()
    {
        //action to connect to db
    }
}

class User
{
    protected $db;
    public function __construct(Db $db)
    {
        $this->db = $db;
    }
}
$db = new Db();
$user = new User($db);
```

အထက်ပါ ရေးနည်းဟာဆိုရင် Dependency Inversion Principle ကိုမလိုက်နာပါဘူး။ User class က Db class ရဲ့ implementation အပေါ်တိုက်ရိုက်မှီခိုနေပါတယ်။  
User class က Db class implementation ကိုသိဖို့လိုလား?  
ဒါမှမဟုတ် Db နဲ့ချိတ်ဆက်စရာ နည်းတစ်ခုရှိတယ်ဆိုတာကိုပဲသိရင်ရပြီလား?  
Dependency Inversion မှာဆိုရင် Db နဲ့ချိတ်ဆက်စရာနည်းတစ်ခုရှိတယ်ဆိုတာကို သိရင်ရပြီလို့ သတ်မှတ်ပါတယ်။

```php
interface DbInterface 
{
    public function connect();
}

class LegacyDb implements DbInterface 
{
    public function connect()
    {
        // code to connect to db
    }
}

class ModernDb implements DbInterface 
{
    public function connect()
    {
        // code to connect to db
    }
}

class User
{
    protected $db;

    public function __construct(DbInterface $db)
    {
        $this->db = $db;
    }
}

// Decide which db system to use
$db = new ModernDb();
// Or $db = new LegacyDb(); 

// Create a user object with the chosen db system 
$user = new User($db);
```

အထက်ပါရေးနည်းမှာဆို User က Db class အပေါ်မှာတိုက်ရိုက်မမှီခိုတော့ပါဘူး။ Db နဲ့ပတ်သက်တဲ့ classes တွေရော User ရောက ဘုံ abstraction အပေါ်ပဲမှီခိုသွားပါပြီ။ လိုတဲ့ db system ကိုယူသုံးလို့ရပါပြီ။ အခုဆိုရင် High-level code တွေက သူသုံးထားတဲ့ low-level code တွေရဲ့ implementation အပေါ် မမှီခိုတော့ပါဘူး။

**ရည်ရွယ်ချက်**: ကျနော်တို့ High level code တွေကို ထိစရာမလိုတော့ပဲ low level implementation တွေကိုကြိုက်သလိုပြောင်းလို့ရဖို့ရည်ရွယ်ပါတယ်။

### Summary

အခုဆိုရင်ကျနော်တို့ S.O.L.I.D အကြောင်း အခြေခံလေ့လာပြီးပါပြီ။ အချိန်ပေးပြီးဖတ်ပေးတဲ့အတွက်ကျေးဇူးတင်ပါတယ်။ အကြံပေးချင်တာတွေ comment ပေးသွားဖို့လည်း request လုပ်ပါတယ်ခင်ဗျာ။

**References**:

[https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898](https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898)

[https://en.wikipedia.org/wiki/SOLID](https://en.wikipedia.org/wiki/SOLID)
