GROWTH LOG STORIES

함께 만든 성장을,
기록으로 연결합니다.

AI와 함께 배우고, 직접 만들고, 서로 나눈
그로스로그 멤버들의 생생한 성장 기록을 만나보세요.

성장 기록
5기+이어진 커뮤니티
HEALTHIO
PROJECT

사진 한 장으로 시작하는 건강 루틴, Health IO

대표 이야기 읽기

ALL STORIES

성장의 순간을
한곳에서 만나보세요.

프로젝트의 시작부터 모임에서 나눈 인사이트까지,
그로스로그가 함께 만든 기록을 모았습니다.
개의 성장 기록

성장일지

[GL 3기 10회차 ①] 규칙을 먼저 정하고 시작하기 — REST API 설계, 3년의 선택이 회사가 되기까지 🌱

GROWTH LOG🌱 2026. 8. 7. 06:00

안녕하세요! 그로스로그 입니다!😊 🌱

URI에 동사를 쓰면 왜 안 되는지부터 시작하는 REST 설계 정리, 그리고 3년 전 일주일짜리 프로젝트가 회사가 되기까지의 선택들. 3기 10회차 첫 번째입니다.

성장일지는 멤버들이 2주에 한 번씩 자신의 성장을 기록하는 활동이에요. 매 회차 운영진이 모든 글을 읽고, 그중 특히 마음에 남은 글을 함께 골라 큐레이션합니다.

이번 두 편은 원칙에 대한 이야기입니다. 한 편은 원칙이 무엇인지, 다른 한 편은 그 원칙을 언제 써야 하는지를 다뤄요.

 

01

🔗 Spring Boot로 RESTful API 설계 및 구현

박지훈 님

이런 내용이에요
REST의 여섯 가지 기본 원칙부터 시작해 URI 설계 가이드라인, HTTP 메서드 매핑, Spring Boot 구현까지 이어지는 정리입니다.
특히 URI 설계 부분이 실용적이에요. 잘못된 예시 → 문제점 → 올바른 예시를 표로 나란히 놓았습니다.
그리고 Controller → Service → DAO → MyBatis까지 실제 코드로 흐름을 보여줍니다. 8회차의 TypeScript 체크리스트를 쓰셨던 그분이에요.

REST는 다들 쓰지만, 왜 그렇게 써야 하는지까지 아는 경우는 드뭅니다. 이 글이 그 부분을 채웁니다.

조금 더 들어가 보면

먼저 REST가 어디서 왔는지를 짚습니다. HTTP/1.0과 1.1 설계에 참여한 Roy Fielding이 2000년 논문에서 제안했다고요.

이 배경이 중요합니다. REST는 새 프로토콜이 아니라 "HTTP를 원래 설계대로 잘 쓰자"는 제안이거든요. 그래서 REST 원칙 대부분이 HTTP에 이미 있는 기능을 가리킵니다.

여섯 원칙 중 실무에서 자주 걸리는 두 가지를 보겠습니다.

Stateless(무상태성)"각 요청은 독립적이며, 서버는 세션/쿠키 등 상태를 저장하지 않음"입니다.

이게 왜 중요할까요. 서버를 여러 대로 늘릴 수 있게 되기 때문입니다. 서버가 세션을 들고 있으면 사용자는 항상 같은 서버로 가야 해요. 1기 1회차에서 이태형 님이 Redis로 세션을 밖으로 뺐던 이유가 정확히 이겁니다. 무상태로 만들면 어느 서버가 받아도 되니 확장이 쉬워집니다.

Cacheable(캐시 가능)Last-Modified, ETag 같은 HTTP 표준 헤더를 활용하는 겁니다. 브라우저나 중간 프록시가 "이거 안 바뀌었네" 하고 재사용할 수 있게요.

🧭 URI에 동사를 쓰면 안 되는 이유

이 글에서 가장 실용적인 부분입니다. 표로 정리된 규칙들을 보면 원리가 하나예요.

