@@ -1,7 +0,0 @@
|
||||
객체가 특정한 작업이나 기능을 수행하는 역할을 맡고 있다는 의미
|
||||
|
||||
자신이 가지고 있는 자신을 표현하는 데이터인 프로퍼티(속성)을 변경하거나 사용하는 과정을
|
||||
남(다른 객체)에게 위임하는 것이 아니라 자신의 멤버함수를 통해 스스로 하도록 하는 것을 의미
|
||||
|
||||
예를들면
|
||||
자동차 객체는 자신이 어떻게 움직여야 하는지와 관련된 Move 기능을 남에게 위탁하지 않음.
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"nodes":[
|
||||
{"id":"33d7d950058b35a0","type":"file","file":"3.Resource (자료실)/클린 코드의 기술/단일 책임 원칙.md","x":-333,"y":-166,"width":513,"height":266},
|
||||
{"id":"7642a3e2561f5690","type":"text","text":"SRP를 지키려면 하나의 클래스 파일에 하나의 class(객체)만 선언하고 사용하는게 좋다.\n이렇게 하려면 클래스파일이 많아질 수 밖에 없는데\n별도의 파일들로 분리하는게 SRP를 지키는 자연스러운 해결책이라고 한다.\n - 그럼 클래스파일이 너무 많아질텐데?\n : [[파일 분리]]\n- 패키지(폴더)구조를 어떻게 가져가는게 일반적인가?\n : [[패키지 구조]]","x":-333,"y":200,"width":693,"height":240},
|
||||
{"id":"05b38eceabbfff37","type":"text","text":"클래스마다 메소드가 하나만 있어야 한다는 이야기인가?","x":280,"y":-166,"width":297,"height":80},
|
||||
{"id":"dd42f36c7e4e5b80","type":"text","text":"하나의 책임을 위해 여러개의 메서드가 사용 될 수 있다.\n클래스가 이 메서드들을 통해 수행하는 업무가 하나여야 한다.","x":280,"y":-340,"width":460,"height":120},
|
||||
{"id":"ec406bdee9ca8b36","type":"text","text":"책임이라는 기준이 모호하기 때문에 변경을 기준으로 잡으면 설계에 용이할 수 있다.","x":280,"y":-60,"width":400,"height":93},
|
||||
{"id":"abdc5fc4589917d0","type":"text","text":"단일 책임의 원칙을 지키려다 보면 한계에 봉착하게 된다.\n'결국 누군가는 여러개의 기능을 가지고 있을 수 밖에 없는데?'\n라는 생각에 빠지게 되었음.\n이걸 DI 기능을 제공해주는 framework 사용해서 해결하던가\n애그리게이터 패턴의 객체를 하나 만들던가 하는식으로 해결 할 수 있음.","x":820,"y":-86,"width":580,"height":166},
|
||||
{"id":"b14a217bb0fd0b6a","x":1040,"y":180,"width":520,"height":400,"type":"file","file":"3.Resource (자료실)/클린 코드의 기술/애그리게이터의 주요 역할.md"},
|
||||
{"id":"249ebdc4eafa6e80","x":620,"y":180,"width":400,"height":280,"type":"file","file":"3.Resource (자료실)/클린 코드의 기술/애그리게이터.md"},
|
||||
{"id":"e69cff2fb722aa5e","x":1520,"y":-240,"width":640,"height":360,"type":"text","text":"애그리게이터 활용 예시\n- **사용자 인터페이스(UI)** \n 복잡한 UI 컴포넌트들을 조합하여 상위 UI 컴포넌트를 관리하는 데 애그리게이터를 사용할 수 있습니다. 예를 들어, 여러 개의 버튼, 텍스트 필드, 드롭다운 등을 하나의 큰 UI 컴포넌트로 묶을 수 있습니다.\n \n- **게임 개발** \n 게임에서는 캐릭터, 아이템, 맵 등의 다양한 객체들이 함께 동작하므로, 이를 조합하여 관리하는 애그리게이터가 필요합니다. 예를 들어, `GameEngine`이 여러 게임 객체들을 관리하는 역할을 할 수 있습니다.\n \n- **서비스 관리 시스템** \n 여러 서비스를 하나의 통합된 시스템에서 관리해야 할 때, 각 서비스 객체들을 애그리게이터로 묶어서 상위 시스템에서 관리할 수 있습니다."}
|
||||
],
|
||||
"edges":[
|
||||
{"id":"6030b838f141758b","fromNode":"33d7d950058b35a0","fromSide":"bottom","toNode":"7642a3e2561f5690","toSide":"top"},
|
||||
{"id":"3be70f6875fbc19b","fromNode":"33d7d950058b35a0","fromSide":"right","toNode":"05b38eceabbfff37","toSide":"left"},
|
||||
{"id":"26cbb4e52b3c67bb","fromNode":"05b38eceabbfff37","fromSide":"top","toNode":"dd42f36c7e4e5b80","toSide":"bottom"},
|
||||
{"id":"551424005689dc8d","fromNode":"33d7d950058b35a0","fromSide":"right","toNode":"ec406bdee9ca8b36","toSide":"left"},
|
||||
{"id":"a4d3d983b072903f","fromNode":"05b38eceabbfff37","fromSide":"right","toNode":"abdc5fc4589917d0","toSide":"top"},
|
||||
{"id":"9f0d95e70e7e4eb5","fromNode":"ec406bdee9ca8b36","fromSide":"right","toNode":"abdc5fc4589917d0","toSide":"left"},
|
||||
{"id":"d201db751400f333","fromNode":"abdc5fc4589917d0","fromSide":"bottom","toNode":"249ebdc4eafa6e80","toSide":"top"},
|
||||
{"id":"964cd9d639e29127","fromNode":"abdc5fc4589917d0","fromSide":"bottom","toNode":"b14a217bb0fd0b6a","toSide":"top"},
|
||||
{"id":"d438a973851a5405","fromNode":"abdc5fc4589917d0","fromSide":"right","toNode":"e69cff2fb722aa5e","toSide":"left"}
|
||||
]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
==S==ingle ==R==esponsibility ==P==rinciple -> SRP
|
||||
==클래스는 단 하나의 변경 이유만 가져야 한다.==
|
||||
즉, **하나의 클래스는 하나의 책임([[객체의 책임]])을 가져야 한다**.
|
||||
|
||||
SRP가 함수에도 적용될 수는 있지만 기본적으로 SRP는 클래스의 책임을 다루는 원칙
|
||||
함수는 함수의 단일 책임이라고 부를 수 있다.
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
객체가 다른 객체와 상호작용 할 때, 그 객체의 내부 구조나 구현에 대해 알지 못하도록 하는 원칙
|
||||
|
||||
객체가 자신이 직접적인 책임을 지고 있는 객체와만 상호작용 해야한다. [[객체의 책임]]
|
||||
|
||||
디미터의 법칙을 지키려면 다음의 상호작용만 하도록 해야함.
|
||||
1. 자기 자신과만 상호작용한다.
|
||||
2. (매개변수 등으로) 전달받은 객체하고만 상호작용 한다.
|
||||
3. 반환값이 자신과 직접 연결된 객체가 아니면 그 객체의 메서드를 호출하지 않는다.
|
||||
|
||||
뭔소리냐? GPT에게 물어봤더니
|
||||
|
||||
getDriverName(){ return this.driver.name; } 이렇게 직접 driver의 property 에 접근하지 말고 this.driver.getName(); driver가 제공하는 함수를 통해서만 사용하라는 의미인거야?
|
||||
|
||||
맞습니다! 정확히 그런 의미입니다.
|
||||
|
||||
==디미터의 법칙을 지키려면, `Car` 객체가 `Driver` 객체의 **속성(property)**에 직접 접근하는 것을 피하고, `Driver` 객체가 제공하는 **메서드**를 통해서만 정보를 얻도록 해야 합니다.==
|
||||
|
||||
즉, `this.driver.name`처럼 `Driver` 객체의 **속성에 직접 접근**하는 것이 아니라, `this.driver.getName()`과 같은 **메서드를 통해** 정보를 요청해야 한다는 것입니다. 이렇게 하면 `Car` 객체는 `Driver` 객체의 구현 세부 사항을 알지 못하고, `Driver` 객체가 제공하는 인터페이스만을 사용하게 됩니다.
|
||||
@@ -1,3 +0,0 @@
|
||||
**애그리게이터(Aggregator)**는 **여러 개의 객체나 컴포넌트를 하나로 묶어서 관리하고, 이를 통해 상위 객체의 동작을 쉽게 조정하는 패턴**
|
||||
|
||||
**객체들이 직접적으로 서로 의존하지 않게** 하고, **하나의 객체로 통합**하여 기능을 제공할 수 있게 합니다.
|
||||
@@ -1,11 +0,0 @@
|
||||
1. **여러 객체를 통합하고 조정**
|
||||
|
||||
- 서로 다른 객체들이 개별적으로 동작하는 것이 아니라, 애그리게이터가 이들을 조합하여 전체적인 흐름을 제어합니다.
|
||||
|
||||
2. **객체들의 결합도를 낮추고 관리 용이성 제공**
|
||||
|
||||
- 애그리게이터는 하위 객체들을 **단일 진입점**으로 통합하여 외부에서 각 객체를 따로 조작하는 대신, 하나의 객체만을 조작하면 되므로 관리가 용이합니다.
|
||||
|
||||
3. **하위 객체의 책임을 숨기고, 상위 객체에만 집중**
|
||||
|
||||
- 애그리게이터는 하위 객체들의 **세부 구현**을 숨기고, **상위 객체에 필요한 기능**만 제공합니다.
|
||||
@@ -1,14 +0,0 @@
|
||||
1. 모든 요구 사항에 의문을 제기하라
|
||||
(모든 사람은 종종 틀리기 마련이고 잘못 지시된 일에 시간을 투자하면 안된다.)
|
||||
2. **부품이든 프로세스든 최대한 단순화하라**
|
||||
(이건 다시 넣어야 할 것 같은데? 라는 생각이 들지 않으면 충분히 제거하지 않은 것)
|
||||
(필요하지 않은 모든 요소를 제거해야한다.)
|
||||
(혹시나 하는 마음에 쓸데없는 보험을 들지마라.)
|
||||
3. 항상 단순화하고 최적화하라
|
||||
(단, 정말 꼭 필요한 것들에 대해서만 단순화하고 최적화해라.)
|
||||
(쓸데없는 문제를 해결하고 최적화하는 실수를 하지말자.)
|
||||
4. 개발/생산 사이클을 빠르게 돌려라
|
||||
(단, 앞의 3가지 원칙을 지키면서 달려야한다. 반드시)
|
||||
(밍기적대지말고 열심히 달려라)
|
||||
5. 모든 과정을 자동화하라.
|
||||
(절대 이 순서를 반대로 진행하지마라.)
|
||||
@@ -1,5 +0,0 @@
|
||||
- **[[단일 책임 원칙]](SRP, Single Responsibility Principle)**을 따를 것
|
||||
|
||||
- **자신의 데이터는 스스로 관리할 것 (캡슐화)**
|
||||
|
||||
- **다른 [[객체의 책임]]을 침범하지 않을 것**
|
||||
@@ -1 +0,0 @@
|
||||
[[디미터의 법칙]]
|
||||
@@ -1,19 +0,0 @@
|
||||
[[단일 책임 원칙]]을 지키기 위한 방법 중 가장 자연스럽고 좋은 방법
|
||||
|
||||
하나의 책임만을 가지는 객체를 여러개의 클래스파일들에 분리해서 선언하고 관리하는것을 의미
|
||||
|
||||
![[Pasted image 20250319091803.png]]+
|
||||
### **파일 분리를 하면 얻는 이점**
|
||||
|
||||
1. **가독성 증가**
|
||||
- 한 파일에 여러 책임이 섞여 있으면 관리하기 어려움.
|
||||
- 각 파일에 하나의 책임만 부여하면 **코드를 빠르게 이해할 수 있음**.
|
||||
2. **유지보수 용이**
|
||||
- 기능이 추가/수정될 때 필요한 클래스만 보면 됨.
|
||||
- 특정 기능이 필요할 때 **어느 파일을 수정해야 할지 명확**함.
|
||||
3. **재사용성 증가**
|
||||
- 한 클래스가 한 가지 역할만 하면, **다른 프로젝트에서도 재사용하기 쉬움**.
|
||||
- 예를 들어, `ReportGenerator`만 다른 시스템에서도 쉽게 활용 가능.
|
||||
4. **충돌 방지**
|
||||
- 여러 사람이 개발할 때, **같은 파일을 수정할 확률이 낮아짐**.
|
||||
- 병합(merge) 충돌이 줄어들어 협업이 쉬워짐.
|
||||
@@ -1,93 +0,0 @@
|
||||
Node.js의 일반적인 패키지 구조 설계
|
||||
|
||||
MVC패턴
|
||||
✔ `controllers/` ➝ **HTTP 요청 처리** (Express 라우트에서 직접 연결)
|
||||
✔ `models/` ➝ **데이터베이스 모델** (Mongoose, Sequelize 등 ORM 사용)
|
||||
✔ `services/` ➝ **비즈니스 로직** (컨트롤러에서 서비스 호출)
|
||||
✔ `routes/` ➝ **라우팅 관리** (각 엔드포인트 정의)
|
||||
✔ `middlewares/` ➝ **공통 미들웨어** (인증, 예외 처리, 유효성 검사)
|
||||
✔ `utils/` ➝ **공통 유틸리티 함수**
|
||||
|
||||
Java에서는?
|
||||
- **기능(도메인)별로 분리**
|
||||
- **변경될 가능성이 높은 부분과 낮은 부분을 분리**
|
||||
- **상위 패키지는 안정적이고, 하위 패키지는 유연하게 유지**
|
||||
|
||||
(1) 계층별 패키지 구조 (Layered Architecture)
|
||||
com/example/app/
|
||||
├── controller/ (API, UI 관련 로직)
|
||||
├── service/ (비즈니스 로직)
|
||||
├── repository/ (데이터 접근)
|
||||
├── model/ (엔티티, DTO, VO)
|
||||
├── config/ (설정 관련 클래스)
|
||||
└── exception/ (예외 처리)
|
||||
📌 **각 패키지가 역할별로 분리되어 있어 유지보수가 쉬움**
|
||||
📌 하지만, **기능이 많아지면 서비스 계층이 너무 커질 수 있음**
|
||||
|
||||
|
||||
(2) 기능(도메인)별 패키지 구조 (Domain-Driven Design, DDD 스타일)
|
||||
com/example/app/
|
||||
├── user/
|
||||
│ ├── controller/
|
||||
│ ├── service/
|
||||
│ ├── repository/
|
||||
│ ├── model/
|
||||
│ └── exception/
|
||||
├── order/
|
||||
│ ├── controller/
|
||||
│ ├── service/
|
||||
│ ├── repository/
|
||||
│ ├── model/
|
||||
│ └── exception/
|
||||
└── product/
|
||||
├── controller/
|
||||
├── service/
|
||||
├── repository/
|
||||
├── model/
|
||||
└── exception/
|
||||
📌 **각 기능(user, order, product 등)이 독립적이어서 관리가 쉬움**
|
||||
📌 **각 기능을 모듈화하여 재사용 가능**
|
||||
📌 **대규모 프로젝트에서 효과적** (ex. 마이크로서비스)
|
||||
|
||||
**➡ 장점: 변경이 한 기능에만 영향을 주므로 확장성이 좋음**
|
||||
**➡ 단점: 작은 프로젝트에서는 과도할 수 있음**
|
||||
: 작은 프로젝트도 DDD를 채택하고 패키지 구조를 단순화하면 된다.
|
||||
|
||||
|
||||
**작은 프로젝트**라면, 패키지를 지나치게 분리할 필요 없이 다음과 같이 간단하게 유지할 수도 있습니다.
|
||||
/com.example.simpleproject
|
||||
├── **domain/**
|
||||
│ ├── User.java
|
||||
│ ├── Order.java
|
||||
│ ├── Product.java
|
||||
│ ├── UserRepository.java
|
||||
│ ├── OrderRepository.java
|
||||
│ ├── ProductRepository.java
|
||||
│ └── OrderStatus.java (enum)
|
||||
├── **service/**
|
||||
│ ├── UserService.java
|
||||
│ ├── OrderService.java
|
||||
│ └── ProductService.java
|
||||
├── controller/
|
||||
│ ├── UserController.java
|
||||
│ ├── OrderController.java
|
||||
│ └── ProductController.java
|
||||
├── repository/ => 선택
|
||||
│ ├── JpaUserRepository.java
|
||||
│ ├── JpaOrderRepository.java
|
||||
│ └── JpaProductRepository.java
|
||||
└── MainApplication.java
|
||||
📌 **이 구조의 특징**
|
||||
✔ **도메인 로직(`domain`)과 서비스(`service`)를 나누되, 인프라 부분은 따로 관리하지 않음**
|
||||
✔ **필요하면 `repository` 패키지를 따로 만들어 DB 구현체를 분리**
|
||||
✔ **application 패키지를 없애고 서비스 계층을 단순화**
|
||||
|
||||
👉 **작은 프로젝트라면 위와 같은 구조로도 충분히 유지보수 가능**합니다.
|
||||
![[Pasted image 20250319154830.png]]
|
||||
- **도메인**은 핵심 비즈니스 로직과 모델을 다루고,
|
||||
- **서비스**는 도메인 객체를 활용해 애플리케이션 로직을 처리하며,
|
||||
- **인프라**는 외부 시스템과의 연결 및 구현을 담당합니다.
|
||||
|
||||
infra의 일부로 repository 가 있을 수 있다.
|
||||
infra는 외부와의 상호작용 그 자체를 의미,
|
||||
repository는 외부와의 상호작용 중 데이터베이스(DBMS 혹은 File in/output 등) 관련된 부분을 의미
|
||||
Reference in New Issue
Block a user