세 트랙이 「같은 이름」 으로 만나는 자리 — 읽기 자료
쇼핑몰, SNS, 게시판, 예약 시스템, 배달앱, 동영상 사이트 — 어떤 서비스든 처음 만나는 화면은 거의 같습니다. 회원가입 폼. 입력칸 몇 개와 가입 버튼 하나. 수많은 프로젝트가 같은 모양을 다시 만들고 있고, 그래서 이 흔한 화면을 한 번 제대로 들여다 보면 다음 모든 프로젝트가 쉬워집니다.
이미 v2~v4 에서 회원가입을 따라하기로 한 번 완성했습니다. 코드는 동작합니다. 오늘은 그 코드가 「어떻게 만들어지는가」 를 위에서 한 번 내려다봅니다 — 실제 팀 프로젝트라면 이 화면 하나가 어떤 단계를 거쳐 나오는가?
실제 팀 프로젝트는 코드 짜기 전에 다음 단계를 모두 지납니다. 우리는 한 차시에 압축해서 한번 훑어봅니다.
① 기획 ② 요구사항 ③ 유스케이스 ④ 화면 스케치 ⑤ 구현
────── ───────── ────────── ─────────── ──────
뭘 만들지 무슨 데이터를 사용자가 어떻게 화면 어떻게 Front
결정 저장할지 쓸지 한 줄 그릴지 Back
DB
↓ ↓ ↓ ↓ ↓
"회원가입을 ★ id, pwd, nick "폼 입력 → 입력 3칸 폼 / 컨트롤러
만들자" ← 데이터 약속 가입 버튼 → + 버튼 1개 / 테이블
처음 정해짐! redirect"
| 단계 | 하는 일 | 회원가입 예 |
|---|---|---|
| ① 기획 | 기능을 만들기로 정함 | "회원가입 기능을 만들자" |
| ② 요구사항정의서 | 어떤 데이터를 저장할까 | id, pwd, nick ← 데이터 약속이 처음 정해진다 |
| ③ 유스케이스 | 사용자가 어떻게 쓰는지 한 줄 | "폼에 3칸 입력 → 가입 버튼 → 로그인 페이지로 이동" |
| ④ 화면 스케치 | 디자이너가 그림으로 | 입력칸 3개 + 버튼 1개 |
| ⑤ 구현 | Front + Back + DB | JSP 폼 / Controller / mymember 테이블 |
핵심: ② 단계에서 정해진 「id, pwd, nick」 이라는 약속은 ⑤ 구현 단계의 모든 트랙(Front·Back·DB)을 통과합니다. 이 한 줄기 흐름이 보이는 것이 오늘 차시의 첫 목표입니다.
회원가입 화면, Controller, Service, Mapper, MySQL 테이블 — 모두 한 사람 손으로 짰습니다. 그런데 실제 팀 프로젝트는 보통 3~5 명이 같이 합니다. 누가 무엇을 맡고, 어떻게 동시에 일할 수 있는지 가 막막합니다.
상식적으로는 「DB → Backend → Frontend」 순서로 차례차례 짜야 할 것 같습니다. 그런데 현실 팀은 같은 시간에 세 사람이 따로 일합니다. 화면 디자이너는 서버가 없는데도 폼을 만들고, Backend 는 DB 가 비어있는데도 Controller 를 짭니다.
팀 프로젝트의 첫 회의에서 결정해야 할 단 한 가지: 이 데이터를 어떤 이름으로 부를까? 세 사람이 같은 양식의 종이를 들고 시작하는 것과 같습니다. 칸 이름이 같으면 누가 어떤 칸을 채워와도 자연스럽게 합쳐집니다.
| 트랙 | 어디에 등장 | 예시 |
|---|---|---|
| Frontend | <input name="..."> |
name="id", name="pwd", name="nick" |
| Backend | DTO 필드명 | private String id; · private String pwd; · private String nick; |
| DB | 테이블 컬럼명 | mymember(id, pwd, nick) |
<!-- signup.html — Frontend 멤버가 짠 산출물 -->
<form action="/signup" method="post" class="signup-form">
<h2>회원가입</h2>
<input name="id" placeholder="아이디">
<input name="pwd" type="password" placeholder="비밀번호">
<input name="nick" placeholder="닉네임">
<button>가입하기</button>
</form>
<style>
.signup-form { max-width: 360px; padding: 24px;
border-radius: 12px; background: #fafafa; }
.signup-form input { display:block; width:100%; padding:10px;
margin:8px 0; border:1px solid #ddd; }
.signup-form button { width:100%; padding:12px;
background:#3b82f6; color:#fff; border:0; }
</style>
Frontend 멤버는 디자인과 UX 에 집중합니다. 서버가 한 줄도 없어도 만들 수 있습니다. 한 가지만 약속을 지키면 됩니다 — name 속성을 팀이 정한 이름으로.
// com/smhrd/domain/Member.java
package com.smhrd.domain;
import lombok.*;
@Data @AllArgsConstructor @NoArgsConstructor
public class Member {
private String id; // ← 약속의 첫 칸
private String pwd; // ← 약속의 둘째 칸
private String nick; // ← 약속의 셋째 칸
}
// com/smhrd/controller/SignupController.java
@Controller
public class SignupController {
@Autowired private MemberService service;
@PostMapping("/signup")
public String signup(Member m) { // 자동 바인딩
System.out.println("받은 데이터: " + m);
service.signup(m);
return "redirect:/login";
}
}
// com/smhrd/mapper/MemberMapper.xml
<insert id="insert" parameterType="com.smhrd.domain.Member">
INSERT INTO mymember (id, pwd, nick)
VALUES (#{id}, #{pwd}, #{nick})
</insert>
Backend 멤버는 로직 정확성 에 집중합니다. 화면은 빈 HTML 만 있어도 동작 시험이 됩니다. 한 가지만 약속을 지키면 됩니다 — DTO 필드명 을 팀이 정한 이름으로.
-- DB 멤버가 짠 산출물 — 화면도 서버도 없는 상태에서 작성 가능
CREATE TABLE mymember (
id VARCHAR(50) PRIMARY KEY,
pwd VARCHAR(100) NOT NULL,
nick VARCHAR(30)
);
-- 검증용 가데이터 3 건
INSERT INTO mymember VALUES ('hong123', 'hashed_pw_1', '홍길동');
INSERT INTO mymember VALUES ('kim456', 'hashed_pw_2', '김영희');
INSERT INTO mymember VALUES ('lee789', 'hashed_pw_3', '이철수');
-- DBA 혼자서 동작 검증
SELECT * FROM mymember WHERE id = 'hong123';
UPDATE mymember SET nick = '홍길순' WHERE id = 'hong123';
DELETE FROM mymember WHERE id = 'lee789';
DB 멤버는 데이터 모델 에 집중합니다. 가데이터와 SELECT 만으로 「테이블이 약속대로 동작하는가」 를 미리 확인할 수 있습니다. 한 가지만 약속을 지키면 됩니다 — 컬럼명 을 팀이 정한 이름으로.
세 트랙의 산출물이 처음 만나는 자리. 코드 한 줄도 새로 짜지 않습니다 — 이름이 같으니 자동 바인딩이 알아서 다리를 놓습니다.
브라우저 Controller MySQL
───────── ─────────── ─────
<form action="/signup"> @PostMapping("/signup") INSERT INTO
name="id" ───→ Member m { id ───→ mymember(
name="pwd" ───→ pwd ───→ id, pwd,
name="nick" ───→ nick }───→ nick) ...
↑ ↑ ↑
└───────────── 같은 단어 ─────────────────────┘
(팀이 정한 약속)
이 차시의 가장 중요한 깨달음 한 가지: 같은 데이터를 받는 화면은 디자인이 갈아끼워질 수 있습니다. 폼의 action, method, name 세 가지만 약속대로면 — 화면 디자인은 무엇이든 가능합니다. Backend 와 DB 는 한 줄도 바뀌지 않습니다.
<form action="/signup" method="post">
<input name="id">
<input name="pwd" type="password">
<input name="nick">
<button>가입</button>
</form>
<form action="/signup" method="post" class="card-form">
<h2>Welcome 👋</h2>
<label>아이디</label>
<input name="id" class="rounded">
<label>비밀번호</label>
<input name="pwd" class="rounded" type="password">
<label>닉네임</label>
<input name="nick" class="rounded">
<button class="gradient-btn">가입하고 시작하기</button>
</form>
두 폼 모두 같은 Controller (@PostMapping("/signup")) 에 들어갑니다. Backend 코드는 단 한 글자도 바꾸지 않습니다. 이게 「데이터 약속」 이 가져다 주는 자유 — 화면을 통째로 다른 페이지에 옮겨도, 서버 입장에서는 같은 요청입니다.
<!-- Frontend 가 만든 폼 -->
<input name="userId" />
// Backend 의 DTO
public class Member { private String id; ... }
// 결과:
받은 데이터: Member(id=null, pwd=*, nick=*)
// ^^^^^^^ "userId" → "id" 매핑 실패
로그인 시도 → DB 에 INSERT 됐는데 id 가 null. 컴파일도 되고 화면도 동작하지만 「데이터만 비어있는」 가장 헷갈리는 류의 사고입니다.
// Backend DTO
public class Member { private String password; ... }
<-- Mapper XML -->
INSERT INTO mymember (id, password, nick) VALUES (#{id}, #{password}, #{nick})
-- 그러나 DB 는 컬럼명이 pwd
mysql> DESC mymember;
+-------+--------------+
| id | varchar(50) |
| pwd | varchar(100) | ← password 가 아님
| nick | varchar(30) |
+-------+--------------+
// 결과:
SQLException: Unknown column 'password' in 'field list'
<!-- list.jsp -->
<c:forEach var="m" items="${members}">
${m.nickname} <!-- 그러나 DTO 는 String nick -->
</c:forEach>
// 결과: 닉네임 자리가 모두 빈 칸. 에러도 안 남.
name = DTO 필드 = 컬럼명. 한 표에 정리해서 공유.이 5 가지를 첫날 30 분 안에 정해놓으면 사고의 90% 가 사라집니다. 「합쳐서 깨지는」 일은 보통 약속이 없거나 모호해서 생깁니다.
이 과정에서 학생이 직접 짠 두 프로젝트 — 자료/code/MavenMember, 자료/code/MavenBoard — 는 한 사람이 모든 트랙을 다 짠 결과물입니다. 그러나 이 차시 관점에서 다시 보면, 두 프로젝트는 정확히 「Front 트랙 산출물 + Back 트랙 산출물 + DB 트랙 산출물」 의 합산입니다. 같은 코드를 「혼자」 가 아니라 「세 사람」 이 했다고 상상하면, 누가 어떤 파일을 맡았을지가 자연스럽게 그려집니다.
id, pwd, nick) 이 모든 트랙을 통과한다회원가입 코드는 동작한다. 그러나 「왜 그렇게 짜는지」 와 「화면이 바뀌면 어떻게 되는지」 는 안 보였다.
기획 → 요구사항 → 화면 → 구현 단계가 보인다. 데이터 약속이 모든 트랙을 잇고, 화면 디자인은 갈아끼울 수 있다는 것을 직접 본다.