"매 layer-by-type 의 feature-by-vertical-slice 의 invert". Feature-Driven Architecture 매 codebase 의 organization unit 매 feature/use-case — 매 each feature 매 own UI + state + API + tests 의 own. Frontend 매 FSD (Feature-Sliced Design), Backend 매 vertical slice / modular monolith 의 manifest.
매 핵심
매 Why
Layer-by-type problem: 매 controllers/, services/, models/ 매 small project 의 fine, 매 100+ features 시 매 cross-cutting changes 의 5 directories 의 touch.
Feature 의 lifecycle: 매 feature 의 add/remove/own 의 single folder 의 happen.
Team scaling: 매 vertical squad 의 own 매 single feature folder, 매 conflicts 의 minimize.
// features/auth-login/index.ts
export{LoginForm}from'./ui/LoginForm';export{useLoginMutation}from'./api/login';// 매 internal model/store 의 not exported — encapsulation
// features/place-order/handler.ts
exportclassPlaceOrderCommand{constructor(publicuserId: string,publicitems: Item[]){}}exportasyncfunctionplaceOrder(cmd: PlaceOrderCommand,deps: Deps){constuser=awaitdeps.users.findById(cmd.userId);if(!user)thrownewNotFoundError();constorder=Order.create(user,cmd.items);awaitdeps.orders.save(order);awaitdeps.bus.emit('order.placed',{orderId: order.id});return{orderId: order.id};}// features/place-order/route.ts
router.post('/orders',async(req,res)=>{constresult=awaitplaceOrder(req.body,deps);res.json(result);});// 매 single folder 매 use-case 의 entire handle
Cross-feature communication via events
// features/cart-checkout — 매 features/inventory-update 의 NOT 매 import
// 매 instead: emit event, 매 inventory feature 의 subscribe
import{bus}from'@/shared/event-bus';asyncfunctioncheckout(cart: Cart){awaitbus.emit('checkout.completed',{items: cart.items});}// features/inventory-update/index.ts
bus.on('checkout.completed',async({items})=>{awaitdecrementStock(items);});
Feature flag boundary
// features/new-search-v2/index.ts
import{useFlag}from'@/shared/feature-flags';import{SearchV1}from'@/features/search-v1';import{SearchV2}from'./ui/SearchV2';exportfunctionSearch() {constv2=useFlag('search-v2');returnv2?<SearchV2/>:<SearchV1/>;}// Removal 의 single folder delete
매 결정 기준
상황
Approach
Solo / < 10 features
매 layer-by-type 매 fine
Frontend, growing team
매 FSD
Backend, modular monolith
매 vertical slice (CQRS-style)
Microservices
매 service-per-feature 매 already
Strict isolation 의 needed
매 ESLint boundaries + barrel exports
기본값: 매 frontend 매 FSD, 매 backend 매 vertical slice — 매 cross-feature 의 events.
언제: 매 10+ features, 매 multi-team. Frontend 매 page-driven 의 outgrow. Modular monolith 매 service split 의 prepare.
언제 X: 매 small app (<10 screens). 매 prototype phase — 매 over-structure cost > benefit.
❌ 안티패턴
Cross-feature direct import: 매 features/cart 매 features/checkout/internal 의 import — 매 coupling 의 reintroduce. Public API 만 의 use.
God shared/: 매 모든 utility 의 shared/utils/ 의 dump — 매 entities/features 의 leak 의 should.
Premature feature split: 매 single-screen app 의 7 features 의 carve — 매 navigation cost.
Layer skipping: 매 entities 매 features 의 import — 매 dependency rule violation.
🧪 검증 / 중복
Verified (feature-sliced.design official; Jimmy Bogard "Vertical Slice Architecture").