📜 제목으로 보기

  • 참고 유튜브 : https://www.youtube.com/watch?v=navJTjZlUGk
  • 정리본: https://github.com/LenKIM/object-book
  • 코드: https://github.com/eternity-oop/object
  • 책(목차) : https://wikibook.co.kr/object/

ch10. 개발자의 세계

개발자의 세계

image-20220205203300192

  • 개발자는 IT회사내에서도 극히 희귀한 존재다.
    • 개발자를 도구로 바라본다. (생각을 주면 프로그램으로 바꿔줄거야)

Director

디렉터가 하는 일을 추상레이어로

image-20220205204027713

  • 악의 축 Director: 한국에선 잘 안쓰는 용어. 일본Director 미국, 한국PM

image-20220205204120062 image-20220205204253479

  • 디렉터가 하는 일:

    • Paper: 어디선가 지령서(기획서, Paper)를 받는다. Paper안의 사양서는 2가지 범주(Class)가 있고, 범주에 해당하는 프로젝트들을 수행할 것이다.

      • ServerClient : 1건, 서버+클라이언트 다 만든다.
      • Client: 2건, 클라이언트만 만든다.
    • Programmer: Director는 기획서 안의 사양서(1건, 2건)을 다 살펴본 뒤, 개발자들을 섭외해온다.

      • Programmer는 Paper(의 사양을 알아야 개발)를 기준으로 개발한다.(아는 관계 성립) image-20220205204425561
        • 디렉터는 Paper와 Programmer를 잘 연결해서 프로젝트를 수행하는 것이다.
      • Programmer는
        • FrontEnd
        • BackEnd로 나뉜다.

image-20220205204537445

  • Director가 바라보는 추상레이어는 PaperProgrammer가 될 것이고
    • PaperProgrammer가 각각 바라보는 추상레이어는
      • ServerClient/ClientFrontEnd/BackEnd가 될 것이다.
Paper

image-20220205204930129

  • Paper으로서 아무것도 메소드가 없는 인터페이스로서의 형이다.
    • 책에서는 인터페이스에 정의된 시그니쳐(추상메소드)를 오퍼레이터라 부름
      • 그 오퍼레이션이 구상클래스에서 구현되는 것을 메소드라 부름
      • 그렇다면, 인터페이스는 메소드를 가지는게 아니라 오퍼레이터를 가지는 것
Programmer

image-20220205205215745

  • Programmer외부에 프로그램을 만드는 인터페이스를 제공한다

    • my) 인터페이스 속 오퍼레이터, 메소드는 외부에 인터페이스를 제공하는 역할을 한다.

    • 팀장(PM, Director)이 "()(Paper paper)기획서를 던져주면서) 프로그램 만들어!"라고 명령할 수 있게끔

      • 프로그래머들은… 팀장에게 기능을 제공해주는 책임을 가지므로 메소드makeProgram()을 제공한다.
        • 이 때, 팀장이 기획서를 던져주면서 만들라고 하니, 인자를 던질 수 있게 기능 제공
      • my) 인터페이스든, 클래스든, 외부에서 나를 쓰는 놈에게 기능을 제공하기 위해 메소드를 정의한다.

      image-20220205205844064

Client

image-20220205205943360

  • Paper라는 추상클래스를 기반으로 구상클래스 Client를 구현해보자.
    • my) Paper나 Programmer는 각각의 공통점을 뽑아놓 상위개념 -> 추상층이다.
      • my) 실존하는 것들은 범주별로 impl해서 구현하고, 그 공통점을 가진 윗 개념은 추상클래스or인터페이스로 만들자.
  • Paper는 메소드가 없는 마커 인터페이스다.
    • Client용 프로젝트를 만들고 싶어서 Class로 구현한다.
    • client의 사양서에 들어있어야하는 내용들을 필드와 메소드로 채운다.
      • librarylanguage를 지정해주고
      • 프로젝트 담당할 programmer를 할당받을 변수도 미리 만들어놓자.
        • 개발자는 프로젝트 사양서 나오고, 나중에 할당되니, 초기화 없이 변수만
      • 추후 투입될 programmer를 박아줄 특정필드setter인 setProgrammer(프로그래머객체)도 만들어준다.
    • 나중에 수십개의 필드가 추가 되어야할 것이다.
    • 나중에 생성자에서 만들어도 되는데, 지금은 일단 대입해서 필드 초기화