잘못된 예시 올바른 예시
GET /get-user_list.json GET /users
GET /users/123/orders_list/ GET /users/123/orders
GET /product/456.json GET /products/456
GET /user_profiles GET /user-profiles

동사를 쓰지 않는 이유가 핵심입니다. 글의 설명이 정확해요.

"REST는 HTTP 메서드(GET, POST…)로 동작을 구분하므로 URI엔 명사(리소스)만 남겨야 합니다."

"무엇을"은 URI가, "어떻게"는 메서드가 담당하는 겁니다. GET /get-users는 "가져오기"를 두 번 말하는 셈이에요.

이 구분이 잡히면 API가 예측 가능해집니다. /users라는 주소 하나에 GET(조회), POST(생성), PUT(수정), DELETE(삭제)를 붙이면 CRUD가 다 되니까요. 주소를 네 개 만들 필요가 없습니다.

확장자를 빼는 이유도 같은 맥락입니다. .json을 붙이면 주소가 형식에 묶여버려요. 나중에 XML도 지원하려면 주소를 하나 더 만들어야 합니다. 대신 클라이언트가 Accept: application/json 헤더로 요청하면, 같은 주소로 여러 형식을 줄 수 있어요.

언더스코어 대신 대시를 쓰라는 대목도 근거가 좋았습니다.

"구글 같은 검색엔진은 대시(-)를 '단어 구분자'로 인식합니다. 언더스코어(_)는 단어를 이어 붙이는 연결부로 인식해서, 실제로는 'userprofiles'처럼 한 덩어리로 처리할 수 있습니다."

URI 설계가 SEO와 이어진다는 관찰입니다. 3회차의 시맨틱 마크업, 9회차의 Core Web Vitals에 이어 또 하나의 SEO 접점이에요.

📝 원문에서는 이렇게 구현합니다

@RequestParam@PathVariable을 나눠 쓴 게 좋은 예시입니다.

@GetMapping("/menu")
public List<Menu> recommend(
    @RequestParam String foodType,
    @RequestParam String taste
) {
    Map<String, String> params = Map.of("foodType", foodType, "taste", taste);
    return menuService.selectMenuRecommendation(params);
}
@GetMapping("/{foodType}")
public List<Menu> byType(@PathVariable String foodType) {
    return menuService.selectMenuByfoodType(Map.of("foodType", foodType));
}

둘의 차이가 REST 사고방식을 보여줍니다.

@PathVariable"어떤 리소스인가"를 정합니다. /menu/kr은 "한식 메뉴"라는 리소스 자체예요.

@RequestParam"그 리소스를 어떻게 걸러낼 것인가"입니다. ?foodType=kr&taste=hot은 조건 조합이죠.

주소는 대상을, 쿼리는 조건을 — 이 감각이 잡히면 API 설계가 훨씬 일관됩니다.

그리고 Controller → Service → DAO → MyBatis로 이어지는 계층 분리도 보여줍니다. 2기 11회차에서 이태형 님이 다뤘던 클린 아키텍처와 같은 구조예요. 컨트롤러는 요청만 받고, 서비스가 흐름을 잡고, DAO가 DB를 다룹니다.

큐레이터 노트

규칙에 이유를 붙인 정리라서 뽑았습니다.

"URI에 동사 쓰지 마세요"는 어디서나 볼 수 있습니다. 그런데 "HTTP 메서드가 이미 동작을 표현하니까"라는 이유까지 적힌 자료는 적어요. 이유를 알면 처음 보는 상황에서도 판단할 수 있습니다.

잘못된 예시를 먼저 보여준 형식도 좋았습니다. GET /get-user_list.json처럼 실제로 자주 나오는 형태를 놓고 문제를 짚으니, 읽으면서 "아 내가 저렇게 썼는데" 하게 되거든요.

이 저자는 8회차의 TypeScript 체크리스트에 이어 두 번째 큐레이션입니다. 둘 다 "체크리스트"에 가까운 형태예요. 필요할 때 펼쳐보는 용도로 정리하는 자기 방식이 있는 분입니다.

