호댕의 iOS 개발

[TWL] 21. 11. 08 ~ 21. 11. 12 (프로토콜, 시간 복잡도, 스택 / 힙 영역, SOLID) 본문

Software Engineering/TIL

[TWL] 21. 11. 08 ~ 21. 11. 12 (프로토콜, 시간 복잡도, 스택 / 힙 영역, SOLID)

호르댕댕댕 2021. 11. 13. 11:06

야곰의 피가 되고 살이 되는 잔소리~

# 마스터가 목표가 아니다!

캠프를 진행하면서 마스터하는 것이 목표가 아니다. 뭘 모르는지, 뭘 깊게 공부할 지 알아가는 과정이다.즉, 어떤 방식으로 탐구하면 좋을지 알아가는 과정이 필요하다. (공부의 자세!)

먼저 관심있는 부분에 대해 어떻게 공부하면 좋을지 깊게 공부해보고, 다른 사람들이 공유한 것을 살펴보는 것도 좋다.(개발자 Conference나 Semina가 많은 이유)

모든 것을 익히지 못한다고 부담을 너무 갖진 말자. 다른 사람들이 공부한 것을 공유받는 것도 적극 활용하자!

 

학습한 내용

# 프로토콜

프로토콜은 타입이 갖출 기능들의 청사진이다. 즉, 하나의 기능 요구사항이다.(여기서 프로토콜은 상속한다고 표현하지 않고 '채택한다’라는 표현을 사용한다.)

그렇다면 언제 프로토콜을 사용할 수 있을까?

열거형의 경우 케이스를 추가한다면 side effect로 이를 활용한 다른 Switch 구문같은 곳에서 컴파일 오류가 발생한다. (열거형의 모든 케이스를 exhaustive하게 사용하지 않았기 때문)-> 따라서 열거형은 정말 바뀔 일이 없는 경우 사용해야 한다. (예를 들어 요일, 성별 같은 곳)

이때 프로토콜을 사용하면 이런 컴파일 오류 없이 사용할 수 있다.

 

프로토콜은 타입으로 사용할 수 있다.프로토콜을 준수할 경우 어떤 것이든 들어올 수 있다. 하지만 프로토콜을 준수하지 않는다면 들어올 수 없다.이런 특성을 활용해 프로토콜을 매개변수에 사용한다면 받고 싶은 매개변수만 받을 수도 있다.

프로토콜은 하나의 명찰이며, 프로토콜을 준수하는 구조체를 추가하더라도 다른 코드에는 전혀 영향을 주지 않는다.

 

프로토콜에서 var는 변수의 의미보단 프로퍼티라는 의미이다.

  • get set (읽기쓰기) : 변수(=상수로 구현 불가), 읽기쓰기 변수로 구현함 (=가변 저장 프로퍼티 또는 getter/setter가 둘다 있는 가변 연산 프로퍼티)
  • get (읽기) : 상수와 유사, 읽기전용 변수로 구현함

델리게이션은 아직 정확히 언제 사용해야 하는지 이해를 하지 못했다…

 

# reverse() VS reversed()

메서드의 이름만 봐도 비슷해 보이는 이 둘은 배열을 뒤집는 방법이 다르기 때문에 시간 복잡도에서도 차이를 가진다. 

어떤 차이가 있는지는 따로 블로그 글을 작성하도록 하겠다. 

 

🤷🏻‍♂️ 스택 영역에 올라가는 것과 힙 영역에 올라가는 것을 어떻게 구분할 수 있을까?

코드를 실행하는 시점에서 컴퓨터가 메모리를 얼마나 쓸지 모른다면 메모리를 준비할 수 없고 이 땐 heap 영역에 올라가게 된다.여기서 얼마나 쓸지 모른다면 이를 처리하는데 얼마나 걸릴지도 모른다. 즉, 일단 돌려봐야 안다는 것이다. 따라서 이를 직접 조정해줄 필요가 있다.(클래스에서 직접 deinit을 해주는 이유이다)

반대로 코드를 실행하는 시점에서 컴퓨터가 메모리를 얼마나 사용할 지 파악이 가능하다면 stack 영역에 올라가게 된다.

 

# SOLID

1. 단일 책임의 원칙 (SRP)

하나의 클래스는 한 가지의 책임만 가져야 한다. 즉, 코드가 높은 응집도를 가지고 있어야 한다.

만약 코드가 낮은 응집도를 가지고 있다면 하나를 수정할 때 다양한 곳에서 수정을 해야 하며, 또 하나의 타입에 대해 수정할 때 수정하지 않는 코드도 발생한다. Object를 나눠놨는데 특정 스펙의 변경이 있을 때 코드 전반을 수정해야 한다면 책임이 분산되어 있는 것이다.

(여기서 변경이란 가위 바위 보 게임의 경우 승패를 가르는 로직 변경이 될 수 있다)

여러 객체를 책임지게 되면 문제가 발생할 여지가 많아지기 때문에 Fat Class를 경계해야 한다.

2. 개방폐쇄 원칙 (OCP)

확장을 할 때에는 최대한 기존의 코드를 건드리지 않고 확장해야 한다.만약 기존의 코드를 수정하더라도 연쇄적으로 수정하지 않도록 해야 한다.

기존 코드에 대해 수정이 없으니, 재검증의 필요 없이 소프트웨어를 키워나갈 수 있다.

3. 리스코프 치환 원칙 (LSP)

자식 클래스는 부모 클래스의 역할을 완벽하게 수행할 수 있어야 한다.

4. 의존성 역전의 원칙 (DIP)

상위 수준의 모듈은 하위 수준의 모듈에 의존해선 안된다.

5. 인터페이스 분리 법칙 (ISP)

클라이언트가 불필요하게 자신이 사용하지 않는 인터페이스(ex: 프로토콜)를 의존하지 않도록 해야 한다.

인터페이스가 크면 상속받은 클래스에서 불필요한 빌드가 생길 수 있다. 따라서 인터페이스는 작게 분리해야 하며 클라이언트가 다양한 인터페이스에서 선택할 수 있도록 해야 한다.

 

사실 아직 코드에서 SOLID를 어떻게 지켜야할지 잘 감이 오지 않는다. 프로젝트를 진행하며 최소 하나씩 지켜보도록 노력해야겠다. 

 

 

Comments