ServerClient

image-20220205210600624

  • 마찬가지로 server + client를 다 개발할 수 있도록 하는 사양서의 내용을 채운다.

    • 사용할 server
    • 랭귀지 앞/뒤 2개
    • 프로그래머 앞/뒤 2명
      • 프로그래머 setter 2개
FrontEnd

image-20220206004905381

  • language와 library를 인식해서 자기만의 프로그램을 만든다.
    • Programmer를 구현해서 -> makeProgram을 제공하는데,
      • makeProgram내부에서 -> 자신만의 makeFrontEndProgram ( Program )을 만드는 기능을 제공한다.
    • 던지는 paper를 받아들여서, paper속에 있는 language와 library를 세팅해준 다음 -> 자신만의 프로그램을 만든다.
      • 이 때, Paper는 마커인터페이스이므로 paper로부터는 어떠한 정보를 얻어낼 수 없다 image-20220206005321132
      • 마커인터페이스 paper를 구현한 Client에서 정보를 얻기 위해 다운캐스팅(=OCP어김)할 수 밖에 없는 상황이다. image-20220206005449364
        • 다른 방법이 생각이 안날 것이다…
        • 대부분이 여기서 설계를 포기한다. 오늘의 핵심은 이 문제의 해결이다.
          • 리스코프 치환 원칙을 어김
          • OCP를 어김(부모자리에 자식이 들어갈 수 있다? 부모를 자식으로 바꿔야하는 상황에선.. 어기는 것이라고 함…)
        • SOLID원칙이나 설계원칙들을 배운다고 해서 이 문제를 해결할 순 없다. 저자가 강조하듯 코드로서 익혀야햐한다
  • 마커인터페이스 paper를 객체로 받을 때
    • paper 구현체인 Client일 수도 있고, ServerClient이 들어갈 수도 있다.
      • 바깥에서 Paper 구상체들이 늘어날때마다 if instanceof -> (다운캐스팅) 분기 가 늘어나도록 코드수정해야하는 문제점 발생할 것이다.
      • else의 처리가 지금은 생략되어있지만, 필요하며.. 또 그 밑으로 추가될 수도 있다.
  • 그래도 paper -> 구현체속 정보가 세팅되어야 -> 자신만의 프로그램을 만들 수 있는 상황이다.
BackEnd

image-20220206010030897

  • 백엔드 개발자도, 사정이 똑같다.
    • 마커인터페이스 -> 택1 구현체를 받아서 정보 받기 -> 확인용으로 다운캐스팅 해야하는 상황 + else 등 코드 추가 수정이 이루어질 예정임
  • 그래도 paper -> 구현체속 정보가 세팅되어야 -> 자신만의 프로그램을 만들 수 있는 상황이다.

  • 개발자의 세계 핵심문제: Paper받아서 구현체로부터 정보 빼내야하는 상황
    • 리스코프 치환 원칙을 어김
    • OCP를 어김 = 다운캐스팅 해야함
      • 프로그램이 굳어서 paper의 자식class(구상체)를 겁나서 못만들게 됨.(코드 수정해야함)
        • Programmer를 구현한 모든 세부개발자들의 코드마다 if instanceof 분기를 수정해줘야함
    • if를 제거해서 외부쪽 클라이언트쪽으로 옮기는게 좋다.
  • 여기서 문제 발생 paper가 다운캐스팅을 시도하고 있다. 그러면 이 클래스는 확장에 막혀있게 된다. 이런 문제를 해결하기 위해서는 코드로서 문제를 해결하기 위한 방법을 모색해야 한다.
    • if는 goto를 일으켜서 런타임, 컴파일에러를 일으키지 않아 그래서 if나 swich를 쓰면 정적타입의 안정성을 잃어버리게 된다.
