Skip to content

Latest commit

ย 

History

History
141 lines (100 loc) ยท 6.83 KB

File metadata and controls

141 lines (100 loc) ยท 6.83 KB

Humble Object Pattern

CC E23 Mocking Part2์— ๋‚˜์˜ด

humble object pattern์€ 2๊ฐ€์ง€ ๊ด€์ ์—์„œ ๋ฐ”๋ผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

  1. H/W ๋“ฑ ๊ตฌ์ฒด์ ์ธ ์ฝ”๋“œ์— ์˜์กดํ•˜๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์ž

    • ๋‚ด ๋กœ์ง์—์„œ H/W ์˜์กด์ ์ธ ๋ถ€๋ถ„์„ Humble Interface๋ฅผ ํ†ตํ•ด ๋ถ„๋ฆฌํ•˜๊ณ  ๋‚ด ๋กœ์ง์€ Unit Test
  2. ์„œ๋ฒ„ ๋กœ์ง์— ์˜์กดํ•˜๋Š” UI ๊ฐœ๋ฐœ์ž(App, Web Front)

    • GUI์—์„œ Process Interface(Humble Interface)๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ  Fake ๊ตฌํ˜„์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ 
    • ๋‚ด ๋กœ์ง(GUI)์€ ์ˆ˜๋™์œผ๋กœ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๋งŒํผ Humbleํ•˜๊ฒŒ ์œ ์ง€

1์˜ ๊ฒฝ์šฐ๋Š” H/W ๋“ฑ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ž์‹ ์˜ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋ฉด์„œ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ด๊ณ ,

2์˜ ๊ฒฝ์šฐ๋Š” ์„œ๋ฒ„ ๋กœ์ง๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ž์‹ ์˜ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋ฉด์„œ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ด๋‹ค.

๊ฐ๊ฐ์— ๋Œ€ํ•ด์„œ ์‚ดํŽด๋ณด์ž.

1. H/W ๋“ฑ ๊ตฌ์ฒด์ ์ธ ์ฝ”๋“œ์— ์˜์กดํ•˜๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์ž

Alt text

  • Humble ์˜ค๋ธŒ์ ํŠธ ํŒจํ„ด์€ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด ์‹œ์Šคํ…œ์˜ ๊ฒฝ๊ณ„์— ์ ์šฉ
  • ๊ฒฝ๊ณ„(HW, DB ๋“ฑ)์— ์ข…์†๋œ ํด๋ž˜์Šค(Humble Object)์˜ ๋กœ์ง์„ ํ…Œ์ŠคํŠธ ํ•  ํ•„์š” ์—†์„ ์ •๋„๋กœ ์ตœ์†Œํ™”(humbleํ•˜๊ฒŒ - Humble Controller)

Alt text

  • ๊ฒฝ๊ณ„์— ์ข…์†๋œ ํด๋ž˜์Šค(Humble Controller)์—์„œ ์ถ”์ถœ๋œ ์ค‘์š”ํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง(Controller Logic)์€ ๊ฒฝ๊ณ„์™€ decouple๋˜๊ณ , ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ํด๋ž˜์Šค(Business Object)๋กœ ์ด๋™
  • Business Object๋Š” Humbler Object๋ฅผ Boundary Interface๋ฅผ ํ†ตํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  Humble Object์˜ ์กด์žฌ๋ฅผ ๋ชจ๋ฅด๊ฒŒ ๋œ๋‹ค(DIP)
  • Humble Object๋Š” Boundary Interface๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

์ด ๋ง์€ ์šฐ๋ฆฌ๊ฐ€ spring์„ ์‚ฌ์šฉํ•  ๋•Œ Controller, Dao, Repository ๋“ฑ์˜ ๊ตฌํ˜„์ฒด์—์„œ ๊ฒฝ๊ณ„(UI, DB)์— ์†ํ•œ ๋กœ์ง๋“ค์„ ํ…Œ์ŠคํŠธํ•  ํ•„์š”๊ฐ€ ์—†์„ ๋งŒํผ Humbleํ•˜๊ฒŒ ํ•˜์—ฌ Interface ๋’ค๋กœ ์ˆจ๊ธฐ๊ณ (Interface์˜ ๊ตฌํ˜„์ฒด๊ฐ€ ๋˜๋„๋ก), ์šฐ๋ฆฌ ์ฝ”๋“œ๋Š” ์ด Interface์— ์˜์กดํ•˜๊ณ  ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ํ…Œ์ŠคํŠธํ•  ํ•„์š”๊ฐ€ ์žˆ๋Š” ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด ์ฝ”๋“œ์™€ Interface๋ฅผ ํ†ตํ•ด ๋ถ„๋ฆฌํ•˜์—ฌ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.

