|
| 1 | +--- |
| 2 | +title: Slice groups |
| 3 | +sidebar: |
| 4 | + order: 3 |
| 5 | +--- |
| 6 | + |
| 7 | +import { FileTree } from '@astrojs/starlight/components'; |
| 8 | + |
| 9 | +Slice group은 관련된 slice를 보기 쉽게 묶어 두는 폴더입니다. |
| 10 | +FSD의 필수 요소는 아니며, slice 수가 많아져 탐색이 어려워질 때 선택적으로 도입할 수 있습니다. |
| 11 | + |
| 12 | +이 문서는 slice group이 무엇인지, 어떤 문제를 해결하는지, 언제 도입할지, 적용할 때 어떤 규칙을 지켜야 하는지를 설명합니다. |
| 13 | + |
| 14 | +> Slice group은 structural grouping, slice grouping 등으로도 불립니다. 이 문서에서는 **slice group**이라고 합니다. |
| 15 | +
|
| 16 | +## Slice group이란 |
| 17 | + |
| 18 | +Slice group은 같은 layer 안에서 관련 slice를 묶는 폴더입니다. |
| 19 | +slice group 자체는 slice가 아니며, 자체 segment나 public API를 갖지 않습니다. |
| 20 | + |
| 21 | +즉, slice group은 FSD의 의존성 규칙을 바꾸지 않고, 폴더 구조를 더 찾기 쉽고 읽기 쉽게 만들기 위한 방법입니다. |
| 22 | + |
| 23 | +### 핵심 규칙 |
| 24 | + |
| 25 | +> **규칙 1: 그룹 폴더는 구조를 위한 폴더일 뿐입니다** |
| 26 | +> |
| 27 | +> 그룹 폴더에는 자체 `model`, `ui`, `api` 같은 segment를 두지 않습니다. `index.ts` 같은 public API도 두지 않습니다. |
| 28 | +
|
| 29 | +> **규칙 2: 그룹 안의 slice도 여전히 독립적입니다** |
| 30 | +> |
| 31 | +> 같은 그룹 아래에 있어도, slice 사이의 격리 규칙은 그룹 밖과 똑같이 적용됩니다. |
| 32 | +
|
| 33 | +> **규칙 3: 그룹은 탐색을 위한 구조일 뿐, 별도의 기능 단위처럼 사용하지 않습니다** |
| 34 | +> |
| 35 | +> slice group을 새로운 layer, 하위 layer, 공유 모듈처럼 사용하지 않습니다. |
| 36 | +
|
| 37 | +이 규칙을 지키지 않으면 group 폴더가 단순 정리된 폴더가 아니라 별도의 구조 단위처럼 사용될 수 있습니다. |
| 38 | +그러면 어떤 폴더가 실제 slice인지 구분하기 어려워지고, 의존 관계도 더 복잡해질 수 있습니다. |
| 39 | + |
| 40 | +## 왜 필요한가 |
| 41 | + |
| 42 | +slice가 적을 때는 평평한 구조에서도 충분히 탐색할 수 있습니다. |
| 43 | +하지만 같은 성격의 slice가 많아지면, 관련 코드를 찾기 위해 layer 전체를 여러 번 살펴봐야 합니다. |
| 44 | + |
| 45 | +예를 들어 `entities` layer에 결제와 관련된 slice가 많아졌다고 가정해 보겠습니다. |
| 46 | + |
| 47 | +**그룹핑 전:** |
| 48 | + |
| 49 | +<FileTree> |
| 50 | +- entities/ |
| 51 | + - invoice/ |
| 52 | + - model/ |
| 53 | + - ui/ |
| 54 | + - receipt/ |
| 55 | + - model/ |
| 56 | + - ui/ |
| 57 | + - transaction/ |
| 58 | + - model/ |
| 59 | + - ui/ |
| 60 | + - user/ |
| 61 | + - model/ |
| 62 | + - ui/ |
| 63 | + - product/ |
| 64 | + - model/ |
| 65 | + - ui/ |
| 66 | + - ... |
| 67 | +</FileTree> |
| 68 | + |
| 69 | +결제 관련 slice(`invoice`, `receipt`, `transaction`)를 찾으려면 layer 전체를 훑어보면서 관련 항목을 찾아야 합니다. |
| 70 | + |
| 71 | +**그룹핑 후:** |
| 72 | + |
| 73 | +<FileTree> |
| 74 | +- entities/ |
| 75 | + - payment/ slice group |
| 76 | + - invoice/ slice |
| 77 | + - model/ |
| 78 | + - ui/ |
| 79 | + - receipt/ slice |
| 80 | + - model/ |
| 81 | + - ui/ |
| 82 | + - transaction/ slice |
| 83 | + - model/ |
| 84 | + - ui/ |
| 85 | + - user/ slice (그룹 아님) |
| 86 | + - model/ |
| 87 | + - ui/ |
| 88 | + - product/ slice (그룹 아님) |
| 89 | + - model/ |
| 90 | + - ui/ |
| 91 | + - ... |
| 92 | +</FileTree> |
| 93 | + |
| 94 | +이제 결제 도메인 관련 slice는 `payment/` 아래에서 바로 찾을 수 있습니다. |
| 95 | + |
| 96 | +slice group은 이런 식으로 관련 slice를 가까이 배치해서 **관련 slice를 더 빨리 찾을 수 있게 돕는 역할**을 합니다. |
| 97 | +특히 새로 합류한 팀원이나, 해당 영역을 처음 보는 개발자가 구조를 파악할 때 도움이 됩니다. |
| 98 | + |
| 99 | +### pages에서도 같은 문제가 생길 수 있습니다 |
| 100 | + |
| 101 | +비슷한 문제는 pages layer에서도 나타날 수 있습니다. |
| 102 | +특정 도메인의 목록, 상세, 생성, 수정 page가 layer 전체에 흩어져 있으면 탐색성이 떨어집니다. |
| 103 | + |
| 104 | +<FileTree> |
| 105 | +- pages/ |
| 106 | + - orderCreate/ |
| 107 | + - ui/ |
| 108 | + - orderDetail/ |
| 109 | + - ui/ |
| 110 | + - orderList/ |
| 111 | + - ui/ |
| 112 | + - customerDetail/ |
| 113 | + - ui/ |
| 114 | + - customerList/ |
| 115 | + - ui/ |
| 116 | + - settings/ |
| 117 | + - ui/ |
| 118 | + - ... |
| 119 | +</FileTree> |
| 120 | + |
| 121 | +`order` 관련 page와 `customer` 관련 page가 flat하게 나열돼 있어, 특정 도메인의 page를 찾으려면 layer 전체를 훑어봐야 합니다. |
| 122 | +slice group을 도입하면 같은 도메인의 page를 한곳에서 확인할 수 있습니다. |
| 123 | + |
| 124 | +<FileTree> |
| 125 | +- pages/ |
| 126 | + - order/ slice group |
| 127 | + - orderCreate/ slice |
| 128 | + - ui/ |
| 129 | + - orderDetail/ slice |
| 130 | + - ui/ |
| 131 | + - orderList/ slice |
| 132 | + - ui/ |
| 133 | + - customer/ slice group |
| 134 | + - customerDetail/ slice |
| 135 | + - ui/ |
| 136 | + - customerList/ slice |
| 137 | + - ui/ |
| 138 | + - settings/ slice (그룹 아님) |
| 139 | + - ui/ |
| 140 | + - ... |
| 141 | +</FileTree> |
| 142 | + |
| 143 | +이처럼 slice group은 entities뿐 아니라, 관련된 page가 많아져 탐색이 어려워지는 pages layer에도 적용할 수 있습니다. |
| 144 | + |
| 145 | +## 언제 도입을 고려하는가 |
| 146 | + |
| 147 | +slice group은 기본 구조가 아니며, 탐색 문제를 해결해야 할 때 선택적으로 도입하는 구조입니다. |
| 148 | + |
| 149 | +### 도입을 고려할 신호 |
| 150 | + |
| 151 | +- **동일한 비즈니스 맥락의 slice가 layer 안에 여러 개 흩어져 있다.** |
| 152 | + 예를 들어 `invoice`, `receipt`, `transaction`이 모두 payment 맥락을 다루지만 flat하게 나열되어 있는 경우입니다. |
| 153 | + |
| 154 | +- **slice 이름만 보아도 공통된 상위 맥락이 자연스럽게 드러난다.** |
| 155 | + 예를 들어 `orderCreate`, `orderDetail`, `orderList`는 모두 `order`라는 공통 맥락 아래에서 이해됩니다. |
| 156 | + 마찬가지로 `invoice`, `receipt`, `transaction`도 `payment` 맥락으로 함께 인식될 수 있습니다. |
| 157 | + |
| 158 | +- **관련 slice를 찾기 위해 layer 전체를 반복해서 살펴보게 된다.** |
| 159 | + |
| 160 | +- **새 팀원이 구조를 이해하기 위해 layer 전체를 반복해서 살펴보게 된다.** |
| 161 | + |
| 162 | +### 아직 필요 없을 신호 |
| 163 | + |
| 164 | +- slice 수가 많아도 이름만으로 충분히 빠르게 탐색된다. |
| 165 | + |
| 166 | +- 그룹 기준이 자연스럽지 않고, 팀마다 묶는 방식이 계속 달라진다. |
| 167 | + |
| 168 | +- 그룹을 만들어도 그 안에 slice가 1~2개뿐이라 정리 효과가 거의 없다. |
| 169 | + |
| 170 | +- 그룹을 만들면 오히려 "이게 slice인가, 그룹인가"를 추가로 설명해야 한다. |
| 171 | + |
| 172 | +핵심은 폴더 구조 깊이를 늘리는 데 있지 않고, 실제로 구조를 더 쉽게 찾고 이해할 수 있게 하느냐에 있습니다. |
| 173 | + |
| 174 | +## 어떻게 적용하는가 |
| 175 | + |
| 176 | +### entities — 도메인 기반 그룹핑 |
| 177 | + |
| 178 | +도메인 모델 관점에서 가까운 slice를 묶습니다. |
| 179 | + |
| 180 | +<FileTree> |
| 181 | +- entities/ |
| 182 | + - payment/ slice group |
| 183 | + - invoice/ slice |
| 184 | + - model/ |
| 185 | + - ui/ |
| 186 | + - receipt/ slice |
| 187 | + - model/ |
| 188 | + - ui/ |
| 189 | + - transaction/ slice |
| 190 | + - model/ |
| 191 | + - ui/ |
| 192 | + - user/ slice (그룹 아님) |
| 193 | + - model/ |
| 194 | + - ui/ |
| 195 | + - ... |
| 196 | +</FileTree> |
| 197 | + |
| 198 | +`payment/`은 slice가 아니므로, 자체 `model.ts`, `index.ts`, `api/`를 두지 않습니다. |
| 199 | + |
| 200 | +모든 slice를 그룹에 넣을 필요도 없습니다. |
| 201 | +`user/`처럼 그 자체로 의미가 분명한 slice는 그룹 없이 그대로 둘 수 있습니다. |
| 202 | + |
| 203 | +### pages — 도메인별 페이지 그룹핑 |
| 204 | + |
| 205 | +같은 도메인의 여러 page를 함께 다뤄야 할 때 사용할 수 있습니다. |
| 206 | + |
| 207 | +<FileTree> |
| 208 | +- pages/ |
| 209 | + - order/ slice group |
| 210 | + - orderCreate/ slice |
| 211 | + - ui/ |
| 212 | + - orderDetail/ slice |
| 213 | + - ui/ |
| 214 | + - orderList/ slice |
| 215 | + - ui/ |
| 216 | + - customer/ slice group |
| 217 | + - customerDetail/ slice |
| 218 | + - ui/ |
| 219 | + - customerList/ slice |
| 220 | + - ui/ |
| 221 | + - settings/ slice (그룹 아님) |
| 222 | + - ui/ |
| 223 | + - ... |
| 224 | +</FileTree> |
| 225 | + |
| 226 | +이 구조는 목록, 상세, 생성, 수정처럼 같은 주제의 page가 많을 때 도움이 됩니다. |
| 227 | +상위 폴더 하나만 열어도 관련 page를 함께 확인할 수 있기 때문입니다. |
| 228 | + |
| 229 | +### features에서도 사용할 수 있나요? |
| 230 | + |
| 231 | +가능합니다. |
| 232 | +다만 feature는 여러 entity와 여러 사용 흐름에 걸쳐 있는 경우가 많아, entities나 pages보다 그룹 기준이 덜 분명할 수 있습니다. |
| 233 | + |
| 234 | +따라서 features에서의 slice group은 예외적으로 사용할 수 있는 선택지 정도로 보는 편이 좋습니다. |
| 235 | +자연스러운 그룹 기준이 없다면 억지로 도입하지 않는 편이 낫습니다. |
| 236 | + |
| 237 | +## 피해야 할 패턴 |
| 238 | + |
| 239 | +slice group은 구조화용 폴더여야 합니다. |
| 240 | +그룹 폴더에 공용 코드나 여러 `slice`를 다시 묶어 내보내는 파일을 두기 시작하면, 그룹이 사실상 하나의 모듈처럼 동작하게 됩니다. |
| 241 | + |
| 242 | +**피해야 할 패턴:** |
| 243 | + |
| 244 | +<FileTree> |
| 245 | +- entities/ |
| 246 | + - payment/ |
| 247 | + - model.ts 그룹 레벨 공유 모델 |
| 248 | + - index.ts 그룹 레벨 re-export |
| 249 | + - invoice/ |
| 250 | + - model/ |
| 251 | + - ui/ |
| 252 | + - receipt/ |
| 253 | + - model/ |
| 254 | + - ui/ |
| 255 | +</FileTree> |
| 256 | + |
| 257 | +이 구조에서는 `payment/model.ts`나 `payment/index.ts`를 통해 |
| 258 | +하위 slice들이 독립적으로 보이더라도 실제로는 그룹 단위로 함께 엮이기 쉽습니다. |
| 259 | + |
| 260 | +그 결과 slice 경계가 흐려지고, 의존성 방향을 파악하기 어려워지며, 실제 독립 단위가 무엇인지도 헷갈리게 됩니다. |
| 261 | + |
| 262 | +**올바른 패턴:** |
| 263 | + |
| 264 | +<FileTree> |
| 265 | +- entities/ |
| 266 | + - payment/ |
| 267 | + - invoice/ |
| 268 | + - model/ |
| 269 | + - ui/ |
| 270 | + - receipt/ |
| 271 | + - model/ |
| 272 | + - ui/ |
| 273 | +</FileTree> |
| 274 | + |
| 275 | +공통 로직이 실제로 필요하다면, 그것을 그룹 폴더에 억지로 두기보다 더 적절한 layer나 별도의 `slice`로 분리할 수 있는지 먼저 검토해야 합니다. |
| 276 | + |
| 277 | +## FAQ |
| 278 | + |
| 279 | +### 모든 slice를 그룹에 넣어야 하나요? |
| 280 | + |
| 281 | +아닙니다. |
| 282 | +자연스럽게 함께 묶이는 slice만 그룹으로 묶고, 나머지는 그대로 둡니다. |
| 283 | + |
| 284 | +예를 들어 `payment/invoice`, `payment/receipt`처럼 함께 보는 편이 자연스러운 경우만 그룹핑하고, |
| 285 | +`user`, `settings`처럼 독립적으로 이해되는 slice는 그룹 없이 둘 수 있습니다. |
| 286 | + |
| 287 | +### import 경로에 그룹명이 포함되어도 괜찮나요? |
| 288 | + |
| 289 | +괜찮습니다. |
| 290 | +예를 들어 `@/entities/payment/invoice`처럼 그룹명이 경로에 포함되면, 어떤 주제 아래의 slice인지 경로만으로도 드러납니다. |
| 291 | + |
| 292 | +다만 경로를 어떻게 노출할지는 팀의 import convention 문제입니다. |
| 293 | + |
| 294 | +### slice group이 있으면 slice 간 import가 더 자유로워지나요? |
| 295 | + |
| 296 | +아닙니다. |
| 297 | +같은 그룹 안에 있다는 이유만으로 slice 간 import 규칙이 완화되지는 않습니다. |
| 298 | + |
| 299 | +group은 탐색을 위한 구조일 뿐이며, slice 경계와 의존성 규칙은 기존과 동일하게 유지됩니다. |
| 300 | + |
| 301 | +## 참고 자료 |
| 302 | + |
| 303 | +- [카카오페이 - pages layer에서 slice grouping을 적용한 사례](https://tech.kakaopay.com/post/fsd/#2-slice-grouping-%ED%97%88%EC%9A%A9-%EB%B0%8F-pages-%EB%A0%88%EC%9D%B4%EC%96%B4-%EA%B5%AC%EC%84%B1) |
| 304 | +- [러시아 텔레그램 FSD 커뮤니티 - 구조적 그룹핑, slice group, 계층 확장에 대한 논의](https://t.me/c/1216849846/1/2785) |
| 305 | +- [러시아 텔레그램 FSD 커뮤니티 - 중첩 구조와 flat 구조, slice group의 형태와 허용 범위](https://t.me/c/1216849846/1/5051) |
| 306 | +- [러시아 텔레그램 FSD 커뮤니티 - 왜 features에서는 그룹핑 예시가 적은가, features에서도 slice group이 가능한가](https://t.me/c/1216849846/1/80620) |
0 commit comments