Slide 1

Slide 1 text

아직도 SOLID 를 ‘글’ 로만 알고 계신가요? Korea Android 심지훈 super.init(version=6)

Slide 2

Slide 2 text

󰞴󰠁 SOLID 가 무엇인가요 ? 로버트 C. 마틴이 명명한 객체 지향 프로그래밍 및 설계의 다섯 가지 기본 원칙 시간이 지나도 유지 보수와 확장이 쉬운 시스템을 만들고자 할 때 이 원칙들을 함께 적용할 수 있다. 간단한 로또 판매 시스템(콘솔 입,출력)을 구현하고, 새로운 요구사항을 추가시키면서 리팩토링하며 SOLID 원칙을 하나하나 적용해보기. 󰞴󰠁 너무 암기해 온 느낌이 나네요..

Slide 3

Slide 3 text

로또 판매 시스템(콘솔, 안드로이드 )

Slide 4

Slide 4 text

SRP(Single Responsibility Principle: 단일 책임 원칙) A module should be responsible to one, and only one, actor." -Clean architecture : a craftsman's guide to software structure and design. Martin, Robert C. (2018). ● 모듈은 오직 하나의 책임만을 가져야 한다. ● 모듈은 변경해야 하는 이유가 단 하나여야 한다. 참고할 만한 GRASP 패턴 ● 정보 전문가(Information Expert) 패턴: 책임을 객체에 할당하는 기본 원리: - 일을 수행하는 데 필요한 정보를 갖고 있는 클래스에게 책임을 할당.

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

OCP(Open-Closed Principle: 개방-폐쇄 원칙) Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification - Meyer, Bertrand (1988). Object-Oriented Software Construction ● 소프트웨어 엔티티는 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다. ● 새로운 기능이나 동작을 추가할 때 기존 코드를 수정하지 않고 확장할 수 있어야 한다.

Slide 7

Slide 7 text

새로운 로또 판매자 유형이 등장하면, 또 다시 LottoSeller 를 수정해야 한다. 수정에 닫혀 있지 않다!

Slide 8

Slide 8 text

수정에 닫혀 있고 확장에 열려 있다

Slide 9

Slide 9 text

● B 클래스가 A 클래스의 하위 클래스라면, ● A의 객체가 필요한 곳에서 B의 객체를 사용할 수 있어야 한다. ● 하위 클래스는 상위 클래스의 계약(Contract)을 위반해서는 안 된다. ● 상위 타입을 하위 타입으로 치환할 때, 프로그램이 정상적으로 동작해야 한다. LSP(Liskov Substitution Principle:리스코프 치환 원칙) If S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program. - Barbara Liskov in a 1987 conference keynote address

Slide 10

Slide 10 text

정사각형 (Square)에 대해서 직사각형 (Rectangle) 타입으로 메서드 호출 시 실패!

Slide 11

Slide 11 text

LSP 위반: 뭐가 문제일까? Square is a Rectangle ⭕ Rectangle 을 사용하는 모든 곳에서 Square 로 대체가 가능하다. ❌ ● is-a 관계가 성립하는지 행동(Behavior)로 판단해야 함. ● 직사각형과 정사각형은 행동이 다르다. → 상속이 아니라 인터페이스 또는 조합(Composition) 사용 ● 정사각형을 직사각형의 하위 클래스로 만들지 않고 별도의 개념으로 분리해야 한다!

Slide 12

Slide 12 text

ISP(Interface Segregation Principle: 인터페이스 분리 원칙) No code should be forced to depend on methods it does not use. - Agile Software Development: Principles, Patterns, and Practices Martin, Robert (2002). ● 인터페이스는 작고 명확하게, 하나의 책임에 집중하여 설계해야 한다. ● 하나의 인터페이스가 너무 많은 기능을 포함하면, 이를 구현하는 클래스는 필요하지 않은 기능도 구현해야 한다. ● 클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

● High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces). ● Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions. - Agile Software Development, Principles, Patterns, and Practices Martin, Robert C. (2003). DIP(Dependency Inversion Principle: 의존성 역전 원칙)

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

토의 Korea Android super.init(version=6)

Slide 18

Slide 18 text

● 책임의 기준 판단은 어떻게 하나요? 책임의 기준은 비즈니스와 기획이 어떻게 변경될지에 달려있습니다. 일반화하자면, 변경의 이유가 단 하나일 때 하나의 책임이라고 볼 수 있습니다. Side Note: 어떤 모듈의 네이밍을 바꾸는 것만으로도 간단히 책임의 기준 판단 문제를 해결하는 경우도 많습니다. ● 컴포즈로 TextField 컴포넌트를 만들 때 입력된 문자열 State Hoisting 을 뷰모델까지 하는 게 좋을까요? 뷰모델까지 Hoisting 하는 것을 기본으로 채택할 것이다. 추후에 생기는 요구사항 변경에 대처하기가 좋았고, 사용자 인수 테스트를 작성하기에도 편리해집니다. 테스트 가능성의 관점에서 코드를 설계하고 리팩토링하면 자연히 SOLID 가 지켜지는 경우가 많습니다. 안드로이드 개발에는 어떻게 SOLID 를 잘 적용할 수 있을까요?

