일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 오브젝트
- 프로세스 스케줄링
- COLOR
- Algorithm
- 앨런
- @state
- 비동기
- 알고리즘
- SwiftUI
- 인프런
- 가상 메모리
- forEach
- decode
- IOS
- core data
- async
- 데드락
- 100 days of SwiftUI
- UserDefaults
- 동시성
- scrollview
- deadlock
- struct
- 동기화
- 운영체제
- 상호배제
- Codable
- Linked List
- Swift
- Apple Developer Academy
- Today
- Total
기어가더라도 제대로
0. 조영호님 객체 지향 특강 본문
- 객체지향이 어려운 것은 이론을 만들기다.
- 여러 사람이 납득할 만한 이론을 만드는 것이 어렵다.
- ex) 왜 그 객체가 저런 일을해?
- ex) 왜 그 속성을 가져가?
- 이런 질문들에 동의할 만한 답을 내는 것이 객체지향
- 속성은 뒤로 미루고 행동만 고려하자.
영화관 예제
예매 생성에 필요한 정보의 전문가에게 할당
- Screening 에 상영에 필요한 정보를 할당
- 상영정보를 알고 있다 -> Movie
- 예매 정보를 생성한다. -> Customer
- Movie
- 영화 정보를 알고 있다. -> Discount Policy
- 가격을 계산한다.
- Discount Policy
- 할인 정책을 알고 있다. -> Discount
- 할인된 가격을 계산한다. -> Condition
- Discount Condition
- 할인 조건을 알고 있다.
- 할인 여부를 판단한다.
객체지향의 사실과 오해
- 객체 지향에서는 클래스가 작을 수록 좋다.
- SRP 를 만족시키기 위해 작은 클래스들이 많다. (good)
- 일단 절차지향으로 짜고, 찢어놓기 위해 리팩토링을 한다. (good)
- 객체 지향에서의 책임과, 단일 책임 원칙을 이야기할 때의 책임은 다르다.
- 단일 책임 원칙 == 단일 병용의 원칙
- 극단적으로 클래스에서 하나의 메서드만 운용을 해야한다고 생각해서는 안된다.
- 병용 -> use in combination, 함께 사용
- "이 클래스가 병용되어야 하는 이유는 하나여야 한다." 라고 말하는 것이 단일 책임 원칙
- 단일 책임 원칙 == 단일 병용의 원칙
- 심플하게, 여러사람이 서로 다른 이유로 같은 클래스를 수정하여 커밋하고 있다?
- SRP 위반! 찢으세요.
절차지향은 데이터는 이미 정해져있다.
객체 지향에서의 어플리케이션는 이런 말을 할지 모른다.
> 데이터는 잘 모르겠다.
> 어플리케이션이 무언가를 해야하는데, 이 일을 하는데 적합한 객체가 누굴까?
책임 주도 설계
객체지향이 캡슐화되는 이유
해줘 ~ 했을 때 변화가 연속적이 되면 캡슐화가 깨진 것이다.
- 예를 들어 할인정책의 메서드가 변경되면
- 할인 정책을 명령을 내리는 곳에서 이번 할인 정책은 어떤 타입이니까
- 이렇게 저렇게 처리해야지 하면서 명령 내리는 곳의 코드가 변경되면
- 이는 캡슐화가 깨진 것이다.
- 명령을 내리는 클래스에서 "나는 잘 모르겠고 ~, 너가 해줘 ~" 이것이 캡슐화다.
- 다시 말하면 객체는 메시지만 던지고, 그 뒤의 세세한 작업에는 관여하지 않는다.
응집도, 결합도, SRP
- 결합도
- 높다 - a 가 10 번 변경되면 b 가 8 번 변경 돼
- 낮다 - a 가 10 번 변경되면 b 가 2 번 변경 돼
- 응집도
- 높다 - a 에서 무언가 변경할 때 여기서만 변경하고 있다.
- 낮다 - a 에서 변경하는데 b, c, d 도 변경이 된다.
긍정적인것은 결합도가 낮고, 응집도가 높은 코드이다. 또한 SRP 를 만족하는 코드는 응집도가 높은 코드이다.
객체지향 구현
- `DiscountPolicy` 는 `Screening` 을 받아서 각각의 할인 조건들을 판단한다.
- 이 때, IF 문이 없다. 컨디션에 따라서,
- `DiscountCondition(추상)`
- `SequenceCondition(구체)`, `PeriodCondition(구체)`
- 위 타입들이 인자로 넘겨받은 `Screening` 을 판단해서 Boolean 값을 넘겨줄 뿐이다.
- DiscountPolicy 는 이래라 저래라 하지 않는다.
- 이것이 다형성이다.
- 만약 두 구체 타입 중에서 코드의 변경이 일어나게 된다면,
- DiscountPolicy 는 그 변화를 감지하고 자기 코드를 수정할 확률이 낮을 것이다.
- 다형성이 좋은 이유는 변경할 때, 특정 클래스만 고치면 되기 때문이다.
- 다른말로 캡슐화가 가능하기 때문이다.
절차지향과 객체 지향 비교
- 절차 지향적 코드
- 객체 지향적 코드
절차지향은 직관적이고 런타임에서 이러이러하게 동작하겠구나 예측이 쉽고, 계산과 순서가 동일하여 쉬운데 반해 객체지향 코드는 그렇지 않다.
런타임에서 실제 연결된 객체가 무엇인지에 따라 계산 로직이 달라진다. 선언한 코드와 실제 실행되는 코드가 런타임에 달라서 객체지향이 읽기 어려운 것이다.
절차지향의 경우엔 코드를 변경할 때 단점이 있다. 이 코드가 어디서 변경될지를 계속 찾아야하고, 구조화가 되어있지 않기 때문에 머리속에 잘 기억이 남지 않는다.
객체지향의 장점은 명사다. "순번조건을 고치고 싶어" -> "`SequenceCondition`" 을 고치면 되겠다. 어디에 있을 거같은지가 명확하다.
아키텍처 패턴에서 도메인 모델
- 모델
- 필요한 정보만 가지고 유용하게 추상화
- 도메인
- 도메인 자체를 우리에게 필요한 정보만 가지고 추상화
- 글이 될 수도, 다이어그램이 될 수도 있다.
- 도메인 모델 패턴 ? -> 객체지향으로 짰다는 이야기다.
선택의 기로에서 객체지향을 선택하는 이유를 대보기
어떤 코드를 짤 때 절차지향으로 짤 것인가? 객체지향으로 짤 것인가?
어느 특정 하나가 꼭 나쁜것은 아니다. 예를 들어 데이터를 가져와서 화면에 뿌려주는 작업을 한다고 했을 때, 객체지향적으로 짜지 않아도 된다. 절차지향적으로 하는 것이 어느 땐 더 나은 답이 되기도 한다.
어느 경우에 객체지향을 사용할 것인가?
설계는 변경의 관점에서 이유가 있어야 한다.
- 이 말은 "꼭 유연해야한다" 를 뜻할까
- 꼭 프로토콜을 선언하고 구체 타입을 만들어야 변경하기 쉬운 코드일까?
- 어떤 경우엔 알아보기 쉬운 코드가 변경하기 좋은 코드이다.
- 다른 경우엔 인터페이스 쓰고, 다형성 쓰고 하는 것이 더 변경하기 쉬울 수 있다.
만약 위의 코드에서 "중복 할인 정책"을 도입한다면..?
- 제일 나쁜 코드
- 오늘 단일의 할인 정책을 사용했는데, 내일 수정 요구사항이 들어올거 같으니까 미리 대비를 해놓자.
- 코드가 복잡해지기만 함
- 다른 동료들이 코드를 이해하기 어려움
- 그대로 예측이 불가함
- 오늘 단일의 할인 정책을 사용했는데, 내일 수정 요구사항이 들어올거 같으니까 미리 대비를 해놓자.
- 절차적으로 짜놓았다고 하면?
- 정책을 담당하는 코드(개념)가 알고리즘에 숨어있어서 엄청 찾아들어가야함.
- 대체 내가 뭐하고 있는 거지란 생각이 듬
- 어찌저찌 찾아서 고치면 뭐가 나쁠까?
- 기존코드를 수정해야 한다는 두려움
- if 문 하나 넣는게 다른 버그의 잠재적인 가능성이 올라간다.
- 중복할인 이라는 개념이 없다.
- 그저 알고리즘으로 나와있다.
- 한줄 한줄 읽고 해석해봐야 알 수 있다.
- 기존코드를 수정해야 한다는 두려움
- 객체 지향으로 짜놓았다면?
- 기존 코드를 수정하지 않고 새로운 클래스를 추가
- 기존 코드를 수정하면서 생길 버그의 발생 기회를 차단
할인 정책의 개수가 변경되더라도, Movie 는 알 필요 없다. Fee 만 받게 된다.
개념을 명시적으로 표현
중복할인의 로직이 개념적으로 나타나게 되었다.
Open-Closed Principle(개방 폐쇄 원칙)
- 현재의 구조는 시스템을 확장하는 데는 열려있다.
- 단일 할인 정책 -> 중복 할인 정책
- 그러나 기존 코드를 수정하는데에는 닫혀 있다.
- 이것이 OCP, 이제 다형성을 곁들인..
도메인 모델이 적합할 때
도메인 모델은 복잡성을 알고리즘에서 분리하고 객체 간의 관계로 만들 수 있다. 유효성 검사, 계산, 파생 등이 포함된 복잡하고 끊임없이 변하는 비지니스 규칙을 구현해야 한다면 객체 모델을 사용해 비지니스 규칙을 처리하는 것이 현명하다.
- Martin Fowler -
대부분의 비지니스 로직은 매우 빨리 바뀐다. 조회 하는 기능은 절차지향적으로 짜고,
객체를 요청받아서 객체를 수정해야하는 경우는 도메인 모델(객체지향적)로 짜세요)
요구사항이 어떻게 변경될지 모른다면
비지니스는 무언가 잘되면 이것도 넣고 저것도 넣는다.
다시 말해 변경사항이 계획적이지 않다. 어떻게 수정이 될지 모른다는 말이다.
또, 트래픽은 처음엔 완만하게 곡선을 그리다가 어느 순간 퀀텀 점프를 한다. 이 때 장애 처리가 관건이다.
그렇기에 처음에 짤 때 심플하게 짜야한다. 미리 예측한대로 될 리가 없다.
변경이 발생할 때마다 리팩토링을 해야한다.(+ 단위테스트도 필수)