Director

image-20220206010649959

  • 디렉터는 특정 프로젝트 이름(String)으로 특정 기획서 객체(Paper)들을 소유하기 위해 hashmap에 소유하고 있다.
    • 빈 hashmap에 addProject 메소드로 더한다. (remove나.. edit 등은 일단X)
  • runProject()는 name으로 project의 paper를 꺼내는 데
    • **Paper는 마커인터페이스로 -> 자식구현체Class들로 범주의 여러 종류가 정해져있으며 ** image-20220206100812053
    • paper로 꺼냈다면 -> 구체적으로 어느 종류 사양서(client or serverclient)인지 모른다. image-20220206100750271
      • if instanceof 분기종류마다 하나씩 분기를 만들어줘야하는 수고로움 -> 유지보수시 수정 많음.
      • 만약, 해당종류라고 분기가 되었으면 (해당종류로 다운캐스팅)해야 마커에는 없던 기능들을 쓸 수 있다.
        • ServerClient project = (ServerClient)paper; image-20220206100829725
    • 만약, ServerClient 사양서를 가졌다면
      • FE/BE 각각 프로그래머 변수를 만든 뒤 -> set으로 세팅해준다. (프리랜서 seller개념? 차후 세팅할려면 빈변수->setter)
    • 각각의 개발자들한테, 자신만의 프로그램 만들라고 마커인터페이스를 다운캐스팅한 (ServerClient)project를 넘겨서 만들게 한다.
      • 각각의 개발자들의 완성품이 Program으로 같다
    • deploy해준다.
  • 만약, client프로그램이라면
    • (해당종류로 다운캐스팅)해야 마커에는 없던 기능들을 쓸 수 있다.
      • Client project = (Client)paper;
    • 개발자 1명만 변수 만들고 -> setter로 세팅해주고 -> (자신만의X, 공통적인) 프로그램만들라고 시키고 -> deploy
Error
  1. 추상체인 paper를 받아도, 특정 구상체인 Client paper만 내부분기(if instanceof)로 받아 세팅하던 FrontEnd개발자에게 ServerClient paper인 project를 넘겨봤자, language와 library를 세팅 못하기 때문에 엄한 결과(context에러)가 나온다.

    • Programmer중 FrontEnd 종류가 된 이상, Client로 다운캐스팅된 paper만 받아 처리(lang, lib 세팅)하도록 정의되어있다.
      • FrontEnd image-20220206102029062
    • paper 종류에 따라 project가 가진 필드가 다르며, FE/BE개발자는 Client가 아닌 ServerClient paper만 처리하도록 설계된 상태다.

      • Client

        image-20220206101813803

      • ServerClient

        image-20220206101922975

    • if를 썼기 때문에 -> 컴파일 에러가 안나고 내부에 문제가 숨어있게 된다.
      • 모든 에러가 context에러로 빠져버렸다.
      • if -> OCP원칙 파괴(다운캐스팅)끝나지않고 대부분의 에러가 context에러로 숨어버린다.
        • goto를 써서 runtime에 죽지도 않고, compile에 걸리지도 않는 context에러
        • 여러 case로 사람이 따로 판별해볼수 밖에 없다.
      • if -> 다운캐스팅들이, 바깥에서 context에러를 일으킴.
    • SOLID 원칙 중에서도 설계상에서는 LSP와 OCP를 더 신경써야한다.

      • LSP와 OCP를 지키면, 나머지 3개도 다 지켜진다
      • LSP는 지키기가 너무 힘들다.
        • 심지어 Paper는 마커인터페이스로, 구상체들은 다 자기만의 메소드를 가질텐데, abc -> abcd 확장성LSP가 어렵다고 했지만, 여기서는 구상체들 각각이 0 -> d에 해당하는 경우이므로
        • d의 문제를 해결하도록 습관적으로 연습하자

