정답은 없다. 하지만 원칙은 있다. 그리고 혼자 할 때와 팀으로 할 때는 완전히 다른 게임이다.
Claude 선생님이 알려주신 대원칙 5
1. 관심사 분리 (Separation of Concerns)
핵심각 파일/폴더는 하나의 명확한 책임을 가져야 한다의미- ’아, 이 기능 바꾸려면 저 파일들을 수정하면 되겠구나’라고 미리 알 수 있는 것
- ‘어디어디에 같은 코드가 또 있을까?’ 하고 걱정하지 않아도 되는 것
예시
// ✅ 관심사가 잘 분리된 구조
src/
├── utils/
│ └── dateHelper.js // 날짜 관련 로직만
├── api/
│ └── eventApi.js // 서버 통신만
├── components/
│ └── EventCard.vue // 화면 표시만
└── stores/
└── eventStore.js // 상태 관리만
// 날짜 형식 바꿔달라? → dateHelper.js만 수정
// API 주소 바뀜? → eventApi.js만 수정
// 디자인 변경? → EventCard.vue만 수정
2. 의존성 방향 (Dependency Direction)
핵심상위 → 하위로만 의존해야 한다의미- utils가 components를 import하면 안 됨
- 순환 참조 방지 (A가 B를 부르고, B가 다시 A를 부르면 무한루프)
예시
// 폴더 계층: views > components > utils
// ✅ 올바른 방향
// views/EventList.vue
import EventCard from '@/components/EventCard.vue' // 상위→하위 OK
// components/EventCard.vue
import { formatDate } from '@/utils/dateHelper.js' // 상위→하위 OK
// ❌ 잘못된 방향
// utils/dateHelper.js
import EventCard from '@/components/EventCard.vue' // 하위→상위 NG!
// components/EventCard.vue
import EventList from '@/views/EventList.vue' // 하위→상위 NG!
// ❌ 이렇게 되면 빌드 에러!
// A.js
import B from './B.js'
// B.js
import A from './A.js' // A와 B가 서로를 부름 → 무한루프!
3. 예측 가능성 (Predictability)
핵심파일명과 위치만 봐도 역할을 알 수 있어야 한다의미- 새로운 사람이 와도 직관적으로 이해 가능
- 파일 찾는 시간 최소화
예시
// ❌ 예측하기 어려운 이름들
components/
├── Thing.vue // 뭘 하는 컴포넌트인지 모름
├── utils.js // 어떤 유틸인지 모름
├── api.js // 어떤 API인지 모름
└── temp.vue // 임시파일? 뭔지 모름
// ✅ 예측 가능한 이름들
components/
├── EventCard.vue // 이벤트 카드구나!
├── UserProfile.vue // 사용자 프로필이구나!
├── FileUploadButton.vue // 파일 업로드 버튼이구나!
└── CalendarGrid.vue // 달력 격자구나!
// 폴더도 마찬가지
src/
├── components/ // 재사용 컴포넌트들이 있겠구나
├── views/ // 페이지들이 있겠구나
├── utils/ // 유틸리티 함수들이 있겠구나
└── api/ // 서버 통신 관련이 있겠구나
// ❌ 이렇게 되면 빌드 에러!
// A.js
import B from './B.js'
// B.js
import A from './A.js' // A와 B가 서로를 부름 → 무한루프!
4. 확장성 (Scalability)
핵심프로젝트가 10배 커져도 구조가 깨지지 않아야 한다의미- 폴더가 너무 깊어지거나 파일이 너무 많아지면 안 됨
- 프로덕트 성장에 따라 자연스럽게 진화할 수 있는 구조
예시한 폴더에 파일 10개 넘으면 분할 고려!
// 초기: 컴포넌트 5개
components/
├── Button.vue
├── Input.vue
├── Modal.vue
├── EventCard.vue
└── UserCard.vue
// 성장: 컴포넌트 30개 → 분류 필요!
components/
├── ui/ // 기본 UI들
│ ├── Button.vue
│ ├── Input.vue
│ └── Modal.vue
├── cards/ // 카드형 컴포넌트들
│ ├── EventCard.vue
│ ├── UserCard.vue
│ └── ProductCard.vue
└── forms/ // 폼 관련들
├── EventForm.vue
├── UserForm.vue
└── LoginForm.vue
// 더 성장: 컴포넌트 100개 → 더 세분화
components/
├── ui/
│ ├── buttons/ // 버튼들만
│ ├── inputs/ // 입력 요소들만
│ └── modals/ // 모달들만
├── business/ // 비즈니스 로직 관련
│ ├── events/
│ ├── users/
│ └── products/
└── layouts/ // 레이아웃 관련
5. 일관성 (Consistency)
핵심같은 성격의 것들은 같은 규칙으로 배치한다의미- 예외를 만들 때는 명확한 이유가 있어야 함
- 패턴이 있어야 기억하기 쉽고 찾기 쉬움
예시네이밍 일관성
// ❌ 일관성 없음
components/
├── eventCard.vue // camelCase
├── user-profile.vue // kebab-case
├── ButtonBig.vue // PascalCase
└── input_field.vue // snake_case
// ✅ 일관성 있음 (Vue 권장: PascalCase)
components/
├── EventCard.vue // 모두 PascalCase
├── UserProfile.vue
├── ButtonBig.vue
└── InputField.vue
- 구조 일관성
// ✅ 모든 기능이 같은 패턴
features/
├── events/
│ ├── EventList.vue // 목록
│ ├── EventForm.vue // 폼
│ ├── EventDetail.vue // 상세
│ └── eventStore.js // 스토어
├── users/
│ ├── UserList.vue // 같은 패턴!
│ ├── UserForm.vue // 같은 패턴!
│ ├── UserDetail.vue // 같은 패턴!
│ └── userStore.js // 같은 패턴!
└── products/
├── ProductList.vue // 같은 패턴!
├── ProductForm.vue // 같은 패턴!
├── ProductDetail.vue // 같은 패턴!
└── productStore.js // 같은 패턴!
실제 상황"상품 폼 컴포넌트 어디 있지?"- "events, users와 같은 패턴이니까 products/ProductForm.vue겠네!" (즉시 예측 가능)
됐고, 그래서 혼자 할 때 어떻게 해야하는데?
⎯ 나만의 기준 세우는 10가지 질문
1. 프로젝트 성격 파악하기
질문1 "이 프로젝트는 얼마나 오래 갈 건가?”
// 실험용 (1-2주)
→ 간단한 구조로, 빠른 개발 우선
→ src/ 바로 아래에 파일들 두기
// 포트폴리오용 (1-3개월)
→ 중간 복잡도, 깔끔하게 보이는 구조
→ components/, views/, utils/ 정도
// 실제 서비스 (6개월+)
→ 확장성 고려한 엔터프라이즈 구조
→ features/, stores/, composables/ 등
질문2"최종적으로 몇 개 정도의 파일이 생길까?”
// ~20개 파일: 단순 구조
src/
├── components/
├── utils/
└── assets/
// 20-100개 파일: 중간 구조
src/
├── components/
│ ├── ui/
│ └── business/
├── views/
├── stores/
└── utils/
// 100개+ 파일: 복잡한 구조
src/
├── features/
├── shared/
├── layouts/
└── core/
2. 내 사고 패턴 파악하기
질문3 "나는 코드를 어떻게 찾는가?”
// 자가 진단 테스트
"이벤트 관련 코드 수정해야 해" 했을 때:
A. "events 폴더부터 찾는다"
→ 기능별 구조 선호 (features/)
B. "컴포넌트 폴더에서 Event로 시작하는 걸 찾는다"
→ 타입별 구조 선호 (components/)
C. "파일명으로 검색한다"
→ 네이밍이 더 중요, 구조는 단순하게
질문4 "나는 어떤 순서로 개발하는가?”
// 내 개발 스타일 파악
A. "기능 하나를 완전히 끝내고 다음으로"
→ features/events/ 안에 모든 관련 파일
B. "UI부터 다 만들고, 로직은 나중에"
→ components/ 먼저, 나중에 stores/
C. "작은 단위부터 조립해서 큰 것으로"
→ utils/ → components/ → views/ 순서
질문5 나는 비슷한 파일들을 어떻게 그룹핑하고 싶은가?”
// 그룹핑 성향 테스트
예시: EventCard, UserCard, ProductCard가 있을 때
A. cards/ 폴더에 모아둔다
→ 형태/역할 기준 그룹핑
B. events/, users/, products/ 각각에 둔다
→ 도메인/기능 기준 그룹핑
C. components/ 에 다 두되 접두사로 구분
→ 플랫한 구조 선호
3. 실용적 기준 세우기
질문6 "내가 자주 동시에 수정하는 파일들은?”
// 실제 개발하면서 관찰해보기
"이벤트 생성 기능 만들 때"
→ EventForm.vue + eventStore.js + eventApi.js
→ 이런 파일들은 가까이 두자!
"UI 디자인 수정할 때"
→ Button.vue + Input.vue + Modal.vue
→ 이런 것들도 가까이 두자!
질문7 "내가 가장 싫어하는 불편함은?”
// 개인적 스트레스 포인트
A. "파일 찾는 데 시간 오래 걸리는 것"
→ 예측 가능한 네이밍과 위치 중시
B. "같은 코드를 여러 곳에서 복붙하는 것"
→ 재사용성 우선, utils/ 폴더 중시
C. "폴더가 너무 깊어지는 것"
→ 플랫한 구조 선호, 최대 3depth
D. "파일이 너무 많아서 헷갈리는 것"
→ 세분화된 폴더 구조 선호
4. 실험하고 검증하기
질문8 "이 구조로 3개 기능 만들어보니 어때?”
// 실제 사용 후 평가
기능 1: 이벤트 목록
기능 2: 사용자 프로필
기능 3: 파일 업로드
"새 기능 추가할 때마다 어디에 둘지 고민됐나?"
"비슷한 코드 찾기 쉬웠나?"
"파일명만 봐도 역할을 알 수 있었나?"
질문9 "1주일 후에 내 코드를 다시 봤을 때?"
// 기억력 테스트
"아, 저 기능은 어디에 뒀더라?"
→ 10초 안에 찾았으면 좋은 구조
→ 30초 이상 걸렸으면 구조 개선 필요
"이 파일이 뭘 하는 파일이지?"
→ 파일명만 봐도 기억났으면 좋은 네이밍
→ 파일 열어봐야 알겠으면 네이밍 개선 필요
내 스타일 정의하기
질문10 "내 개발 철학은 뭔가?"
// 우선순위 정하기
A. "빠른 개발이 최우선"
→ 구조는 단순하게, 네이밍은 직관적으로
B. "깔끔한 코드가 최우선"
→ 관심사 분리 철저히, 재사용성 중시
C. "미래 확장성이 최우선"
→ 처음부터 복잡한 구조도 OK
D. "학습 효과가 최우선"
→ 다양한 패턴 실험해보기
10가지 질문 활용 예시
// 내 답변들:
1. 3개월 정도 할 예정 → 중간 복잡도
2. 30-50개 파일 예상 → 적당한 분류 필요
3. 기능별로 찾는 스타일 → features/ 선호
4. UI 먼저 만드는 스타일 → components/ 우선
5. 도메인별 그룹핑 선호 → events/, users/ 분리
6. Form + Store + API 자주 같이 수정 → 같은 폴더에
7. 파일 찾기 어려운 게 스트레스 → 명확한 네이밍
8. 실험 결과: features/ 구조가 편했음
9. 1주일 후에도 쉽게 찾았음
10. 학습 중이니까 다양한 패턴 시도해보고 싶음
// 결론: 내 스타일
src/
├── features/ # 기능별 그룹핑
│ ├── events/
│ └── users/
├── shared/ # 공통 요소들
│ ├── components/
│ ├── utils/
│ └── api/
└── assets/
됐고, 그래서 팀으로 할 때는 어떻게 해야하는데?
⎯ ‘합의’가 ‘완벽함’보다 중요하다
개인 vs 협업의 차이점
개인 프로젝트: "내가 편한 구조" = 정답
협업 프로젝트: "팀이 합의한 구조" = 정답
// 실제 상황
개인: 내 스타일대로 features/ 구조 사용
협업: 팀원 A는 features/ 선호, B는 components/ 선호
→ 누구 말을 들을 것인가?
우리가 해야 할 구체적인 행동들
프로젝트 시작 전: 팀 컨텍스트 파악하기
// 첫 번째 미팅에서 나눠야 할 대화들
"우리 팀원들이 어떤 경험을 가지고 있나요?"
→ 신입 많으면: 단순하고 직관적인 구조
→ 경력자 많으면: 복잡해도 효율적인 구조
"회사에 기존 프로젝트 컨벤션이 있나요?"
→ 있으면: 기존 패턴 따르기 (일관성 우선)
→ 없으면: 새로 만들되 다른 팀과 충돌 없게
"이 프로젝트 규모와 기간은?"
→ MVP(2주): 빠른 개발 우선, 구조는 심플하게
→ 장기 서비스(6개월+): 유지보수성 우선, 구조 탄탄하게
구조 설계 미팅: 구체적 시나리오로 논의
// 추상적 논의 금지! 구체적 예시로만!
❌ "우리 어떤 구조로 할까요?"
✅ "어드민 사용자 관리 기능을 어디에 둘까요?"
// 실제 논의 예시
팀원 A: "admin/users/에 UserList.vue, UserForm.vue 두자"
팀원 B: "components/admin/에 두고 views/admin/에서 조립하자"
팀원 C: "features/user-management/에 두자"
→ 각자 이유 설명하고 장단점 비교
→ 투표나 토론으로 결정
우선순위 합의: 트레이드오프 명확히 하기
// 팀 가치 정렬하기
"우리 팀에게 가장 중요한 것은?"
Option A: 빠른 개발 속도
→ 구조는 단순하게, 중복 코드 허용
Option B: 코드 품질
→ 구조 복잡해도 재사용성 우선
Option C: 신입 학습 곡선
→ 직관적이고 예측 가능한 구조
Option D: 유지보수성
→ 처음엔 복잡해도 장기적 관점
// 팀 투표 결과에 따라 구조 결정!
작은 실험으로 검증하기
// "논쟁보다는 실험"
1주차: 각자 선호하는 방식으로 작은 기능 하나씩 만들어보기
A팀원: features/auth/ 방식
B팀원: components/auth/ 방식
C팀원: pages/auth/ 방식
2주차: 서로 코드 리뷰하며 장단점 체감하기
"실제로 코드 찾기 쉬웠나?"
"새 기능 추가할 때 어디에 둘지 고민됐나?"
"다른 사람 코드 이해하기 쉬웠나?"
3주차: 결과 바탕으로 팀 컨벤션 결정
문서화와 가이드라인 만들기
// 팀 합의 내용을 README에 기록
# 우리 팀 디렉토리 구조 가이드
## 기본 원칙
- 기능별 그룹핑 우선 (features/)
- 공통 컴포넌트는 shared/components/
- 어드민과 사용자 기능 분리
## 파일 배치 규칙
- 새 기능: features/{기능명}/ 폴더 생성
- CRUD 세트: 같은 폴더에 배치
- 공통 로직: shared/utils/ 또는 composables/
## 네이밍 컨벤션
- 컴포넌트: PascalCase (UserList.vue)
- 파일/폴더: kebab-case (user-management/)
- 상수: UPPER_SNAKE_CASE
## 애매할 때 결정 방법
- Slack #dev-team 채널에서 논의
- 24시간 내 답변 없으면 기존 패턴 따르기
- 결정 사항은 이 문서에 업데이트
지속적인 소통과 개선
// 정기 회고 (2주마다)
"현재 구조에서 불편했던 점들"
- 구체적 사례와 함께 공유
- "이 파일 찾는 데 5분 걸렸어요"
- "비슷한 기능이 3곳에 흩어져 있어요"
"개선 제안들"
- 작은 것부터 시도
- "새 기능부터 이 방식으로 해봐요"
- 전체 리팩토링은 마일스톤 단위로
"다음 2주 실험"
- 한 가지씩만 바꿔서 효과 측정
협업에서는
- 완벽한 구조는 없다 - 팀이 합의한 구조가 최선
- 논쟁보다 실험 - 말로 하지 말고 실제로 써보기
- 점진적 개선 - 처음부터 완벽하려 하지 말기
- 문서화 필수 - 합의 내용을 기록으로 남기기
- 소통이 핵심 - 불편함이 생기면 바로 공유하기
그건 이상이고,
현업에서 언제 ‘실험-검증’하고 있어?
현업의 진짜 현실
이상: "1주일 실험해보고 결정해요"
현실: "내일까지 기능 완성해야 하는데 구조 고민할 시간이 어딨어?"
이상: "팀 전체 합의 도출"
현실: "시니어가 "이렇게 해" 하면 그대로 하는 거임"
이상: "점진적 개선"
현실: "레거시 건드리면 버그 날까봐 무서워서 그냥 둠"
그럼 현업에서는 실제로 어떻게 하는가?
기존 프로젝트 패턴 그대로 따라하기
// 신입/이직자가 와서 하는 일
1일차: "우리 프로젝트 구조가 어떻게 되어있는지 보세요"
2일차: "기존 코드 보고 똑같이 만드세요"
3일차: "왜 이렇게 되어있는지 물어보지 마세요, 시간 없어요"
// 현실적 적응 전략
→ 일단 기존 패턴 파악하고 따라하기
→ 불편해도 당분간 참기
→ 신뢰 쌓인 후에 조심스럽게 개선 제안
"작은 범위"에서만 조심스럽게 시도
// 전체 구조 바꾸자고? → "미친놈" 취급
// 새 기능 하나만 다른 방식으로? → "음... 해볼까?"
예시:
"이번 새 어드민 기능만 features/ 방식으로 해봐도 될까요?"
→ 기존 코드는 안 건드리고, 새 폴더만 다르게
성공하면: "아, 이 방식 괜찮네? 다음에도 써볼까?"
실패하면: "역시 기존 방식이 나아" 끝.
시니어/팀리드의 성향 파악하기
// A타입 시니어: 보수적
"기존 방식 건드리지 마, 검증된 거니까"
→ 전략: 기존 패턴 완전 숙지 후 아주 작은 개선만
// B타입 시니어: 개방적
"더 좋은 방법 있으면 써봐"
→ 전략: 근거 있는 제안, 리스크 분석과 함께
// C타입 시니어: 실무 중심
"일정만 맞추면 뭐든 상관없어"
→ 전략: 개발 속도 향상시키는 구조 제안
회사/팀 컬처 읽기
// 스타트업
→ 빠른 개발이 최우선, 구조는 이차적
→ 실험 허용도 높지만 시간은 없음
// 대기업
→ 안정성 최우선, 변화 매우 신중
→ 문서화된 가이드라인 존재 가능성 높음
// 개발팀 규모
→ 3-5명: 비공식적 합의, 빠른 의사결정
→ 10명+: 공식적 프로세스, 느린 의사결정
현실적인 "우리" 전략
신입/주니어라면
1단계: "관찰자" (1-2개월)
- 기존 구조 완전 파악하기
- 불편한 점 기록하되 말은 안 하기
- 팀 컬처와 시니어 성향 파악
2단계: "조심스러운 제안자" (3-6개월)
- 아주 작은 개선사항 제안
- "이거 하나만 바꿔봐도 될까요?" 수준
- 근거와 함께 제안 (시간 절약, 버그 감소 등)
3단계: "신뢰받는 개선자" (6개월+)
- 팀원들이 의견 물어볼 때만 적극적으로
- 새 프로젝트나 큰 기능에서만 구조 제안
중급/시니어라면
1. "점진적 개선" 전략
- 전체 리팩토링 대신 "보이스카우트 룰"
- 건드리는 코드만 조금씩 개선
- "이 기능 수정하면서 구조도 조금 정리했어요"
2. "교육" 전략
- 주니어들에게 좋은 구조 알려주기
- 코드 리뷰에서 구조 관련 피드백
- "왜 이렇게 했는지" 설명해주기
3. "기회 포착" 전략
- 새 프로젝트, 대규모 기능 추가 시점 활용
- "이번 기회에 구조 개선해보면 어떨까요?"
가장 현실적인 접근법
"완벽한 구조보다 팀의 생산성이 더 중요”
현실에서는:
1. 기존 구조 존중하기 (레거시도 나름의 이유가 있음)
2. 작은 개선부터 시작하기 (혁명 말고 개량)
3. 팀원들과 신뢰 관계 먼저 쌓기
4. 비즈니스 임팩트가 있는 개선에 집중
5. "구조보다 기능 완성"이 우선임을 인정
// 가장 중요한 것
"내가 원하는 완벽한 구조" < "팀이 함께 일할 수 있는 구조"
// 구조 개선 제안할 때 절대 성공 공식
"이렇게 하면 개발 시간이 30% 단축됩니다" ✅
"이 구조가 더 깔끔해요" ❌
"버그 발생 가능성이 줄어들어요" ✅
"이론적으로 더 좋은 패턴이에요" ❌
"신입이 적응하기 쉬워져요" ✅
"Best Practice라고 들었어요" ❌
디렉토리 구조에 정답은 없다. 하지만 "왜 이렇게 구성했는가"를 설명할 수 있는 구조가 좋은 구조다.
혼자 할 때는 실험하고, 팀으로 할 때는 합의하고, 현업에서는 현실을 받아들이자.