Slide 19

Slide 19 text

SOLID 원칙은 OOP 에만 적용할 수 있는 것인가요? SOLID 가 OOP 개념에서 비롯된 원칙이지만 OOP 에만 적용할 수 있는 것은 아닙니다. Jetpack Compose(함수형 프로그래밍에서 기초한 선언적 UI)에도 SOLID 원칙을 적용할 수 있습니다. State Hoisting 도 DI 와 비슷한 점이 있습니다. DI 를 모든 곳에서 적용하는 것이 오히려 코드를 나쁘게 만들 수 있는 것처럼, State Hoisting 도 모든 곳에 적용하는 것도 그렇습니다. 예를 들어 메뉴 팝업이 열린 상태를 뷰모델까지 State Hoisting 할 필요가 없을 수도 있습니다.

Slide 20

Slide 20 text

● MVC -> MVP View 와 Controller 의 강한 결합, View(Activity, Fragment) 가 로직을 너무 많이 가짐 => SRP : Controller의 역할을 Presenter로 대체하여 View는 UI 업데이트만 담당하고, Presenter는 로직 처리만 담당 => OCP : View의 변화가 있어도 Presenter 내부 로직을 변경하지 않고 새로운 Presenter를 추가하여 확장 가능 ● MVP -> MVVM Presenter가 너무 많은 역할을 함, View와 Presenter 간의 강한 의존성 => SRP: ViewModel을 도입하여 Presenter가 담당하던 데이터 가공과 UI 로직을 분리 => OCP: Presenter 가 View 의 추상화를 참조하는 대신, ViewModel은 View 에 대한 참조가 없음. ● MVVM -> MVI 이전 트렌드의 변화만큼 확실하게 이야기하기 힘든 것 같습니다. 디자인 아키텍처 패턴은 꼭 SOLID 원칙을 지키기 위해 변화하였다기 보다는, 다른 원인이 작용하는 경우도 있다고 생각합니다. 아키텍처 패턴의 변화에서 SOLID 원칙이 어떻게 적용되었나요 ?

Slide 21

Slide 21 text

SOLID 를 꼭 지켜야만 좋은 프로그래밍일까요 ? ● 오른쪽은 컴포즈로 버튼 UI 를 만드는 상황입니다 . 새로운 버튼 타입이 추가될 때 OCP를 준수한다면 기존 코드를 복사, 붙여넣기 후 수정해야 한다. OCP 를 준수하지 않는다면 기존 코드를 수정하면 됩니다. 이런 경우에 OCP 를 준수하는 것이 항상 옳을까요 ? 빠르게 작은 MVP 를 개발해나가는 상황에서 SOLID 를 준수하지 않는 것이 오히려 상황에 더 좋은 경우도 있습니다. ● DI 는 DIP 의 좋은 수단입니다 . 그렇다면 DI 는 만능일까요 ? DI 를 적용할 수 있는 모든 곳에서 적용하면 코드가 오히려 이상해질 수 있습니다. 어떠한 객체의 책임에 대한 정보를 외부에서 주입하도록 하는 것이 좋을 때도 있지만, 오히려 객체 스스로 직접 가지고 있는 것이 좋을 때도 있습니다. 예를 들어 로또 판매자의 휴식 행동에 대한 정보를 외부에서 주입하는 것보다 객체 스스로만 알고 있는 것이 바람직할 수 있습니다. 또한 모든 곳에 DI 를 적용하는 것은 코드 전체의 복잡성을 너무 증가시킬 수도 있습니다. SOLID 는 좋은 프로그래밍을 위한 수단일 뿐, 목적이 아닙니다.

Slide 22

Slide 22 text

발표자 마무리 정리 Korea Android super.init(version=6)

Slide 23

Slide 23 text

발표에서 간단한 요구사항에서 점진적으로 SOLID 원칙을 적용했습니다. 사실, 각 원칙마다 독립적으로 적용된 것은 아니었습니다. DIP 를 적용하면 ISP 가 자연스럽게 따라오고, OCP 를 고려하면 SRP 도 보장되는 경우가 많습니다. SOLID 는 단순한 규칙의 나열이 아닙니다. 유연한 설계, 테스트 가능한 구조, 가독성이 좋은 코드를 위한 수단이며 각 원칙은 유기적인 관계를 가집니다. SOLID 원칙, 단순한 규칙이 아니라 유연한 설계를 위한 수단

Slide 24

Slide 24 text

“내 코드가 SOLID 원칙을 따르는가?” 가 중요한 것이 아닙니다. “내 코드가 새로운 요구사항에 쉽게 대처할 수 있는가?” 가 중요합니다 . 변하지 않는 사실은 계속해서 변화할 것이라는 사실 뿐입니다. 아키텍처, 디자인 패턴, SOLID, 심지어 객체지향, 함수형 프로그램 또한 모두 변화를 수용하기 위한 도구일 뿐입니다. 기술과 요구사항은 계속해서 변화하고, 아키텍처도 이에 맞춰 변화하고 진화합니다. 패턴과 원칙을 따르는 것도 좋지만, 발견하고 만들어 나가는 것은 어떨까요? 중요한 것은?