--- id: wiki-2026-0508-웹-애플리케이션의-3계층-구조 title: 웹 애플리케이션의 3계층 구조 category: 10_Wiki/Topics status: verified canonical_id: self aliases: [3-Tier Architecture, Three-Tier Web App, Presentation-Logic-Data] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [architecture, 3-tier, web, layered] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: typescript framework: nextjs --- # 웹 애플리케이션의 3계층 구조 ## 매 한 줄 > **"매 presentation / logic / data 의 separation"**. 매 1990 년대 client-server 의 evolution — 매 thick client 의 limit 의 escape. 2026 년 매 SPA + BFF + DB 의 form, 또는 SSR (Next.js) 의 collapsed form 의 dominant. ## 매 핵심 ### 매 3 layers - **Presentation (UI)**: 매 user-facing rendering — browser, mobile app. - **Application/Logic (BLL)**: 매 business rule + orchestration — API server. - **Data (DAL)**: 매 persistence — RDBMS, NoSQL, cache. ### 매 communication - **Client → API**: HTTPS REST / GraphQL / gRPC-Web. - **API → DB**: 매 connection pool — TCP. - **Layer rule**: 매 adjacent layer only — UI 의 DB 직접 access 의 X. ### 매 응용 1. Traditional LAMP/MEAN — 매 separated tier. 2. Next.js SSR — 매 server component 가 logic + data 의 collapse. 3. Mobile app + REST API + Postgres — 매 classic 3-tier. ## 💻 패턴 ### Next.js 15 server component (collapsed 3-tier) ```tsx // app/users/page.tsx — server component import { db } from '@/lib/db'; // DAL async function getUsers() { // BLL return db.user.findMany({ where: { active: true } }); } export default async function UsersPage() { // Presentation const users = await getUsers(); return ( ); } ``` ### Classic separated tier (REST) ```typescript // Tier 1: React SPA const res = await fetch('/api/users'); const users = await res.json(); // Tier 2: Express API (Node.js) app.get('/api/users', async (req, res) => { const users = await userService.listActive(); // BLL res.json(users); }); // Tier 3: Repository (Postgres) class UserRepository { async listActive() { return pool.query('SELECT * FROM users WHERE active = true'); } } ``` ### BFF (Backend for Frontend) ```typescript // 매 mobile + web 의 다른 BFF — 매 tier 2 의 split. // /api/web/dashboard — web-tailored aggregate app.get('/api/web/dashboard', async (req, res) => { const [user, stats, notifs] = await Promise.all([ userSvc.get(req.userId), statsSvc.summary(req.userId), notifSvc.unread(req.userId), ]); res.json({ user, stats, notifs }); }); ``` ### Repository pattern (DAL boundary) ```typescript interface UserRepository { findById(id: string): Promise; save(user: User): Promise; } class PostgresUserRepository implements UserRepository { constructor(private pool: Pool) {} async findById(id: string) { const { rows } = await this.pool.query( 'SELECT * FROM users WHERE id = $1', [id] ); return rows[0] ?? null; } async save(user: User) { await this.pool.query('INSERT INTO users ... ON CONFLICT ...'); } } ``` ### Service layer (BLL) ```typescript class OrderService { constructor( private orders: OrderRepository, private inventory: InventoryService, private payments: PaymentService, ) {} async place(userId: string, items: CartItem[]): Promise { await this.inventory.reserve(items); const charge = await this.payments.charge(userId, total(items)); const order = await this.orders.create({ userId, items, chargeId: charge.id }); return order; } } ``` ### Cache layer (between BLL and DAL) ```typescript class CachedUserRepo implements UserRepository { constructor(private inner: UserRepository, private redis: Redis) {} async findById(id: string) { const cached = await this.redis.get(`user:${id}`); if (cached) return JSON.parse(cached); const user = await this.inner.findById(id); if (user) await this.redis.setex(`user:${id}`, 300, JSON.stringify(user)); return user; } } ``` ## 매 결정 기준 | 상황 | Architecture | |---|---| | Simple CRUD app | Next.js full-stack (collapsed) | | Mobile + web + admin | BFF per client | | Microservices | API gateway + service mesh | | Monolithic enterprise | Strict 3-tier with DI | | Real-time | Add WebSocket/SSE tier | **기본값**: 매 Next.js server components 의 simplest path. ## 🔗 Graph - 부모: [[Layered Architecture]] · [[Client-Server]] - 변형: [[N-Tier]] · [[BFF]] · [[Microservices]] - Adjacent: [[MVC]] ## 🤖 LLM 활용 **언제**: web app 의 layer separation 의 design 의 결정 시. **언제 X**: real-time game, embedded system — 매 different model. ## ❌ 안티패턴 - **Smart UI**: 매 SQL 의 frontend — 매 layer 의 violate. - **Anemic service**: 매 service 의 pass-through 의 only — 매 logic 의 controller. - **Chatty DAL**: 매 N+1 query — 매 batch 의 X. - **Leaky DB schema**: 매 ORM entity 의 API 의 expose — 매 DTO 의 separate. ## 🧪 검증 / 중복 - Verified (Fowler *PoEAA*; Microsoft *Application Architecture Guide*; Next.js docs 2026). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — 3-tier + BFF + repository patterns |