πŸŒ€
f1v3-log
  • Welcome
  • 개발
    • SecurityContextλ₯Ό μƒˆλ‘œ λ§Œλ“€μ–΄μ•Ό ν• κΉŒ?
    • OAuth2AuthorizationRequestResolver μ»€μŠ€ν„°λ§ˆμ΄μ§•
    • λ™μ‹œμ„± 문제λ₯Ό ν•΄κ²°ν•΄λ³΄μž
    • MySQL은 μ–΄λ–»κ²Œ ID 값을 순차적으둜 λ„£μ–΄μ£ΌλŠ” κ²ƒμΌκΉŒ? (Feat. Auto Increment Lock)
    • μ™ΈλΆ€ API ν˜ΈμΆœμ— λŒ€ν•œ κ³ μ°°
      • HTTP Clients in Spring Boot
      • I/O와 νŠΈλžœμž­μ…˜ λΆ„λ¦¬ν•˜κΈ°
      • 처리율 μ œν•œ μž₯치 (Rate Limiter) λ„μž…
      • μ™ΈλΆ€ API μ˜μ‘΄μ„±μ„ μ€„μ—¬λ³΄μž
      • μΊμ‹œ λ ˆμ΄μ–΄λ₯Ό κ΅¬μ„±ν•΄λ³΄μž (Local Cache)
    • JPA Deep Dive
      • 결제 및 μ •μ‚° μ‹œμŠ€ν…œ κΈ°λŠ₯ μš”κ΅¬μ‚¬ν•­ 뢄석
      • κΈ€λ‘œλ²Œ μ„œλΉ„μŠ€λ₯Ό κ³ λ €ν•  λ•Œ, νƒ€μž„μ‘΄ 이슈λ₯Ό μ–΄λ–»κ²Œ μ²˜λ¦¬ν•΄μ•Ό ν• κΉŒ?
      • Spring Data JPA - ID 생성 μ „λž΅κ³Ό μ±„λ²ˆμ€ μ–΄λ–»κ²Œ λ˜λŠ”κ±ΈκΉŒ?
  • 회고
    • NHN Academy 인증과정 회고
    • DND 11κΈ° 회고
  • λ…μ„œ
    • Effective Java 3/E
      • Item 1. μƒμ„±μž λŒ€μ‹  정적 νŒ©ν„°λ¦¬ λ©”μ„œλ“œλ₯Ό κ³ λ €ν•˜λΌ
      • Item 2. μƒμ„±μžμ— λ§€κ°œλ³€μˆ˜κ°€ λ§Žλ‹€λ©΄ λΉŒλ”λ₯Ό κ³ λ €ν•˜λΌ
      • Item 3. private μƒμ„±μžλ‚˜ μ—΄κ±° νƒ€μž…μœΌλ‘œ μ‹±κΈ€ν„΄μž„μ„ λ³΄μ¦ν•˜λΌ
    • 객체지ν–₯의 사싀과 μ˜€ν•΄
      • 1μž₯. ν˜‘λ ₯ν•˜λŠ” κ°μ²΄λ“€μ˜ 곡동체
      • 2μž₯. μ΄μƒν•œ λ‚˜λΌμ˜ 객체
      • 3μž₯. νƒ€μž…κ³Ό 좔상화
      • 4μž₯. μ—­ν• , μ±…μž„, ν˜‘λ ₯
      • 5μž₯. μ±…μž„κ³Ό λ©”μ‹œμ§€
      • 6μž₯. 객체 지도
      • 7μž₯. ν•¨κ»˜ λͺ¨μœΌκΈ°
  • Real MySQL 8.0
    • 04. μ•„ν‚€ν…μ²˜
    • 05. νŠΈλžœμž­μ…˜κ³Ό 잠금
    • 08. 인덱슀
    • 09. μ˜΅ν‹°λ§ˆμ΄μ €μ™€ 힌트
  • 생각정리
    • κΈ°μˆ μ— λ§€λͺ°λ˜μ§€ 말자.
  • 곡뢀
    • 객체지ν–₯ 5원칙(SOLID)
      • SRP (Single Responsibility Principle)
      • OCP (Open Closed Principle)
Powered by GitBook
On this page
  • Open and Closed
  • OCP Example
  • OCPκ°€ κ°€λŠ₯ν•œ 것인가?
  • A Smelly Design
  • Rigidity / Fragility / Immobility Problem
  • 경직성(Rigidity)
  • μ·¨μ•½μ„±(Fragility)
  • 뢀동성(Immobility)
  • The Lie
  • Two Solutions
  • Big Design Up Front(BDUF)
  • Agile Design - μ€μœ λ²•
  • μ€μœ λ²•
  • 정리 및 핡심

Was this helpful?

  1. 곡뢀
  2. 객체지ν–₯ 5원칙(SOLID)

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)은 λ³„λ„λ‘œ 집계

  • 리포트 ν•˜λ‹¨μ— 식사 λΉ„μš© 총앑과 전체 λΉ„μš© 총앑을 좜λ ₯

μœ„ μ½”λ“œμ˜ λ¬Έμ œμ μ€ λ¬΄μ—‡μΌκΉŒ?

  1. SRP μœ„λ°˜

  • λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™, λ©”μ‹œμ§€ 생성, ν¬λ§·νŒ…κ³Ό 같은 ν•˜λ‚˜μ˜ μ±…μž„λ§Œμ„ κ°€μ§€κ³  μžˆλŠ” μƒνƒœκ°€ μ•„λ‹˜

  1. 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λ₯Ό μ€€μˆ˜ν•˜λ„λ‘ ν•˜μž.

  • λ„ˆλ¬΄ κΉŠμ€ 섀계가 μ•„λ‹Œ, μ μ ˆν•œ μ‹œμŠ€ν…œ λͺ¨λΈμ— λŒ€ν•œ 사전 섀계λ₯Ό μ§„ν–‰ν•˜μž.

PreviousSRP (Single Responsibility Principle)

Last updated 13 days ago

Was this helpful?

GitHub - msbaek/expense: Clean Coders Episode 10 OCP Expense ExampleGitHub
Logo