အခန်း ၈ :: Fundamental Principles of Software Engineering

Software Engineering လောကတွင် နည်းပညာများ၊ Framework များ၊ Language များသည် နေ့စဉ်နှင့်အမျှ ပြောင်းလဲနေပါသည်။ မနေ့က ခေတ်စားခဲ့သော React Class Component သည် ယနေ့ Function Component ဖြစ်သွားသလို၊ မနေ့က Monolith သည် ယနေ့ Microservices ဖြစ်သွားနိုင်ပါသည်။ သို့သော် ပြောင်းလဲခြင်း မရှိသော၊ အချိန်ကာလတိုင်းတွင် မှန်ကန်နေသော အခြေခံ အုတ်မြစ်များ (Fundamental Principles) ရှိပါသည်။
ဤအခြေခံမူများသည် တိကျသော Programming Language တစ်ခုအပေါ်တွင် မူတည်ခြင်းမရှိဘဲ၊ ကောင်းမွန်သော Software Architecture တစ်ခု၊ Maintainable ဖြစ်သော Codebase တစ်ခု ဖြစ်လာစေရန် ထိန်းကျောင်းပေးသည့် "Software လောက၏ ရူပဗေဒ နိယာမများ" ဟု ဆိုနိုင်ပါသည်။
ဤအခန်းတွင် Software Engineer တစ်ယောက် မဖြစ်မနေ နားလည်ထားရမည့် အခြေခံမူများကို လေ့လာသွားပါမည်။
၈.၁ Separation of Concerns (SoC)
Software System တစ်ခုကို တည်ဆောက်ရာတွင် အရေးကြီးဆုံး အချက်မှာ "ရောထွေးမနေစေခြင်း" ဖြစ်သည်။ Separation of Concerns ဆိုသည်မှာ ပရိုဂရမ်တစ်ခုကို တာဝန်မတူညီသော အစိတ်အပိုင်း (Concern) များအဖြစ် သီးခြားစီ ခွဲထုတ်ခြင်း ဖြစ်သည်။
ဥပမာအားဖြင့် စားသောက်ဆိုင် တစ်ဆိုင်တွင် စားဖိုမှူး (ချက်ပြုတ်ရေး)၊ စားပွဲထိုး (ဧည့်ခံရေး) နှင့် ငွေကိုင် (ငွေစာရင်း) ဟူ၍ တာဝန်ခွဲခြားထားသကဲ့သို့ ဖြစ်သည်။ စားဖိုမှူးက ငွေထွက်ရှင်းနေလျှင် ထိုဆိုင် ရှုပ်ထွေးသွားပါလိမ့်မည်။
Software တွင်လည်း ထိုနည်းတူစွာ -
- Presentation Logic: User ကို Data ပြသခြင်း (UI)
- Business Logic: အဓိက လုပ်ငန်းစဥ်များ (Processing)
- Data Access Logic: Database တွင် သိမ်းဆည်းခြင်း (Storage)
ဟူ၍ ခွဲခြားထားသင့်သည်။ ဤအချက်သည် အခန်း ၅ မှာ ဖော်ပြထားသည့် Layered Architecture နှင့် MVC Pattern တို့၏ အဓိက သဘောတရား ဖြစ်သည်။
graph TD
subgraph "Without SoC (Spaghetti Code)"
A["<b>Monolithic / God Component</b><br><br>UI ရော၊ တွက်ချက်တာရော၊<br>Database ခေါ်တာရော<br>တစ်နေရာတည်း ရောရေးထားခြင်း"]
end
subgraph "With SoC (Clean Architecture)"
B[UI Component<br>View] --> C[Business Logic Component<br>Service]
C --> D[Data Access Component<br>Repository]
end
style A fill:#ffcccc,stroke:#333
style B fill:#ccffcc,stroke:#333
style C fill:#ccffcc,stroke:#333
style D fill:#ccffcc,stroke:#333
SoC ကို လိုက်နာခြင်းဖြင့် UI ဒီဇိုင်း ပြောင်းချင်လျှင် Business Logic ကို သွားထိစရာ မလိုတော့သလို၊ Database ပြောင်းချင်လျှင်လည်း UI ပျက်သွားမည်ကို စိုးရိမ်စရာ မလိုတော့ပါ။
၈.၂ Information Hiding and Encapsulation
ဒီ Principle နှစ်ခုက ဆက်စပ်နေပေမယ့် ကွဲပြားမှု ရှိပါတယ်။ Coupling ကို လျှော့ချဖို့နဲ့ Maintainability ကို မြှင့်တင်ဖို့ အလွန် အရေးပါပါတယ်။
Information Hiding (သတင်းအချက်အလက် ဖုံးကွယ်ခြင်း)
Module တစ်ခုရဲ့ "အတွင်းပိုင်း ဘယ်လို အလုပ်လုပ်လဲ" (How) ဆိုတာကို အခြား Module တွေက မသိအောင် ဖုံးကွယ်ထားခြင်း ဖြစ်ပါတယ်။ အပြင်က လူက "ဘာလုပ်ပေးနိုင်လဲ" (What) ဆိုတာပဲ သိရပါမယ်။
ကားမောင်းခြင်း ဥပမာ: ကားမောင်းသူ (User) တစ်ယောက်အနေနဲ့ စတီယာရင်၊ လီဗာ၊ ဘရိတ် (Interface) ကိုပဲ သိဖို့ လိုပါတယ်။ အင်ဂျင်ထဲမှာ ဆီဘယ်လို ဖြန်းတယ်၊ မီးဘယ်လို ပွင့်တယ် (Implementation Detail) ဆိုတာကို သိစရာ မလိုပါဘူး။ ဒါမှသာ ကားထုတ်လုပ်သူက အင်ဂျင်စနစ်ကို ပြောင်းလဲလိုက်ရင်တောင် မောင်းသူအတွက် ဘာမှ အပြောင်းအလဲ မရှိမှာ ဖြစ်ပါတယ်။
Encapsulation (အလုံပိတ်ခြင်း)
ဒါကတော့ Information Hiding ကို လက်တွေ့ အကောင်အထည်ဖော်တဲ့ နည်းလမ်း ဖြစ်ပါတယ်။ အခန်း ၁ OOP မှာ ဆွေးနွေးခဲ့သလိုပါပဲ။ Data တွေနဲ့ အဲ့ဒီ Data တွေကို ကိုင်တွယ်မယ့် Method တွေကို Class တစ်ခုထဲမှာ ပေါင်းထည့်ပြီး၊ အပြင်ကနေ တိုက်ရိုက် ယူသုံးလို့ မရအောင် private access modifier တွေနဲ့ ပိတ်ထားတာ ဖြစ်ပါတယ်။
// Encapsulation Example
class BankAccount {
private balance: number = 0; // Data ကို ဖုံးကွယ်ထားသည်
// အပြင်လူ သုံးဖို့ Interface ဖွင့်ပေးထားသည်
public deposit(amount: number): void {
if (amount > 0) {
this.balance += amount;
}
}
}
၈.၃ Modularity and Composability
Software Engineering မှာ အကြီးမားဆုံး စိန်ခေါ်မှုက Complexity (ရှုပ်ထွေးမှု) ပါ။ ဒီရှုပ်ထွေးမှုကို ဖြေရှင်းဖို့ Modularity ကို သုံးရပါတယ်။
- Modularity: စနစ်ကြီး တစ်ခုလုံးကို သေးငယ်ပြီး၊ လွတ်လပ်တဲ့ (Independent)၊ လဲလှယ်လို့ရတဲ့ (Replaceable) Module လေးတွေ အဖြစ် ခွဲခြမ်းလိုက်တာပါ။
- Composability: အဲဒီ Module အသေးလေးတွေကို ပြန်လည် ပေါင်းစပ်ပြီး စနစ်အသစ်တွေ (သို့) Feature အသစ်တွေ ဖန်တီးနိုင်စွမ်း ရှိတာပါ။
ဒါကို အမြင်သာဆုံး ဥပမာ ပေးရရင် LEGO တုံးတွေ လိုပါပဲ။ LEGO တုံးလေးတွေက သီးခြားစီ ရှိနေပေမယ့်၊ ပြန်လည် ပေါင်းစပ်လိုက်ရင် ကားဖြစ်သွားလိုက်၊ အိမ်ဖြစ်သွားလိုက်နဲ့ ပုံစံမျိုးစုံ ဖန်တီးနိုင်သလို Software Components တွေကိုလည်း Reusable ဖြစ်အောင် ဖန်တီးထားရပါမယ်။
graph TD
subgraph "Composable System"
direction TB
Auth[Auth Module]
Log[Logging Module]
Email[Email Module]
Noti[Notification Module]
end
subgraph "App 1: Web Application"
direction LR
W_App[Web App] --> Auth
W_App --> Log
W_App --> Email
end
subgraph "App 2: Mobile Application"
direction LR
M_App[Mobile App] --> Auth
M_App --> Noti
end
style Auth fill:#bbdefb,stroke:#333
style Log fill:#bbdefb,stroke:#333
၈.၄ Abstraction and Generalization
ဒီနှစ်ခုက ရှုပ်ထွေးမှုကို လျှော့ချပေးတဲ့ ဉာဏ်စဉ်တွေ ဖြစ်ပါတယ်။
- Abstraction: အရာဝတ္ထု တစ်ခုရဲ့ မလိုအပ်တဲ့ အသေးစိတ် အချက်အလက်တွေကို ဖယ်ရှားပြီး၊ အရေးကြီးတဲ့ အနှစ်သာရကိုပဲ ထုတ်ယူခြင်း ဖြစ်ပါတယ်။
- ဥပမာ: ရန်ကုန်မြေပုံ (Google Maps) ကြည့်တဲ့အခါ လမ်းနာမည်နဲ့ နေရာတွေကိုပဲ ပြထားပါတယ်။ လမ်းဘေးက သစ်ပင် အရေအတွက်၊ အိမ်ခေါင်မိုး အရောင် စတဲ့ "မလိုအပ်တဲ့ အသေးစိတ်" (Details) တွေကို ဖယ်ရှားထားပါတယ်။ ဒါမှသာ "လမ်းရှာခြင်း" ဆိုတဲ့ ရည်ရွယ်ချက် ပေါက်မြောက်မှာပါ။
- Generalization: မတူညီတဲ့ Object တွေကြားက တူညီတဲ့ အချက်တွေကို ရှာဖွေပြီး ပုံစံခွက် (Template) တစ်ခု ထုတ်ယူခြင်း ဖြစ်ပါတယ်။
- ဥပမာ: ခွေး (Dog) နဲ့ ကြောင် (Cat) မှာ "အစာစားသည်"၊ "အိပ်သည်" ဆိုတဲ့ တူညီတဲ့ အချက်တွေ ရှိပါတယ်။ ဒါတွေကို စုစည်းပြီး
Animalဆိုတဲ့ Parent Class တစ်ခု ဖန်တီးလိုက်တာဟာ Generalization ပါပဲ။ (အခန်း ၁ OOP တွင် အသေးစိတ် ဖတ်ရှုနိုင်ပါသည်)။
- ဥပမာ: ခွေး (Dog) နဲ့ ကြောင် (Cat) မှာ "အစာစားသည်"၊ "အိပ်သည်" ဆိုတဲ့ တူညီတဲ့ အချက်တွေ ရှိပါတယ်။ ဒါတွေကို စုစည်းပြီး
၈.၅ Anticipation of Change (အပြောင်းအလဲကို ကြိုတင်မျှော်မှန်းခြင်း)
Software Engineer ကောင်းတစ်ယောက်ဟာ "Change is the only constant" (အပြောင်းအလဲ ဆိုတာ မပြောင်းလဲသော တစ်ခုတည်းသော တရား) ဆိုတာကို မှတ်ထားရပါမည်။
Requirement တွေ ပြောင်းမယ်။ နည်းပညာတွေ ပြောင်းမယ်။ Business Logic တွေ ပြောင်းမယ်။ ဒီအပြောင်းအလဲတွေ လာတဲ့အခါ System တစ်ခုလုံး ဖြိုဖျက်ပြီး ပြန်ဆောက်ရတာမျိုး မဖြစ်ရအောင် ကြိုတင် ပြင်ဆင်ထားရပါမယ်။
လိုက်နာရမည့် နည်းလမ်းများ:
- Configuration: တန်ဖိုးတွေကို Code ထဲမှာ Hard-code မလုပ်ပါနဲ့။ Config file (
.env,.json) တွေမှာ ထားပါ။ - Interfaces: Concrete Class တွေကို တိုက်ရိုက် မချိတ်ဆက်ပါနဲ့။ Interface တွေကို ကြားခံပြီး ချိတ်ဆက်ပါ။ (အခန်း ၅ တွင် ဖော်ပြခဲ့သည့် Dependency Inversion Principle ဖြစ်ပါသည်)။
- Low Coupling: Module တစ်ခုနဲ့ တစ်ခု အမှီအခို နည်းနိုင်သမျှ နည်းအောင် တည်ဆောက်ပါ။
၈.၆ Rigor and Formality (တိကျသေချာမှုနှင့် စနစ်ကျမှု)
Coding ဆိုတာ "ပြီးစလွယ်" လုပ်ရမယ့် အလုပ် မဟုတ်ပါဘူး။ Rigor ဆိုတာ လုပ်ငန်းစဉ်တွေကို စနစ်တကျ၊ တိတိကျကျ လိုက်နာဆောင်ရွက်တာကို ဆိုလိုပါတယ်။
ဒါပေမယ့် ဘယ်လောက် တင်းကျပ်မလဲ ဆိုတာကတော့ Project အမျိုးအစားပေါ် မူတည်ပါတယ်။
- High Formality: လေယာဉ်ပျံ ထိန်းချုပ်စနစ်၊ ဆေးဘက်ဆိုင်ရာ စက်ကိရိယာများ၊ ဘဏ်စနစ်များ။ (အမှားမခံသောကြောင့် Specification များကို သင်္ချာနည်းကျ ရေးသားရသည်၊ စစ်ဆေးမှု အဆင့်ဆင့် လုပ်ရသည်)။
- Low Formality: ကိုယ်ပိုင် Blog၊ MVP၊ စမ်းသပ် Project များ။ (မြန်ဆန်မှုက အဓိက ဖြစ်သောကြောင့် Documentation အနည်းငယ်နှင့် Code ရေးနိုင်သည်)။
Engineer တစ်ယောက်အနေနဲ့ ကိုယ့် Project က ဘယ် Level မှာ ရှိလဲ ဆိုတာကို ဆုံးဖြတ်ပြီး လိုအပ်သလောက် Rigor ကို ထည့်သွင်းရပါမယ်။
၈.၇ Incremental Development
အခန်း ၂ (Process) နှင့် အခန်း ၃ (Agile) တို့တွင် ဆွေးနွေးခဲ့ပြီး ဖြစ်သကဲ့သို့၊ ကြီးမားသော စနစ်ကြီးတစ်ခုလုံးကို တစ်ခါတည်း တည်ဆောက်ခြင်း (Big Bang Approach) သည် ရှုံးနိမ့်နိုင်ခြေ (Risk) အလွန်များပါသည်။
ထို့ကြောင့် စနစ်ကို Increments (အတုံးအခဲ ငယ်လေးများ) အဖြစ် ပိုင်းခြားပြီး တစ်ခုပြီး တစ်ခု တည်ဆောက်ခြင်း၊ စမ်းသပ်ခြင်း၊ User Feedback ရယူခြင်းတို့ကို ပြုလုပ်ရပါမည်။
အကျိုးကျေးဇူးများ:
- Early Feedback: သုံးစွဲသူ လိုချင်တာနဲ့ ကိုယ်လုပ်နေတာ လွဲနေရင် စောစောစီးစီး သိရပါသည်။
- Risk Management: ပြဿနာတက်ရင် အစိတ်အပိုင်းလေး တစ်ခုမှာပဲ တက်တာမို့ ပြင်ဆင်ရ လွယ်ကူပါသည်။
၈.၈ The Principle of Least Astonishment (POLA)
ဒါကတော့ User Experience (UX) နဲ့ API Design ပိုင်းမှာ အရမ်းအရေးကြီးတဲ့ Principle ပါ။ "မင်းရဲ့ Software ဟာ အသုံးပြုသူ မျှော်လင့်ထားတဲ့ အတိုင်းပဲ အလုပ်လုပ်သင့်တယ်။ သူတို့ကို အံ့အားသင့်အောင် (Surprise) မလုပ်သင့်ဘူး" လို့ ဆိုလိုတာပါ။
ဥပမာများ:
- UI: Save ခလုတ်ကို နှိပ်လိုက်ရင် Data ကို သိမ်းရမယ်။ Delete လုပ်ပစ်တာမျိုး၊ Print ထုတ်တာမျိုး မဖြစ်ရပါဘူး။
- Code:
getUsers()ဆိုတဲ့ Function ကို ခေါ်လိုက်ရင် User List ကို Return ပြန်ပေးရမယ်။ Database ထဲက User တွေကို သွားဖျက်ပစ်တာ (Side Effect) မျိုး မလုပ်သင့်ပါဘူး။
Code ရေးတဲ့အခါ "ငါ့ Code ကို နောက်လူ ဖတ်ရင် မျက်လုံးပြူးသွားမလား၊ ခေါင်းညိတ်မလား" ဆိုတာ အမြဲ စဉ်းစားပါ။ ရိုးရှင်းပြီး ခန့်မှန်းရ လွယ်ကူသော (Predictable) Code သည် အကောင်းဆုံး Code ဖြစ်ပါသည်။
Junior ဘဝ က ကိုယ်ရေးသည့် code တွေကို နောက်လူ မဖတ်တတ်အောင် ရေးသားခဲ့ဖူးပါတယ်။ တနည်းပြောရင် ကိုယ့် code တွေက အဆင့်မြင့်လို့ နောက်လူ နားမလည်ဘူး ထင်ရအောင်ပါ။ တကယ်တန်း အဆင့်မြင့်သည့် code တွေ က ဘယ်သူ ဖတ်ဖတ် နားလည် လွယ်ပါတယ်။ ဒါကြောင့် နောက်ပိုင်းမှာ Single Level of Abstraction Principle (SLAP) ပုံစံ နဲ့ ရေးဖြစ်ပါတယ်။
Single Level of Abstraction Principle (SLAP)
SLAP ဆိုသည်မှာ Function တစ်ခု ရေးသားရာတွင် Code များကို တူညီသော Abstraction Level တစ်ခုတည်းတွင်သာ ရှိနေစေရန် ရေးသားခြင်း ဖြစ်သည်။ High-level Logic (စီးပွားရေး လုပ်ငန်းစဉ်) နှင့် Low-level Details (Code အသေးစိတ်) များကို ရောထွေး မရေးသင့်ပါ။
Bad Example (Mixed Levels of Abstraction)
ဒီ Code မှာ checkout လုပ်တဲ့ အဓိက အလုပ်နဲ့၊ Database connection ဖွင့်တာ၊ Email format စစ်တာတွေ ရောထွေးနေပါတယ်။ စာဖတ်သူ အနေနဲ့ အတက်အကျ ကြမ်းလွန်းပါတယ်။
function checkout(cart: Cart, user: User) {
// Low-level detail (Checking email regex)
if (!user.email.includes('@')) {
throw new Error("Invalid Email");
}
// High-level logic
const total = cart.items.reduce((sum, item) => sum + item.price, 0);
// Low-level detail (Direct DB query)
db.query("INSERT INTO orders ...", [total, user.id]);
// Low-level detail (Email sending implementation)
const transporter = nodemailer.createTransport({ ... });
transporter.sendMail({ to: user.email, subject: "Order Placed" });
}
Good Example (SLAP Applied)
ဒီ Code မှာတော့ checkout function က မန်နေဂျာ တစ်ယောက်လိုပါပဲ။ အသေးစိတ် မလုပ်ပါဘူး။ သက်ဆိုင်ရာ Function တွေကို လှမ်းခေါ်ခိုင်း (Delegate) ရုံပဲ လုပ်ပါတယ်။ ဖတ်လိုက်ရင် စာအုပ် ခေါင်းစဉ် ဖတ်ရသလို ရှင်းလင်း နေပါလိမ့်မယ်။
function checkout(cart: Cart, user: User) {
validateUser(user); // High-level
const total = calculateTotal(cart); // High-level
saveOrderToDatabase(total, user); // High-level
sendConfirmationEmail(user); // High-level
}
// Low-level details တွေကို သီးသန့် Function တွေထဲမှာ ဝှက်ထားလိုက်ပါတယ်
function validateUser(user: User) {
if (!user.email.includes('@')) throw new Error("Invalid Email");
}
// ... other functions
SLAP ကို လိုက်နာခြင်းအားဖြင့် Code သည် "အံ့အားသင့်စရာ" မရှိတော့ဘဲ၊ မျှော်လင့်ထားသည့် အတိုင်း အဆင့်ဆင့် (Step-by-step) ရှင်းလင်းစွာ အလုပ်လုပ်သွားကြောင်း တွေ့မြင်ရမည် ဖြစ်ပါသည်။
Summary
Software Engineering ဆိုသည်မှာ Code ရေးရုံ သက်သက် မဟုတ်ပါ။ အထက်ပါ အခြေခံ မူဝါဒများကို နားလည်ပြီး လက်တွေ့ အသုံးချနိုင်မှသာ "Coder" အဆင့်မှ "Engineer" အဆင့်သို့ ကူးပြောင်းနိုင်မည် ဖြစ်သည်။ Language တွေ၊ Tool တွေ ပြောင်းလဲသွားနိုင်ပေမယ့် Separation of Concerns, Modularity, Encapsulation စသည့် တန်ဖိုးတရားများကတော့ Software ရှိနေသမျှ ကာလပတ်လုံး တည်မြဲနေမည့် အမှန်တရားများ ဖြစ်ပါသည်။