1.1 Example

package humbleobject.milker;

public class HumbleMilkPumpController {
    public void engage() {
        for (int speed=1; speed<=6; speed++) {
            setPumpSpeed(speed);
            sleep(500);
        }
        setPumpSpeed(7);
    }

    /**
     * hard to test code
     * because too much dependent on control board
     *
     * turn speed into binary digits(3 digits)
     * set speed in specific IO register
     */
    private void setPumpSpeed(int speed) {
        // set decimal to binary
        // get IO register from control board
        // set binary digits to IO register to control speed
    }

    private void sleep(int milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) { }
    }
}
  • ์œ ์ถ•๊ธฐ์—์„œ ๊ฒŒ์ดํŠธ(์ “์†Œ๋“ค์ด ์œ ์ถ•์žฅ์— ๊ฐ€๋‘๋Š”)๋ฅผ ์ œ์–ดํ•˜๋Š” pump๊ฐ€ ์ปจํŠธ๋กค ๋ณด๋“œ์— ์˜ํ•ด ๊ตฌ๋™๋˜๋Š” ๊ฒฝ์šฐ ๊ฐ€์ •
  • ์ปจํŠธ๋กค ๋ณด๋“œ์™€ ํ˜‘์—…ํ•˜๋Š” pump ๊ด€๋ จ ์ฝ”๋“œ(HumbleMilkPumpController#setPumpSpeed)๋Š” ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
  • HumbleMilkPumpController(์ปจํŠธ๋กค ๋ณด๋“œ์™€ ํ˜‘์—…ํ•˜๋Š” ๋กœ์ง)์—์„œ ์ปจํŠธ๋กค ๋ณด๋“œ์™€ ๋ถ„๋ฆฌ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ถ”์ถœํ•˜์—ฌ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ํด๋ž˜์Šค(MilkPump)๋กœ ์ด๋™์‹œํ‚ค๋Š” ๊ฒƒ
  • ์ด ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ํด๋ž˜์Šค(MilkPump)๋Š” ์ปจํŠธ๋กค ๋ณด๋“œ์— ๋Œ€ํ•ด์„œ ์•Œ์ง€ ๋ชปํ•œ๋‹ค. ์ด๋Ÿฐ ์ž‘์—… ํ›„์—๋Š” ์ปจํŠธ๋กค๋Ÿฌ์™€ ์ง์ ‘ ํ†ต์‹ ํ•˜๋Š” ์•„์ฃผ ์ž‘์€ ์ฝ”๋“œ๋งŒ์ด ๋‚จ๊ณ , ํ…Œ์ŠคํŠธํ•  ํ•„์š”๊ฐ€ ์—†๊ฒŒ๋œ๋‹ค. HumbleController์— ๋‚จ์€ ์ฝ”๋“œ๋Š” ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”์—†๋Š” ์ง์ ‘ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ œ์–ดํ•˜๋Š” ์ตœ์†Œํ•œ์˜ ์ฝ”๋“œ์ด๋‹ค.

์œ„ ๋‹ค์ด์–ด๊ทธ๋žจ์—์„œ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ค‘์š”ํ•œ ์ฝ”๋“œ๋Š” Controller Logic์ด๋‹ค. ์ด ๋กœ์ง์ด ์˜์กดํ•˜๊ณ  ์žˆ๋Š” Humble Controller๋Š” ํ…Œ์ŠคํŠธ, ๊ฐœ๋ฐœ์—์„œ ์ œ์™ธํ•˜๊ณ  ์‹ถ๋‹ค.

1.1.1 Extract Boundary Interface

Alt text

  • PumpRegister๋Š” ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด ์ฝ”๋“œ
  • engage๊ฐ€ ํ…Œ์ŠคํŠธํ•˜๋ ค๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • setPumpSpeed, sleep๋Š” override ๊ฐ€๋Šฅ
  • PumpRegister๊ฐ€ controll board๋ฅผ ์ œ์–ด(ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด IO ์ž‘์—…)

์ด์ œ HumbleMilkPumpController๋Š” ๋” ์ด์ƒ Humbleํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ MilkPump๋กœ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•œ๋‹ค.

ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด ์ฝ”๋“œ(PumpRegister)์™€ ์•Œ๊ณ ๋ฆฌ์ฆ˜(engage)์„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ ˆ์ฐจ๋กœ ๋ถ„๋ฆฌํ–ˆ๋‹ค.

  1. ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด ์ฝ”๋“œ(IO๋ฅผ ํ•˜๋Š” ์ฝ”๋“œ์—ฌ์„œ)๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค(PumpRegister) ๋’ค๋กœ ์ˆจ๊ธด๋‹ค(ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด, ํ•  ํ•„์š”๊ฐ€ ์—†์„๋งŒํผ Humbleํ•œ ์ฝ”๋“œ๋ฅผ Humble Interface์˜ ๊ตฌํ˜„์ฒด๊ฐ€ ๋˜๋„๋กํ•œ๋‹ค)
  2. ๋ชจ๋“  rampUp ์•Œ๊ณ ๋ฆฌ์ฆ˜(engage() ๋ฉ”์†Œ๋“œ)์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋“ค์„ MilkPump ํด๋ž˜์Šค ๋‚ด์˜ ํ—ฌํผ ๋ฉ”์†Œ๋“œ๋กœ ์ถ”์ถœํ–ˆ๋‹ค(setPumpSpeed, sleep ๋“ฑ์„ protected๋กœ ์„ ์–ธํ•ด์„œ test์—์„œ overrideํ•  ์ˆ˜ ์žˆ๋„๋ก).
public class MilkPumpTest {
    private String actions = "";

    class TestingMilkPump extends MilkPump {
        @Override
        protected void setPumpSpeed(int speed) {
            actions += speed + "ss";
        }

        @Override
        protected void sleep(int milliseconds) {
            actions += milliseconds + "s";
        }
    }

    @Test
    public void engage() {
        TestingMilkPump milkPump = new TestingMilkPump();
        milkPump.engage();
        assertThat(actions, is("1ss500s2ss500s3ss500s4ss500s5ss500s6ss500s7ss"));
    }
}

์ด ํŒจํ„ด์€

  • testable code์™€ boundary๋ฅผ ๋„˜์–ด์„œ untestableํ•œ code๋ฅผ separateํ•˜๊ณ  decoupleํ•˜์—ฌ DI๋ฅผ ํ†ตํ•ด decoupling์„ ์ด๋ฃฌ๋‹ค.
  • ์ด๋ฅผ ํ†ตํ•ด untestable code๊ฐ€ testable code์— ์˜์กดํ•˜๋„๋ก DI๋ฅผ ์ ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ๋ถˆ๊ฐ€ํ•œ ์ฝ”๋“œ๊ฐ€ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ์— ์˜์กด์„ฑ์„ ๊ฐ–๋„๋กํ•œ๋‹ค.
  • ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์–ด๋ ค์šด ์–ด๋– ํ•œ boundary์—๋„ ์ด ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

2. ์„œ๋ฒ„ ๋กœ์ง์— ์˜์กดํ•˜๋Š” UI ๊ฐœ๋ฐœ์ž(App, Web Front)

Alt text

LoginActivity.java

LoginPresenterImpl.java

3. ๊ฒฐ๋ก 

  1. H/W ๋“ฑ ๊ตฌ์ฒด์ ์ธ ์ฝ”๋“œ์— ์˜์กดํ•˜๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์ž

    • ๋‚ด ๋กœ์ง์—์„œ H/W ์˜์กด์ ์ธ ๋ถ€๋ถ„์„ Humble Interface๋ฅผ ํ†ตํ•ด ๋ถ„๋ฆฌํ•˜๊ณ  ๋‚ด ๋กœ์ง์€ Unit Test
  2. ์„œ๋ฒ„ ๋กœ์ง์— ์˜์กดํ•˜๋Š” UI ๊ฐœ๋ฐœ์ž(App, Web Front)

    • GUI์—์„œ Process Interface(Humble Interface)๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ  Fake ๊ตฌํ˜„์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ 
    • ๋‚ด ๋กœ์ง(GUI)์€ ์ˆ˜๋™์œผ๋กœ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๋งŒํผ Humbleํ•˜๊ฒŒ ์œ ์ง€