OCP (Open Closed Principle)
Open and Closed
"Open for extension But, Closed for modification"
ํ์ฅ์ ๋ํด์๋ ์ด๋ ค์๊ณ ๋ณ๊ฒฝ์ ๋ํด์๋ ๋ซํ์์ด์ผ ํ๋ค.
์ฌ๊ธฐ์์ "Open for extendsion" ์ด๋ ์๋ก์ด ํ์ ์ ์ถ๊ฐํจ์ผ๋ก์จ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
๊ทธ ๋ค์ "Closed for modification" ์ด๋ ์ด๋ฌํ ํ์ฅ์ด ์ผ์ด๋ ๋ ์์ ๋ ๋ฒจ์ด ์ํฅ์ ๋ฐ์ง ๋ง์์ผ ํ๋ค๋ ๊ฒ์ ์๋ฏธํ๋ค.
์ด๋ฌํ ๋ฐฉ์์ ์ ์ค์ํ๋ค๋ฉด, ์ด๋ค ๋ชจ๋์ ํ์๋ฅผ ์์ค์ฝ๋์ ๋ณ๊ฒฝ ์์ด ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์๋ค.
OCP Example
OCP๋ฅผ ์งํค๊ธฐ ์ํด์๋ ์ถ์ํ์ ์ญ์ (Inversion)์ด ํ์ํ๋ค.
insert abstract interface between copy and device
cause the inverted dependencies
interface Reader {
Integer getChar();
}
interface Writer {
void putChar(Integer c);
}
public class Copy {
public void copy(Reader reader, Writer writer) {
Integer c;
while ((c = reader.getChar() != null)) {
writer.putChar(c);
}
}
}
class TestReader implements Reader {
@Override
public Integer getChar() {
// do something...
}
}
class TestWriter implements Writer {
@Override
public void putChar(Integer c) {
// do something...
}
}
Reader, Writer๊ฐ ์ถ๊ฐ๋๋ค๊ณ Copy ํด๋์ค์ ๋ณ๊ฒฝ์ด ์ผ์ด๋ ๊น?
๋๋ฐ์ด์ค(Reader, Writer)๊ฐ ์ถ๊ฐ๋๋ฉด ํด๋น ๋์๋น์ค๋ฅผ ๋ด๋นํ๋ ํด๋์ค๋ฅผ ์ถ๊ฐํ์ง๋ง, copy ๋ก์ง์ ์์ ์ ์ผ์ด๋์ง ์๋๋ค.
OCP๊ฐ ๊ฐ๋ฅํ ๊ฒ์ธ๊ฐ?
OCP๋ฅผ ์ค์ํ๋ฉด ๋ณ๊ฒฝ์ ์๋ฒฝํ๊ฒ ์ ๊ฑฐํ ์ ์๋๊ฐ?
์ด๋ก ์ ์ผ๋ก๋ ๊ฐ๋ฅํ๋ค.
ํ์ง๋ง, ์ค์ฉ์ ์ด์ง ์๋ค.
2๊ฐ์ง ๋ฌธ์ ์
main partition
๋ฉ์ธ ํํธ์ ๊ฒฝ์ฐ if-else๊ฐ ์์ ์ ์๋ค. ์คํ๋ง๊ณผ ๊ฐ์ด DI ์ปจํ ์ด๋๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ ๋์ ํด์ฃผ๋๊น ๋ฐฐ์ ํ๊ฒ ๋๋ค.
Crystal ball problem (๋ง๋ฒ์ ์์ ๊ตฌ์ฌ ๋ฌธ์ )
๋๋ ๋ชจ๋ฅด๋ ๊ฒ์ด ๋ง๊ธฐ ๋๋ฌธ์ ๋ฏธ๋ฆฌ ์ธํฐํ์ด์ค๋ฅผ ๋ค ์ค๋นํ๋ ๋ฐฉ์์ ์ฌ์ค์ ๋ถ๊ฐ๋ฅํ๋ค.
ํ์ฅ์ ํ์ํ ๋ชจ๋ ๊ฒ์ ์ธํฐํ์ด์คํ ํ๋ค๋ฉด ๊ต์ฅํ ๋ณต์กํด์ง ๊ฒ์ด๋ค.
A Smelly Design
public void printReport(ReportPrinter printer) {
int total = 0;
int mealExpenses = 0;
printer.print("Expenses " + getDate() + "\n");
for (Expense expense : expenses) {
if (expense.type == BREAKFAST || expense.type == DINNER)
mealExpenses += expense.amount;
String name = "TILT";
switch (expense.type) {
case DINNER: name = "Dinner"; break;
case BREAKFAST: name = "Breakfast"; break;
case CAR_RENTAL: name = "Car Rental"; break;
}
printer.print(String.format("%s\t%s\t$%.02f\n",
( (expense.type == DINNER && expense.amount > 5000)
|| (expense.type == BREAKFAST && expense.amount > 1000)) ? "X" : " ",
name, expense.amount / 100.0));
total += expense.amount;
}
printer.print(String.format("\nMeal expenses $%.02f",mealExpenses / 100.0 ));
printer.print(String.format("\nTotal $%.02f", total / 100.0));
}
๋น์ฉ(Expense) ๋ชฉ๋ก์ ๋ฐํ์ผ๋ก ๋ฆฌํฌํธ๋ฅผ ์ถ๋ ฅํ๋ ๋ฉ์๋
๊ฐ ๋น์ฉ์ ์ข ๋ฅ์ ๊ธ์ก์ ์ถ๋ ฅํ๋ฉฐ, ์์ฌ ๋น์ฉ(BREAKFAST, DINNER)์ ๋ณ๋๋ก ์ง๊ณ
๋ฆฌํฌํธ ํ๋จ์ ์์ฌ ๋น์ฉ ์ด์ก๊ณผ ์ ์ฒด ๋น์ฉ ์ด์ก์ ์ถ๋ ฅ
์ ์ฝ๋์ ๋ฌธ์ ์ ์ ๋ฌด์์ผ๊น?
SRP ์๋ฐ
๋ฉ์๋ ๋ด๋ถ์์ ๋น์ฆ๋์ค ๊ท์น, ๋ฉ์์ง ์์ฑ, ํฌ๋งทํ ๊ณผ ๊ฐ์ ํ๋์ ์ฑ ์๋ง์ ๊ฐ์ง๊ณ ์๋ ์ํ๊ฐ ์๋
OCP ์๋ฐ
๋น์ฆ๋์ค ๊ท์น์ ํ์ฅํ๋ ค๋ฉด ์์ ์ด ํ์ํ ์ํ
๋ํ, ๋ฉ์์ง ์์ฑ ๋ฐ ํฌ๋งทํ ์ ํ์ฅํ๋ ค๋ฉด ์์ ์ด ํ์ํ ์ํ
Rigidity / Fragility / Immobility Problem
์ ์ฝ๋์์์ ๋ฌธ์ ์ ๋ค์ ๋ํด์ ๋ถ์ํด๋ณด์.
๊ฒฝ์ง์ฑ(Rigidity)
์์คํ ์์ ํ๋์ ๋ณ๊ฒฝ์ด ๋ชจ๋ ๋ณ๊ฒฝ์ ์ ๋ฐํ ๊ฒฝ์ฐ ๊ฒฝ์ง์ฑ์ด ๋๋ค๊ณ ํ๋ค.
์์ฌ ํ์ (meal type)์ LUNCH, SNACK ๊ณผ ๊ฐ์ ํ์ ์ ์ถ๊ฐํ๋ค๋ ์๊ตฌ์ฌํญ์ ๋์ํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ๋๊ฐ?
Even though the design change is small, the impact is huge. So the system resist change. It's rigid.
์ค๊ณ ๋ณ๊ฒฝ์ ์ฌ์ํด ๋ณด์ด์ง๋ง, ๊ทธ ์ํฅ์ ๋งค์ฐ ํฝ๋๋ค. ๊ทธ๋์ ์์คํ ์ ๋ณํ์ ์ ํญํฉ๋๋ค. ์ด๊ฒ์ด ๊ฒฝ์ง๋ ์ํ์ ๋๋ค.
์ทจ์ฝ์ฑ(Fragility)
์์คํ ์์ ํ๋์ ๋ณ๊ฒฝ์ผ๋ก ์ธํด ์ ์ฒด์ ์ผ๋ก ์ทจ์ฝํ ๋ถ๋ถ์ด ๋ง์ด ์๊ธฐ๋ ๊ฒ์ ๋งํ๋ค.
switch๋ฌธ์ด๋ ์กฐ๊ฑด๋ฌธ์ผ๋ก ๋๋ ๊ฒฝ์ฐ, ๋ณ๊ฒฝ์ ๊ฐํ ๋ ๋๋ฝ๋๋ ๊ฒ์ด ์๋์ง, ์๋ชป ๋ณ๊ฒฝํ ๊ฒ์ ์๋์ง ์ด๋ป๊ฒ ์ฒดํฌํ์ง?
์ฆ, Fan-out Problem์ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ Fragilityํ๋ค. ๋ชจ๋ Design smell ์ค Fragility๊ฐ ๊ฐ์ฅ ๋จผ์ ์ ๊ฑฐํด์ผํ ๋์์ด๋ค.
๋ถ๋์ฑ(Immobility)
์์คํ ์ ์ฌ์ฌ์ฉ์ฑ์ด ๋จ์ด์ง๊ณ , ์ฝ๋์ ๋ณ๊ฒฝ์ด ์ด๋ ค์ด ๊ฒ์ ๋งํ๋ค.
๊ธฐ์ ์ฉ ์๋ฃจ์ ์ ๋ง์ถฐ์ง ์์คํ ์ ๋๋ถ๋ถ์ ๊ธฐ๋ฅ์ด ํ์ํ์ง ์๋ ์์ ๋น์ฆ๋์ค ์์ญ์ผ๋ก ๋ถ๋ฆฌํ ์ ์์๊น?
The Lie
๊ณ ๊ฐ์ด ์ ํ ๊ณ ๋ คํ์ง ์์ ์๋ก์ด ๊ธฐ๋ฅ์ ์๊ตฌํ๋ฉด ๋์ฑ ์ด ์๋ค. ๋ง์ผ ๋ฏธ๋ฆฌ ์๊ธฐํด์คฌ๋ค๋ฉด ์ถ์ํ๋ฅผ ์ ์ฉํ์ ๊ฒ์ด๋ค.
โ ๊ทธ๋ ๋ค๋ฉด, OCP๋ฅผ ์ค์ํ๊ธฐ ์ํด์๋ ๋ฏธ๋์ ์ด๋ค ์ผ, ์ด๋ค ํ์ฅ์ด ํ์ํ์ง ๋ฏธ๋ฆฌ ๋ค ์์์ผ ํ๋ค๋ ๋ง์ธ๊ฐ?
์ฐ๋ฆฌ๊ฐ ์๋ฌด๋ฆฌ ์ ์ค๋นํ๊ณ ์์ธกํด๋, ๊ณ ๊ฐ์ ์ค๋นํ์ง ๋ชปํ ๊ฒ์ ๋ํ ๊ธฐ๋ฅ ์ถ๊ฐ/๋ณ๊ฒฝ์ ์๊ตฌํ๋ค.
โ ์ด ๊ฒ์ ํด๊ฒฐํ๊ธฐ ์ํด์ ๋ง๋ฒ์ ์์ ๊ตฌ์ฌ(Crystal ball)์ด ํ์ํ๊ฑฐ ์๋๊ฐ?
์ด๊ฒ์ด OCP์ ๋ํ ๋น๋ฐ์ด๋ค. ์ฐ๋ฆฌ๊ฐ ๋ฏธ๋๋ฅผ ์์ธกํ ์ ์์ ๋๋ง ํด๋น ๊ธฐ๋ฅ์ ๋ณดํธํ ์ ์๋ค.
Two Solutions
์ฐ๋ฆฌ๋ ๋ฏธ๋๋ฅผ ์์ธกํ์ง ๋ชปํ๋๋ฐ ์ด๋ป๊ฒ OCP๋ฅผ ์งํฌ ์ ์์๊น?
Big Design Up Front(BDUF)
๊ณผ๋ํ ์ค๊ณ๋ฅผ ํ๋ ๊ฒ์ด๋ค. ์ฝ๋๋ฅผ ํ ์ค์ ์์ฑํ๊ธฐ ์ , ์ค๊ณ๋ฅผ ๊ต์ฅํ ๋ง์ด ํ๋ ๋ฐฉ๋ฒ์ด๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ
๊ณ ๊ฐ๊ณผ ๋ฌธ์ ์์ญ์ ๊ณ ์ฐฐํ๋ฉฐ, ์๊ตฌ์ฌํญ์ ์์ธกํ์ฌ ๋๋ฉ์ธ ๋ชจ๋ธ์ ๋ง๋ ๋ค.
OCP๊ฐ ๊ฐ๋ฅํ๋๋ก ๋๋ฉ์ธ ๋ชจ๋ธ์ ์ถ์ํ๋ฅผ ์ ์ฉํ๋ค.
๋ชจ๋ ๊ฒ์ ๋ํ ์ฒญ์ฌ์ง์ ์ป์ ๋ ๊น์ง ๋ฐ๋ณตํ๋ค.
๋ฌธ์
ํ์์น ์๋ ์ถ์ํ๋ก ๋๋ฐฐ๋ ๋งค์ฐ ํฌ๊ณ , ๋ฌด๊ฒ๊ณ ๋ณต์กํ ์ค๊ณ๊ฐ ๋์ด๋ฒ๋ฆด ์ ์๋ค.
์ถ์ํ๋ ์ ์ฉํ๊ณ ๊ฐ๋ ฅํ ๋งํผ ๋น์ฉ๋ ํฌ๋ค.
๋ง์ ๊ณ ๊ฐ์ ์ฐ๋ฆฌ๊ฐ ์ถ์ํ ํด๋ ผ ๊ฒ์ ๋ํ ๋ณ๊ฒฝ์ ์์ฒญํ์ง ์๋๋ค. ์ฆ, ํจ์จ์ ์ธ ๋ฐฉ์์ด ์๋๋ค!
Agile Design - ์์ ๋ฒ
์ค์ฉ์ ์ด๊ณ ๋ฐ์์ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ์ฅ ์ข์ ์์๋ฒ์ ์์ ๋ฒ(๋ฉํํฌ)์ด๋ค.
์์ ๋ฒ
์ต๋ํ ๋นจ๋ฆฌ ๊ณ ๊ฐ์ ์๊ตฌ์ฌํญ์ ๋์ด๋ผ ์ ์๋ ๊ฐ์ฅ ๋จ์ํ ์ผ์ ํ๋ค.
๊ทธ๋ ๋ค๋ฉด ๊ณ ๊ฐ์ ๊ทธ ๊ฒฐ๊ณผ๋ฌผ์ ๋ํด ์๊ตฌ์ฌํญ ๋ณ๊ฒฝ์ ์์ํ๋ค.
๋ฐ๋ผ์, ์ด๋ค ๋ณ๊ฒฝ์ด ์๊ตฌ๋๋์ง ์๊ฒ๋๋ค.
[์๋๋ฆฌ์ค]
- ๋ณ์ฌ๋ค์ด ์ ๊ตฐ์ ์ฌ๊ฒฉ์ ํฌ์๋๋ค.
- ์ดํ์ด ๋๋ฐํ๊ณ ์๋ ๊ฐ์ด๋ฐ ์ฐธํธ์ ์จ์ด์๋ค.
- ์ ์ ํฅํด ์ง์ค ์ฌ๊ฒฉํ ์ ์์ผ๋ฉด ์ ํฌ์์ ์น๋ฆฌํ๋ค.
- ๋ฌธ์ ๋ ์ด๋์ ์ ์ด ์์์ง ๋ชจ๋ฅธ๋ค๋ ๊ฒ์ด๋ค.
- ์ด๋ค ๋ฐฉํฅ์์ ์ ๋ค์ด ์ด์ ์๋์ง ๋ชจ๋ฅธ๋ค.
BDUF ๋ฐฉ์์ผ๋ก ์ ๊ทผํ๋ค๋ฉด, ํฌ์๋ง์ด ์ขํ์ ธ ๋ ๋์ ์ํฉ์ด ๋์ด๋ฒ๋ฆฐ๋ค.
์ด๋ฌํ ์ํฉ์์ ์์ฌ๊ฐ XXX ์ผ๋ณ์๊ฒ ์ผ์ด๋๋ผ๊ณ ๋ช
๋ นํ๋ค.
=> ์ ๊ตฐ์ด ์ฌ๊ฒฉํ๋ค. ์ฐ๋ฆฌ๋ ์ด์์ด ๋ ์์จ ๋ฐฉํฅ์ ์์๋ธ ๊ฒ์ด๋ค. (์ด๊ฒ ๋ง๋?)
์ด ๋ด์ฉ์ผ๋ก ์ ์ ์๋ ๊ฒ์ ๋ณํ์ ๋ํ ๊ฐ์ฅ ์ข์ ์์ธก์ ๋ณํ๋ฅผ ๊ฒฝํํ๋ ๊ฒ์ด๋ผ๋ ๊ฒ์ด๋ค.
๋ฌผ๋ก ์ฐ๋ฆฌ๋ BDUF์ Agile ๋ ๊ทน๋จ ์ฌ์ด์ ์ด์๊ฐ๋ค. BDUF๋ ํผํด์ผ ํ์ง๋ง No DUF๋ ํผํด์ผ ํ๋ค! ์์คํ ์ ๋ํด์ ์ฌ๊ณ ํ๊ณ Decoupled ๋ชจ๋ธ์ ์ฌ์ ์ ์ค๊ณํ๋ ๊ฒ์ ๋งค์ฐ ๊ฐ์น์๋ ์ผ์ด๋ค.
์ ๋ฆฌ ๋ฐ ํต์ฌ
์ฐ๋ฆฌ๋ ์๋ฒฝํ ๋ฏธ๋๋ฅผ ์์ธกํ ์ ์๋ค. ๋ฆฌํฉํ ๋ง์ ํตํด์ ์ถ์ํํ๋ฉฐ OCP๋ฅผ ์ค์ํ๋๋ก ํ์.
๋๋ฌด ๊น์ ์ค๊ณ๊ฐ ์๋, ์ ์ ํ ์์คํ ๋ชจ๋ธ์ ๋ํ ์ฌ์ ์ค๊ณ๋ฅผ ์งํํ์.
Last updated
Was this helpful?