원문 읽으러 가기  ↗velog.io/@shaynepark/spring-boot-restful-api-design-and-im…
 

02

🧭 선택과 책임의 연속인 개발 생활

강단 님

강단 님 원문에 실린 이미지
이런 내용이에요
Claude와 대화하다 "YAGNI 원칙"이라는 처음 보는 용어를 만납니다. "지금 필요하지 않은 기능은 미리 구현하지 말라."
그런데 의문이 들어요. "줄곧 들어온 '재활용성과 확장성을 고려하라'와 모순되는 게 아닌가?"
그 질문이 3년 전 기억을 불러옵니다. 그리고 글은 하나의 프로젝트가 회사가 되기까지 5단계를 따라가며, 각 단계마다 필요했던 원칙이 달랐다는 걸 보여줍니다.

3기에 네 번 큐레이션되신 분의 마지막 글입니다. 그리고 회고로서 아주 좋은 글이에요.

조금 더 들어가 보면

출발점의 질문이 좋습니다. YAGNI와 확장성은 모순 아닌가?

실제로 많이 헷갈리는 지점입니다. 한쪽에서는 "미리 만들지 마라"고 하고, 다른 쪽에서는 "확장 가능하게 설계하라"고 하니까요.

글이 찾은 답은 이겁니다.

"결국은 '상황에 따라 적용해야 한다'였습니다."

말로만 들으면 뻔한 결론인데, 그 뒤에 3년치 근거가 붙습니다.

💙 1단계 — "일주일 안에 배포"

3년 전, 프론트엔드 1년 차. 최소 인원, 일주일도 안 되는 시간.

그때 저자는 확장성을 고려하려고 노력했습니다. "나중에 이런 기능 추가해 달라고 하겠지" 하면서요.

그런데 결과가 이랬어요.

"A를 요구했으니, 나중엔 A-1을 요구하겠지? ❌
A를 요구했으나, [🦄💫뭔가뭔가🍑🍺]를 요구한다. ⭕️"

예측한 방향과 전혀 다르게 흘러갔습니다. 확장이 아니라 "프로세스 전면 수정"이 수차례 반복됐고요.

이게 YAGNI가 존재하는 이유입니다. 미래를 예측해서 만든 유연성은 대개 틀린 방향으로 유연합니다. 그리고 그 유연성을 유지하는 비용은 계속 나가죠.

당시 상황 묘사도 생생합니다. 기획서 없이 엑셀에 메뉴명 몇 줄, 디자이너 1명 + 프론트 1명 + 백엔드 1명, 다른 프로젝트도 동시 진행. "선조치 후보고"로 일했다고요.

💙 2단계 — 팀원이 늘고 사용자가 생기다

프로젝트가 팀의 메인이 되고 유저가 생깁니다. 그리고 새 팀원이 합류해요.

"혼자 알아보던 코드를 본 새로운 팀원이 고개를 저었어요. 🤦‍♂️"

여기서 DRY가 필요해집니다. 같은 로직이 여기저기 복붙되어 있어서 "한 곳을 고치면 다른 곳에서 버그가 터졌"거든요.

1단계에서는 문제가 아니었던 게 2단계에서 문제가 됩니다. 혼자 만들 때는 중복이 빨랐지만, 둘이 되니 위험이 됐어요.

그리고 현실적인 어려움도 적혀 있습니다. 팀원이 늘자 "두 명이니까~(이것도)(저것도)" 하며 일이 더 들어왔고, 팀이 아니라 개인에게 꽂히니 정작 동료와 이야기할 시간이 없었다고요.

그럼에도 리팩터링 기간을 따로 받아냈습니다. 이게 중요한 대목이에요. 코드 정리는 시간을 안 주면 영원히 못 합니다.

💙 3단계 — useEffect 지옥

useEffect(() => {
  if (user) setUserData(user);
}, [user]);

useEffect(() => {
  if (userData) fetchUserProjects();
}, [userData]);

