Skip to content

2.3 소프트웨어 설계 원칙과 실천 방법 #1474

@jongfeel

Description

@jongfeel

2.3 소프트웨어 설계 원칙과 실천 방법

2.3.1 설계 원칙

업계의 훌륭한 선구자들이 발견한 설계 원칙을 활용하는 것이 가장 효과적인 방법입니다.
여기서 말하는 설계 원칙이란 소프트웨어를 설계할 때 일반적으로 지켜야 할 지침을 뜻합니다.

2.3.2 SOLID 원칙

SOLID 원칙은 로버트 C. 마틴이 2000년에 발표한 논문 에서 정리한 객체 지향 설계 원칙의 머릿글자를 조합해 만들어졌습니다.

단일 책임 원칙(SRP)

클래스를 변경하는 이유는 단 하나뿐이어야 한다.

단일 책임 원칙(SRP)은 클래스가 오직 하나의 명확한 역할(책임)을 가져야 한다는 원칙입니다.

중요한 것은 클래스를 사용하는 클라이언트(다른 클래스)의 관점에서 설계를 고려해야 한다는 점입니다.

SRP 정의에서 ‘클래스를 변경하는 이유’는 해당 클래스가 사용되는 유스케이스나 관련된 사용자 actor의 관점에서 생각하면 명확해집니다.

개방-폐쇄 원칙(OCP)

소프트웨어의 구성 요소(클래스, 모듈, 함수 등)는 확장에는 개방(Open)되어 있고, 수정에는 폐쇄(Closed)되어 있어야 한다.

개방-폐쇄 원칙(OCP)은 확장성과 관련이 깊으며, 기존 코드를 수정하지 않고 도(폐쇄), 새로운 동작을 추가하여 확장할 수 있도록(개방) 설계하는 데 활용되는 원칙입니다.

OCP의 핵심은 수정 과정을 완전히 없애는 것이 아니라 변경이 적은 안정 적인 코드와 변경이 잦은 불안정한 코드를 분리하는 데 있다는 점에 주목할 필요가 있습니다.
안정적인 코드를 보호하기 위해서는 불안정하고 구체적인 구현(특정 클래스나 메서드 같은)에 직접 의존하기보다 이들을 일반화한 추상적인 개념에 의존하는 방식으로 설계하는 것이 좋습니다.

리스코프 치환 원칙(LSP)

파생형은 기본형을 대체할 수 있어야 한다.

리스코프 치환 원칙(LSP)은 기본형(부모 클래스)을 사용하여 작성된 모든 프로 그램이 프로그램의 동작을 변경하지 않고도 기본형을 파생형(자식 클래스)으로 치환 가능해야 한다는 원칙입니다.

LSP를 준수하고 기본형과 파생형을 올바르게 다루려면 애플리케이션 내에서 이들이 올바르게 작동하도록 보장하는 조건(사전, 사후, 불변)을 명확히 정의할 필요가 있습니다.

인터페이스 분리 원칙(ISP)

사용하지 않는 메서드에 대한 의존을 클라이언트에게 강요해서는 안 된다.

인터페이스 분리 원칙(ISP)은 하나의 큰 인터페이스를 각 클라이언트가 실제로 필요로 하는 기능만 담아 더 작고 명확한 인터페이스들로 분리하자는 설계 원칙 입니다.

인터페이스 분리 원칙(ISP)은 처음에 다루었던 단일 책임 원칙(SRP)과 밀접한 연관이 있습니다.

의존성 역전 원칙(DIP)

a. 상위 모듈은 하위 모듈에 의존해서는 안 된다. 두 모듈 모두 ‘추상’에 의존해야 한다.
b. ‘추상’은 구현의 세부 사항에 의존해서는 안 된다. 구현의 세부 사항이 ‘추상’에 의존해야 한다.

의존성 역전 원칙(DIP)은 SOLID 원칙 중에서도 다른 네 가지보다 더 높은 추상 레벨에서 이해해야 하는 원칙입니다.
컴포넌트나 모듈을 분할할 때 그들 사이의 의존 관계를 어떻게 설정할지, 즉 관계 구조 자체를 설계 대상으로 다루기 때문입니다.

2.3.3 실천 방법

데이빗 스콧 번스타인이 집필한 『Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software』 (Pragmatic Bookshelf, 2015) 책에서는 설계 원칙을 준수하며 코드 품질을 개선하기 위해 제시된 실천 방법을 따르기를 권장합니다.

  • 대부분의 경우에 가치가 있는 것
  • 배우기 쉽고, 가르치기도 쉬운 것
  • 복잡한 사고 과정 없이도 실행할 수 있을 만큼 단순한 것

클린 코드

클린(CLEAN) 코드는 각 글자가 나타내는 다섯 가지 코드 품질 기준을 충족함으로써 소프트웨어의 내부 품질을 높이는 것을 목표로 하는 실천 방법입니다.

  • Cohesive (응집성)
  • Loosely Coupled (느슨한 결합)
  • Encapsulated (캡슐화)
  • Assertive (단정적)
  • Nonredundant (비중복)

2.3.4 기타 주요 사항

두 종류의 로직

소프트웨어의 동작을 구성하는 코드는 크게 핵심 로직과 프로세스 로직 두 가지로 나눌 수 있습니다.

업무에 대한 지식과 규칙을 직접적으로 담고 있는 코드가 핵심 로직 입니다.
이는 비즈니스 로직 중에서도 도메인 로직domain logic 이라고 불립니다.

일련의 업무 처리 절차를 나타내는 것은 프로세스 로직입니다.
이는 비즈니스 로직 중에서도 애플리케이션 서비스 로직 application service logic 이라고 불리며, 여러 도메인 객체 간 동작을 적절히 조율하는 조정자 역할을 합니다.

핵심 로직과 프로세스 로직의 역할을 명확히 분리하여 설계하면 코드의 가독성이 향상됩니다.

프랙탈 구조

하나의 책임을 지는 메소드 - 클래스 - 컴포넌트 - 모듈 - 아키텍처 레벨로 올라가도 핵심 로직과 프로세스가 응집되어 있는 구조로 추상화 계층이 만들어집니다.
이 구조가 프랙탈 구조입니다.

SOLID와 같은 클래스 수준 설계 원칙이 상위 추상화 레벨에서도 확장 가능 하다는 점을 보여줍니다.
이를 위해서는 각 설계 원칙의 표면적인 실천 방법을 넘어, 그 본질을 이해하고 이를 일반화하여 사고할 수 있는 능력이 중요합니다.

Metadata

Metadata

Assignees

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions