စကေးချွတ်ပီး လစာကောင်းတဲ့ developer ဖြစ်ဖို့ TDD(Test Driven Development) ကိုသိထားသင့်တယ်၊ အများအားဖြင့် software company တွေမှာ TDD approve နဲ့ရေးကြတယ်။ TDD ကိုမလုပ်ခင် SOLID ရဲ့ Dependency Inversion Principle ကိုနားလည်ထားသင့်တယ်။ fresher တွေတော့ နားလည်ဖို့မလွယ်ပေမဲ့ အလွယ်ကူဆုံးဖြစ်အောင် ဒီ article မှာရှင်းပြသွားပါမယ်။
What is DIP?
D ဆိုတဲ့ SOLID ရဲ့ အတိုကောက်၊ သူ့ကိုရှင်းရင်
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Structure ကောင်းတဲ့ code ကို ကြည့်လိုက်ရင် code base က hierarchy(အဆင့်ဆင့်) အလိုက် ရှိတယ်၊ high-level module နဲ့ low-level module ဆိုပီး ရှိတယ်၊ fresher တွေက ဒါကိုနားလည်မှုလွဲနိုင်တယ်၊ low-level ကနေ high-level ကို directly depend သွားလုပ်ကြတယ်။နားလည်အောင် အောက်က code ကိုကြည့်
import java.util.Arrays;
import java.util.List;// High Level Module
class ProductCatalog {
public void listAllProducts() {
SQLProductRepository sqlProductRepository = new SQLProductRepository();
List<String> allProductNames = sqlProductRepository.getAllProductNames();
// Display product names
}
}// Low Level Module
class SQLProductRepository {
public List<String> getAllProductNames() {
return Arrays.asList("soap", "toothpaste", "shampoo");
}
}
ဒီမှာProductCatalog
က SQLProductRepository
implementation class ကို create လုပ်လိုက်တယ်။ OOP အရ extend to interface, not to implementation ဖြစ်ရမှာ၊ အဲ့တော့ ProductCatalog
class( high-level module) က sub-module(low-level module) ဖြစ်တဲ့ SQLProductRepository
ပေါ်မှာ depend ဖြစ်နေတယ်။ ဒါတွေက code ရေးခါစ မကြာခဏဖြစ်တတ်တယ်။ ပြန်ပြောပါမယ် Dependency Inversion Principle က
High-level modules should not depend on low-level modules. Both should depend on abstractions.
ဆိုတော့ code က DIP ကို violation( ချိုးဖောက် ) နေတာကိုတွေ့ရမယ်၊ ဒီလောက်ဆို နားလည်လောက်မယ် ထင်တယ်။
ဘယ်လိုပြင်မလဲ၊ မပြင်ခင် software design ရဲ့ abstraction ဆိုတာကို ကြည့်ရအောင်
What is Abstraction?
(1) Code without abstraction
class Benz {
public void drive() {
}
}
class CarUtil {
public static void drive(Benz benz) {
benz.drive();
}
}
CarUtil
class ရဲ့ drive method က Benz
instance ကို parameter နဲ့ လက်ခံထားတယ်။ ဒါကြောင့် drive method ကို ခေါ်ရင် Benz
instance ကိုထည့်ပေးရမယ်၊ dependency ရှိနေတယ်၊ Software Design အရ tight coupling လို့ခေါ်တယ်။ ဘာလို့ဆို Benz
class ရဲ့ drive
method ကို ချိန်းရင် CarUtil
class ကို direct effect သွားဖြစ်တယ် Bugs ဖြစ်စေနိုင်မဲ့ facts တွေ
Tight Coupling is the most undesirable feature in Software
(2) Code with Abstraction
interface Car {
public void drive();
}
class Benz implements Car {
@Override
public void drive() {
}
}
class Tesla implements Car {
@Override
public void drive() {
}
}
class CarUtil {
public static void drive(Car car) {
car.drive();
}
}
code structure အရ CarUtil
ရဲ့ drive method က Benz
ကို depend မဖြစ်တော့ဘဲ Car
interface ပေါ်မှာဘဲ depend သွားဖြစ်တော့တယ်။ ဆိုလိုတာက Car
interface ကို implement လုပ်ထားတဲ့ ဘယ် car မဆို လက်ခံနိုင်တယ်။ ဒါကို abstration လို့ခေါ်သလို loose coupling လို့လည်းခေါ်တယ်။
Abstration ကို နားလည်သွားရင် အပေါ်က code နဲ့ ပြန်ကြည့်အောင်
Refactoring Previous Code with Abstraction
“Abstractions should not depend on details. Details should depend on abstractions.”
import java.util.Arrays;
import java.util.List;
// High Level Module
class ProductCatalog {
public void listAllProducts() {
// High Level Module depends on Abstraction
ProductRepository productRepository = new SQLProductRepository();
List<String> allProductNames = productRepository.getAllProductNames();
// Display product names
}
}interface ProductRepository {
List<String> getAllProductNames();
}
// Low Level Module
class SQLProductRepository implements ProductRepository {
public List<String> getAllProductNames() {
return Arrays.asList("soap", "toothpaste", "shampoo");
}
}
ProductCatalog
class က SQLProductRepository
ပေါ် depend မဖြစ်တော့ဘူး။ ProductRepository
interface ပေါ်မှာဘဲ depend သွားဖြစ်တော့တယ်။ဘာကောင်းသွားလဲဆို
- Concrete implementation ဖြစ်တဲ့
SQLProductReopsitory
ကိုProductCatalog
က direct access မလုပ်ဘဲ interface ကနေတစ်ဆင့် access လုပ်တယ်။ တစ်ခြား database ချိတ်ဖို့လိုအပ်လာရင် နောက် low level class create လုပ်လိုက်ရင် ရတယ်။ Dabase connection ကို ပြောင်းလို့ရသွားမယ်။ MySQL လား Mango ချိတ်မလားဆို interface ကို implement လုပ်ပီး ခေါ်ရုံဘဲ၊ ProductCatalog
ရဲ့ListAllProducts()
မှာ Abstration အပေါ် depend ဖြစ်နေတဲ့ SQL class တွေခေါ်လိုက်ရုံဘဲ၊ loose coupling ဖြစ်တယ်။
ဒီအထိ ကျွန်တော်တို့ ဘာတွေရလိုက်လဲဆိုရင်
Refactoring မလုပ်ခင် ProductCatalog
က SQlProductRepository
ပေါ်မှာ depend ဖြစ်တယ်။ high-level module က low-module ပေါ်မှာ depend ဖြစ်တယ်လို့ ပြောရမယ်၊ tight coupling ဖြစ်တယ်။
ProductCatalog
က ProductRepository
ပေါ်မှာ depend ဖြစ်တယ်။ SQLProductRepository
က ProductRepository
ပေါ်မှာဘဲ depend ဖြစ်တယ်။
Dependency Inversion Principle အရ
High-level modules should not depend on low-level modules. Both should depend on abstractions.
စာကြောင်းကို နားလည်သွားမယ်ထင်တယ်။
နောက်တစ်ဆင့် အနေနဲ့ Dependency Injection ကိုကြည့်ရအောင်
import java.util.Arrays;
import java.util.List;
class ProductCatalog {
private ProductRepository productRepository;
public ProductCatalog(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public void listAllProducts() {
List<String> allProductNames = productRepository.getAllProductNames();
// Display product names
}
}
interface ProductRepository {
List<String> getAllProductNames();
}
class SQLProductRepository implements ProductRepository {
public List<String> getAllProductNames() {
return Arrays.asList("soap", "toothpaste", "shampoo");
}
}
class EcommerceApplication {
public static void main(String[] args) {
ProductRepository productRepository = new SQLProductRepository();
ProductCatalog productCatalog = new ProductCatalog(productRepository);
productCatalog.listAllProducts();
}
}
ProductCatalog
က ProductRepository
ကို inject လုပ်ထားတာတွေ့ရမယ်။ ဒီလို Object ဆောက်ပီး inject လုပ်တာက ကောင်းတယ် ဘာလို့ဆို Mock data တွေနဲ့ TDD လုပ်တဲ့ချိန်မှာ အသုံ၀င်လို့ ၊ ဒီ TDD concept တွေကိုနောက်မှ ရှင်းပါတော့မယ်။
Conclusion
- “High-level modules should not depend on low-level modules. Both should depend on abstractions.”
- “Abstractions should not depend on details. Details should depend on abstractions.”
ဒီစာကြောင်းနှစ်ကြောင်းကို နားလည်ရင် congratulation ပါ DIP principle ကို သင်နားလည်သွားပါပီး။ experience ရှိရင်တော့ လွယ်လွယ်နဲ့ နားလည်နိုင်ပေမဲ့ ၊ မရှိရင် ခတ်နိုင်တယ်။ ဒါကြောင့် experience ရှိဖို့ intentional practice များများလုပ်ဖို့ လိုပါတယ်။