useEffect(() => {
  if (projects.length > 0) setSelectedProject(projects[0]);
}, [projects]);

하나가 끝나면 다음이 도는 사슬 구조입니다. 상태 하나가 바뀌면 연쇄적으로 다른 것들이 따라 돌아요. 흐름을 따라가기가 아주 어렵고, 중간에 하나만 어긋나도 무한 루프가 납니다.

여기서 선택의 기로가 나옵니다.

· A. 새로 다시 만들기 — 안전하지만 오래 걸림

· B. 점진적으로 수정 — 위험하지만 서비스 중단 없음

B를 골랐습니다. 이유는 "사용자들의 서비스 이용을 중단시킬 수 없었고, 완전히 새로 만들 리소스도 없었음."

이미 사용자가 있는 서비스에서는 이게 거의 유일한 답입니다. 그리고 이때 얻은 문장이 있어요.

"추측으로 진행한 최적화는 악의 근원."

💙 4단계 — UI 프레임워크의 배신

초기에 고른 UI 프레임워크가 베타였는데, 정식 출시되면서 완전히 다른 물건이 됐습니다.

기존: Emotion 기반 스타일링 / 새 버전: Tailwind 기반으로 완전 변경 / 호환성: 거의 5%

커스텀까지 해둔 상태라 업데이트를 적용할 수 없었어요. 선택지는 셋이었고, C. 프레임워크 걷어내기를 골랐습니다.

"장기적으로 봤을 때 베타 버전에 계속 의존할 순 없었으니까 (오늘이 가장 빨리 버릴 수 있는 날🥲)"

"오늘이 가장 빨리 버릴 수 있는 날" — 기술 부채를 다루는 태도가 이 한 줄에 있습니다. 미룰수록 더 커지니까요.

그리고 이렇게 정리합니다. "초기에 급히 선택한 프레임워크가, 몇 주짜리 작업으로 돌아올 줄 몰랐어요." 4회차와 6회차에서 다뤘던 "규모에 맞는 선택"이 실제 청구서로 돌아온 사례입니다.

💙 5단계 — 회사가 되다

프로젝트가 하나의 회사가 됐습니다. 이제야 SOLID를 고려할 필요가 생겨요.

"더 이상 '일단 돌아가게' 정도로는 배포될 수 없는 규모와 기대치."

🧭 그리고 레거시를 보는 시각

이 글에서 가장 좋은 부분이 마지막입니다.

"지금 초기 코드들을 보면 헛웃음이 나와요. 그 코드는 '잘못된 코드'였어요. '그때는 맞고, 지금은 틀렸다' 정도가 아니라 진짜 잘못됐었어요.
하지만 그때는 나의 '최선'이었습니다. 당시의 제약과 상황 속에서 내가 선택할 수 있었던 가장 합리적인 방법이었으니까."

변명하지도 않고 자책하지도 않습니다. 코드가 나빴다는 걸 인정하면서, 동시에 그때의 자신을 이해해요.

이 균형이 어렵습니다. 대개는 한쪽으로 기울거든요. "그때는 어쩔 수 없었어"로 넘기거나, "왜 그렇게 짰지"로 자책하거나요.

큐레이터 노트

원칙을 시간 축에 올려놓은 글이라 뽑았습니다.

YAGNI, KISS, DRY, SOLID는 다들 아는 원칙입니다. 그런데 이 글은 "언제 어떤 원칙이 필요했는가"를 5단계로 배치했어요.

· 1단계(생존) — YAGNI + KISS

· 2단계(협업) — DRY

· 3단계(운영) — 점진적 리팩터링

· 4단계(부채 상환) — 기술 선택의 무게

· 5단계(성장) — SOLID

원칙끼리 모순되는 게 아니라 적용 시점이 다른 것이라는 답이 여기서 나옵니다. 1년 차에 SOLID를 지키려 했다면 일주일 안에 배포를 못 했을 거고, 지금 YAGNI만 붙들면 회사가 안 굴러가겠죠.