LSP위반 시행착오

image-20220206104025726

1. LSP위반 지점- 일반적으로 정보없는 추상층Paper에 의해 시작: FrontEnd다운캐스팅>

image-20220206104038160

  • LSP를 위반하는 곳은 빨간네모코드이다. 이것에 의해 다운캐스팅 할 수 밖에 없었다.
    • LSP: 우리는 자식형을 <— 부모형이 대신해도 충분해
      • 부모형이 충분하지 못해서LSP위반 -> if -> 다운캐스팅 -> OCP 위반
        • 부모가 자식에게만 있는 d가 없거나
        • 부모가 아예 메소드가 비어있는 마커인터페이스 등 자식이 확장형일 때
        • 왜 OCP위반(다운캐스팅)했냐? -> 항상 선행되는 LSP위반(부모가 자식을 대체못함)
    • paper(부모)가 충분했으면 = LSP 만족시켰으면 -> 다운캐스팅 할 일이 없는데
      • paper가 paper로서 충분치 않았다.(부모가 자식 대신하는 역할 = LSP 만족X) -> if instanceof -> 다운캐스팅 -> OCP 위반

image-20220206104720198

  • 확장형LSP -> d()의 문제해결은, 6장에서 배운 헐리우드 원칙 = 묻지말고 시켜라이ㄷ다.

    • "얘가 다운캐스팅 하는 이유는, 얘가 추상형(paper형)에 대해 구상 지식(client형의 지식)을 가지려 했기 때문이야"
      • 복잡한 상황은 내가 아닌, 외부로 추상화를 떠밀어야하는데, 그 방법이 헐리우드 원칙
    • 내가 Paper한테 너무 많이 물어봤다 -> 물어보지 말랬는데, 첨부터 다 물어보고 있다.
      • "paper야 너 혹시 Client형이니?"
        • "Client라면 이런 Data들 가지고 있지 않니?"
      • 물어보는 순간부터 OCP위반(다운캐스팅 시작)
      • my) paper 에게 물어보다 = if절 (주체로 들어가) paper야 instanceof Client 이니? + 가지고있으면 변수로 꺼내줄래?
  • 물어보지 않으면 OCP 위반(다운캐스팅) 안할 수 있다. + 시킬때 는 나(this)만 들어가는 것 같지만, 그 외에 같은 레벨의 구상체(BE)도 들어가야하는 공통코드라면 -> 추상체인 (Programmer)로 정의될 것이다.

    • "paper야 <~이니? 맞으면 변수에 꺼내줄래?> 대신 니가 [나에게] 데이터를 set해줘"를 set으로 시킨다. -> paper.setData( this )

    • my) if + 변수로 정보꺼내보며 물어보지말고, setXXX( this )로 나에게 세팅해줘(XXXX(this))set으로 시킨다.

      image-20220206120118325image-20220206120106161

      • 나에게 ( this )
      • 시킨다. setXXXX (this)
      • cf) 시키려면 해줄 사람이 메소드로 기능을 제공해줘야한다 -> 메소드로 만들기
        • 개발자야, paper 던져줄테니, 프로그램 만들어줘
          • Program makeProgram(Paper paper)
    • setData( this ) 의 인자나에게 자리에는 FrontEnd(구상적인)가 오든지, Programmer(추상적인)가 올 것인데, 딱히 관심없다. -> 미뤘다.

      • paper가 뭔가를 하는데 this = 나에게 = 언어 특징상 상위(추상적인) Programmer든, 하위(구체적인) FE/BE이든 누구든지 올 수 있으며, 참고적으로 return은 부모(상위, 추상적인) Programmer로 받아야한다.
      • 인자로 this를 사용한 순간
        • 형(Type)이 무엇인지 물어보던 것도 미뤘다. -> 알아서 인자의 특성상 상위->하위 모든 구상형들 모두 사용가능이므로
        • 원래는 “if 너 무슨형이니?”부터 물어봤었고 + 속성값들도 다 물어봤었는데 image-20220206121240372