3년을 한 편에 담은 것도 값집니다. 성장일지를 2주에 한 번씩 쓰다 보면 대개 그 2주 안의 일을 적게 되는데, 이 글은 긴 호흡으로 자기 궤적을 돌아봤어요. 그런 글은 자주 나오지 않습니다.

그리고 AI와 대화하다 나온 용어에서 시작했다는 점도 이 시대의 학습 방식을 보여줍니다. 모르는 단어를 그냥 넘기지 않고 파고들었더니 3년치 회고가 나온 거예요.

원문 읽으러 가기  ↗kangdanne.tistory.com/344

💡 두 편을 겹쳐 읽으며

한 편은 REST 설계 규칙, 한 편은 3년치 회고입니다. 형식이 완전히 다릅니다.

그런데 두 글은 원칙을 다루는 두 가지 방식을 각각 보여줍니다.

박지훈 님의 글은 원칙이 무엇이고 왜 그런가를 정리합니다. URI에 동사를 쓰지 않는 이유, 확장자를 빼는 이유, 대시를 쓰는 이유. 근거가 붙은 규칙이에요.

강단 님의 글은 그 원칙을 언제 적용할 것인가를 다룹니다. YAGNI와 확장성이 모순처럼 보이는 건, 둘 다 옳은데 적용할 때가 다르기 때문이라는 답이죠.

둘 다 필요합니다. 원칙을 모르면 매번 처음부터 고민해야 하고, 적용 시점을 모르면 원칙에 끌려다니게 되니까요.

그리고 두 글이 공통으로 보여주는 게 하나 더 있습니다. "왜"를 아는 사람만 예외를 판단할 수 있다는 것.

REST 규칙을 외우기만 하면 벗어나야 할 상황에서 못 벗어납니다. YAGNI를 교리처럼 지키면 정말로 미리 설계해야 할 때를 놓치고요.

규칙은 기본값이지 명령이 아닙니다. 근거를 알아야 언제 따르고 언제 벗어날지 정할 수 있어요. 두 글이 각자의 방식으로 그걸 보여줬습니다.

이번 회차에서 가져갈 것

1. URI는 명사, 동작은 메서드. GET /get-users는 "가져오기"를 두 번 말하는 겁니다. 주소 하나에 GET/POST/PUT/DELETE를 붙이면 CRUD가 다 돼요.

2. 주소는 대상, 쿼리는 조건. @PathVariable어떤 리소스인가, @RequestParam어떻게 걸러낼 것인가입니다. 이 구분이 API를 일관되게 만듭니다.

3. 예측해서 만든 유연성은 대개 틀린 방향이다. 요구사항은 예상한 대로 오지 않습니다. 불확실하면 지금 필요한 것만 만들고, 실제 요구가 왔을 때 확장하세요.

4. 원칙은 단계마다 다르다. 혼자 일주일 만에 만들 때는 YAGNI, 팀이 되면 DRY, 규모가 커지면 SOLID. 지금 우리가 어느 단계인지를 먼저 보세요.

5. 기술 부채는 오늘이 가장 싸다. 베타 버전 의존, 임시 구조, 미룬 마이그레이션. 미룰수록 커집니다. 그리고 지난 코드가 나빴다는 걸 인정하되, 그때의 자신을 탓하지는 마세요.


좋은 글 남겨주신 박지훈 님, 강단 님께 감사드립니다! 😊

3기 마지막 큐레이션으로 이어집니다! 🌱

- 에디터 · 성장일지 큐레이터 -


※ 본 큐레이션은 각 저자가 공개한 글을 소개하는 것이며, 모든 원문의 저작권은 저자에게 있습니다. 저자 본인의 요청이 있을 경우 즉시 수정 또는 삭제합니다.

WRITE YOUR GROWTH

오늘의 배움을
내일의 성장으로.

기록은 나를 돌아보게 하고, 공유는 우리를 연결합니다.
당신의 다음 성장 이야기도 그로스로그에서 시작해보세요.

커뮤니티 둘러보기