image-20220206121439718

  • 물어보지 않고 시켜서 -> paper에게 미룬 것들 정리

    1. paper에게, 무슨형인지 물어보는 것을 -> this로 미룸

    2. paper에게, 무슨 데이터가지고 있는지 물어보고 세팅하는 것 -> setXXX로 미룸

  • 앞으로 더 많은 paper(Programmer인듯?)의 자식class들이 생겨나도, this에 들어갈 수 있기 때문에, FrontEnd 클래스는 더이상 안고쳐도 된다.

2. BackEnd와 같이볼 때 DRY위반으로 추상층에 공통로직올린: Programmer

image-20220206152809213

  • paper로 가기전에, backend를 보자.

    • 수정된 makeProgram() 내부에 있는 makeBackEndProgram()BE만의 특성이다.

      image-20220206152951480

    • 하지만, paper를 이용해서 [물어보지 않고 시키는] .setData( this )FE/BE 공통코드

  • 인터페이스였던 Program을 -> 추상클래스로 upgrade { 템플릿메소드 + 훅 }으로 변경해줘야한다.

    • 두 하위(자식)범주(클래스)에 공통코드 + 각자의 코드 -> 템플릿메소드 + 훅으로 각자코드
    • DRY원칙에 의해 공통코드가 반복되는 것을 막기위해 <로직없는 인터페이스> —> <공통로직을 가진 추상클래스>로 upgrade
      • 왜 우리가 처음엔 인터페이스로 시작했다가 -> 중간에 추상클래스로 바뀌는 이유는 DRY원칙 때문이다.
    • 로직이 없던 인터페이스 image-20220206153600876
    • 공통코드는 템플릿메소드 + 각 구상코드의 고유 코드가 들어가도록 을 가진 추상클래스 image-20220206153517023
      • FE/BE 공통코드 getProgram()
      • 개벌 고유코드를 정의해줄 들어갈 (코드없는 메소드)훅 makeProgram()
  • 공통코드를 중복제거 하기 위해서는 인터페이스 -> 추상클래스 공통템플릿 + 훅으로 바뀌는 경우가 많음을 생각하자.

    • 템플릿 메소드 패턴은 객체지향에서 중복발견시마다 쓰이니, 엄청 자주 쓰인다.
      • 인터페이스로 설계 -> 중복발견해서 템플릿메소드를 가진 추상클래스로 바꾸는 것은 밥먹듯이 하는 일 image-20220206153920292
    • 만약, 공통코드가 아니다. (어떤 프로그래머Class는 paper.setData안한다 ) -> 다시 인터페이스로 바꾸면 된다.
3. 추상층에겐 말고 로 떠넘긴: Paper나에게>물어보고>

image-20220206154500020image-20220206154422232

  • 추상레이어 = 공통로직에서 .setData( 나에게 )를 호출하는 이상은
    • 공통로직을 그대로 가져가는 구상층인 FE에서 .setData( 나에게 )로 , BE도 .setData( 나에게 )로 부를 것이다.
    • 그러려면, setData()의 인자는 추상형(FE/BE의 추상형 -> Programmer)으로 정의해야한다.
      • 하위(FE)를 받으면.. 다른 하위(BE)는 사용못함..
  • programmer도 abc(공통로직)은 거의 없었다. -> 구상층의 공통점은 아주 조금이다.
    • paper도 마찬가지다. 추상층으로서 abc공통로직은 아주 조금이이며 이게 정상이다.
      • 추상층인 인터페이스, 추상클래스가 하는일은 진짜 극 소수이다.
      • 구상층(FrontEnd, BackEnd)의 대부분은 d()코드로 차이점 코드들이 대부분이다.
  • paper도 마커 인터페이스라서, 정보가 없다( 추상클래스라도 공통로직은 조금인데 이건 아예 없다)
    • 다운캐스팅해서 -> 구상층으로 가서 정보를 물었었다.
    • **Programmer쪽에서 OCP를 지키려고, 정보물음의 대상인 Paper에게 시켜서 **
      • Paper내부에서 정보를 받으라고 밀어버렸다.
        • Paper도 정보가 없는 놈이라 -> Paper의 구상층들에게 구현하도록 다시 민다.
4. 시 모든 대상에게 하기 위해 을 줬더니, 정의시 전과하여 발생: Client시켜서>추상층>시켜서>

image-20220206155904296

  • programmer가 물어봐서 받기( if instance + 변수받기)를 paper에게 시켜서 꽂기 떠넘겼는데 paper도 정보가 없는 인터페이스다 -> 자연스럽게 구상층 Client에게 `물어봐서 떠넘긴다.

    • 물어보는 로직자체는 안사라진다 -> Programmer - Paper - Client로 넘어왔다.
    • .setData(Programmer programmer)가 makeProgram(Paper paper)가 일어켰던 context에러를 일으킬 것이다.
      • 이쯤에서 개발자들이 포기한다.
        • 끙끙거리면서 Programmer를 개선시켰으나, 다음날 Paper에서 같은 문제가 또 발생해서 포기함
        • if instanceof 다운캐스팅하면서 물어보기 & 구상층은 절대적으로 n개로 정해졌다고 합리화해버린다.(더이상 안늘어나므로 물어보기 써도된다고 합리화)
  • LSP 해소방법이 시켜서 꽂기라서 시켰더니

    • 꽂을 때도 <다운캐스팅해서 꽂는기능이 있는지 물어보기>의 문제가 생겼다.

      image-20220206162318822

    • 추상층끼리만 대화하고, 구상층끼리는 완전히 격리되서 모르게 설계 = 잘 설계되었음에도 불구하고, **가 계속 떠넘겨진다.**다운>

      image-20220206162429394

      • 추상층이 포함하는 내용(공통로직)이 일반적으로 적어서 -> 추상층에 정보가 적다 -> 다운캐스팅해서 물어볼 수 밖에 없는게 일반적이기 때문이다.
    • 추상층인 discountPolicy와 discountCondition의 메소드 = 공통로직 abc()

      • 구상층도 abc() 공통로직만 가지고 있음 -> 추상층이 구상층을 풀커버 가능(비현실적)
        • 원래는 구상층에 d()가 대부분이어야한다.
      • 여기 예제에서 구상층 ServerClient와 Client의 공통로직은 아예 없다
        • setFE+setBE vs set프로그래머
        • 우리가 알 수 있는 공통점이라고는 == 공통 추상층 == (Programmer를 구현, 상속한 구상층들) 밖에 없다
          • 이게 정상이다.
          • 자식들의 공통점은 없다고 보면 된다.
          • 가장 좋은 인터페이스(공통점을 올려 추상화한 것)은 메소드(공통로직)가 없는 것이라고 이야기 할 정도..
  • 공통점이 없을 게 뻔한데, 여기다 메소드들을 다 정의했다? -> 성급화 추상화 -> 그냥 공통로직(점)을 올린 추상층 인터페이스or추상클래스는 메소드가 없어야 or <메소드 1개이하>여야 정상

    • 2개이상의 메소드가 있는 인터페이스, 추상클래스 -> 성급한 추상화
    • 근데, 성급한 추상화를 안하려고 <공통로직>=메소드가 적게 만들었지만 -> 그로 인해 LSP위반으로 -> 공통로직이 너무 정보가 없어서 다운캐스팅해야하는 상황이 발생
    • 어쩌라는 거지?
  • 물어보는 애를 LSP, OCP를 없애기 위해서 시켰더니 -> 핑퐁으로 주고받는 결과밖에 못얻었다

5. 더 심각한 문제: ServerClient

image-20220206165506135

  • setData( this )로 시켜서 (Programmer programmer)를 꽂을 때,

    • 구상층 ServerClient입장에서 들어오는 programmer가 무조건 2개이상(n개를 대응해야한다)이다.

      • 관계역전 후 시킨 paper쪽에서, 다 받기 위해 progammer를 알게 시켰더니(그림 설계상 위배된 화살표 반대방향)

      image-20220206165844359

    • 관계역전 전에는

      • 구상층 BackEnd입장에서 들어오는 paper가 1개만 들어온다. image-20220206165829395
  • Client와 비교해서는

    • Client는 programmer 한명만 대응하는 setData였지만 image-20220206170304748
    • ServerClient는 여러명의 programmer를 if로 나눠서 대응하여 책임이 훨씬 높아진 상태가 된다. image-20220206170317302
    • 결론적으로, 관계역전 전(programmer가 해결)보다 난이도가 높은 일이 되어버렸다.
      • 1:M 책임(Paper에게 전과하여 다운캐스팅) 보다 1:1 책임(Programmer가 해결)이 더 쉽다
        • 1:M 매칭은 더 일반화된 코드가 필요해서 더 어려운문제가 된다.
        • 다운캐스팅은 안하는게 좋지만, 누가 다운캐스팅을 가져가냐에 따라 난이도가 결정된다.
6. 외부 객체 메세지를 받는 이상, if 분기는 외부context관점의 case들까지 다 처리해야하는데: Client

image-20220206194051454

  • Client 프로젝트는 Paper의 setData()를 받아서

    • set시킬 메소드를 제공하는 FrontEnd 개발자인지 만 확인한 뒤 처리했다.
      • 얘는 지금 BackEnd 개발자는 처리를 아예 안하고 있다.
    • if로 짜지말라고 하는 이유는 -> 우리는 모든 Case를 다 알 수 없다.
      • 매 case를 if분기에 다 넣어야하는데
      • Client 클래스를 짜다보면, Client관점에서 FrontEnd만 챙기는 오류를 범하기 때문
        • 작성중인 Class관점만 생각 -> 다른 case를 안다루어도 된다고 생각하는 오류
    • java를 비롯한 모든 랭기지들은, 함수의 위치에 따라 메소드들이나 context가 다뀌는 문법을 사용한다
      • 특정 위치 (Client class내부)에 함수를 넣음으로써 -> 그 instance.(내부this.)에서 호출할 것이라고 생각하고 짠다.
      • 즉, 보다 일반적인 상황이 아니라, 위치상의 context에 맞게 짜려고 한다.
  • 그러나, 인자에 메세지로 넘어온 객체 (Programmer programmer)로서 외부와 통신하고 있는 이상 -> 외부에 영향 받는 이상

    • client코드에서 호출하는 외부 context까지 다 파악한 상태여야만 내부 if 모든 case를 파악할 수 있다
      • Client class입장에서만 짜지말고, 외부에서 호출할 때 외부 context까지 다 생각해야한다.
        • 측, FrontEnd만 들어온다가 아니라, BackEnd로서 programmer가 들어올 수도 있으며 그 경우에도 처리를 해야한다.
    • 메소드의 생성 이유: 남(외부 클라코드)이 시키도록 서비스 제공하는 것
      • **외부 클라 코드가 이 메소드를 어떻게 쓰는지, 모든 경우의 수를 생각하면서 메소드 짜기 **
        • 형태가 특정 class안에 있다고 해서, 그 class관점에서만 짜면 안된다.
  • 가둬지는 문법체계는 조심해라

    • test case를 최대한 많이 짜낸다.
    • 외부 클라이언트 측면에서 이렇게 많이 부르는구나를 알고나서
    • 메소드를 짠다.
7. 시행착오 교훈
  1. 한쪽 Class(Programmer -> Paper로 문제 넘김)를 LSP, OCP지키도록 바꾼다 하더라도
    • 추상페이퍼까지 이쁜데도 불구하고
  2. 받아준 쪽에서 문제가 옮겨갔을 뿐이지 해결되진 않았다.