// 이 파일이 하는 일: "클린 코드와 코드리뷰" 코스 — 왜 코드는 '읽기'가 먼저인지에서 출발해
// 이름 짓기 → 함수 쪼개기 → 좋은 주석 → 중복 제거 → 매직넘버 추출 → 코드리뷰 예절 →
// 직접 리팩터링 실습까지 8개 섹션으로 안내하는 정적 학습 페이지.
// 학습 포인트: API 호출이 없는 '내용 고정' 페이지다. 스타일은 global.css의
// 가이드 전용 클래스(step-card, code-block, tip 등)를 재사용한다 — 색을 여기서 하드코딩하지 않는다.
// 코드 예제는 JSX 중괄호/백틱 충돌을 피하려고 파일 상단의 백틱 문자열 상수로 정의한다.

import { Link } from 'react-router-dom';

// ── 코드 예제 · 표 상수들 ──

const CODE_READ_TIME = `개발자의 하루를 몰래 들여다보면...

코드를 "쓰는" 시간   ██                    약 1
코드를 "읽는" 시간   ████████████████████  약 10

새 기능 한 줄을 쓰기 위해:
- 이 함수가 어디서 불리는지 읽고
- 옆 파일의 비슷한 코드를 읽고
- 어제의 내가 짠 코드를 읽고 (그리고 후회하고)
- 동료의 PR을 읽는다

→ 그래서 "빨리 쓴 코드"보다 "빨리 읽히는 코드"가
  팀 전체의 속도를 결정합니다.`;

const CODE_NAMING_BAD = `// ❌ 3주 뒤의 나도 못 알아보는 코드
const a = 86400;
const tmp = list.filter((x) => x.s === 1);
function data(d) { ... }

// 읽는 사람의 머릿속:
// "a가 뭐지? tmp는 임시로 뭘 담은 거지?
//  s가 1이면 뭐가 어떻다는 거지? data는 데이터를 뭐 어쩌라는 거지?"`;

const CODE_NAMING_GOOD = `// ✅ 이름이 곧 설명인 코드
const SECONDS_PER_DAY = 86400;
const activeMembers = members.filter((member) => member.status === ACTIVE);
function formatEnrollmentDate(enrolledAt) { ... }

// 규칙 3줄 요약:
// 1) 변수·상수 = 명사     activeMembers, courseList, maxRetryCount
// 2) 함수 = 동사로 시작   fetchCourses(), validateEmail(), isCompleted()
// 3) a, b, tmp, data, info 같은 '아무 이름' 금지
//    (반복문의 i, 좌표의 x·y처럼 관례가 굳은 것만 예외)`;

const CODE_ONE_JOB_BAD = `// ❌ 한 함수가 네 가지 일을 하는 중 — 이름도 못 짓겠죠?
function handleSubmit() {
  // 1) 입력값 검사
  if (!name || name.length < 2) { setError('이름을 확인하세요'); return; }
  if (!email.includes('@')) { setError('이메일을 확인하세요'); return; }
  // 2) 서버에 보낼 모양으로 가공
  const payload = { name: name.trim(), email: email.toLowerCase() };
  // 3) 전송
  fetch('/api/members', { method: 'POST', body: JSON.stringify(payload) });
  // 4) 화면 뒷정리
  setName(''); setEmail(''); setError(null);
}`;

const CODE_ONE_JOB_GOOD = `// ✅ 일 하나 = 함수 하나. 각자 이름표를 달아 주면
//    handleSubmit은 '목차'처럼 읽힙니다.
function validateForm({ name, email }) { ... }   // 검사만
function buildMemberPayload({ name, email }) { ... } // 가공만
function resetForm() { ... }                     // 뒷정리만

function handleSubmit() {
  const error = validateForm({ name, email });
  if (error) { setError(error); return; }
  const payload = buildMemberPayload({ name, email });
  fetch('/api/members', { method: 'POST', body: JSON.stringify(payload) });
  resetForm();
}

// 판별법: 함수가 하는 일을 한 문장으로 말할 때
// "~하고, ~하고, 그리고 ~한다"처럼 '그리고'가 나오면 쪼갤 신호!`;

const CODE_COMMENT = `// ❌ '무엇'을 반복하는 주석 — 코드만 봐도 아는 얘기
// i를 1 증가시킨다
i += 1;

// ✅ '왜'를 남기는 주석 — 코드만 봐서는 절대 모르는 얘기
// 서버가 페이지 번호를 0이 아니라 1부터 세기 때문에 보정한다
i += 1;

// ✅ 우리 플랫폼 실전 예 (지금 이 파일 맨 위를 보세요!)
// "이 파일이 하는 일" 주석: 파일을 열자마자 지도부터 보여준다
// "학습 포인트" 주석: 왜 이렇게 짰는지 의도를 남긴다

// 순서 정리:
// 1순위 — 주석 없이도 읽히게 이름·구조를 고친다
// 2순위 — 그래도 남는 '왜'(사정·제약·의도)만 주석으로 쓴다`;

const CODE_DRY = `// ❌ 복붙 3형제 — 버튼 스타일을 바꾸려면 세 군데를 고쳐야 해요
// CourseCard.jsx 에도, NoticeCard.jsx 에도, QuizCard.jsx 에도
// 거의 똑같은 카드 마크업이 통째로 들어 있는 상황

// ✅ 한 곳으로 모으기 — 이 페이지의 Section 컴포넌트가 실례!
function Card({ title, badge, children }) {
  return (
    <div className="card">
      <div className="card-head">
        <h3>{title}</h3>
        {badge && <span className="chip">{badge}</span>}
      </div>
      <div className="card-body">{children}</div>
    </div>
  );
}
// 이제 고칠 곳은 딱 한 곳. 이것이 DRY(Don't Repeat Yourself)!

// 주의: '우연히 닮은' 코드까지 억지로 합치면 오히려 독.
// 기준 — 한쪽을 고칠 때 다른 쪽도 "반드시 같이" 고쳐야 하는가?`;

const CODE_MAGIC = `// ❌ 매직넘버 — 숫자가 마법처럼 뿅 나타나서 아무 설명이 없다
if (progress >= 80) { unlockCertificate(); }
setTimeout(retry, 3000);
if (title.length > 50) { ... }

// 읽는 사람: "80이 뭔데? 왜 3000이지? 50은 누가 정했지?"
// 더 무서운 건: 기준이 80→70으로 바뀔 때 '80'을 전부 찾아
// 바꿔야 하는데, 관련 없는 80까지 섞여서 하나를 놓친다는 것.

// ✅ 이름 있는 상수로 추출 — 숫자에 이름표 달기
const CERTIFICATE_UNLOCK_PERCENT = 80; // 수료 기준: 진도 80% (교육팀 확정)
const RETRY_DELAY_MS = 3000;
const MAX_TITLE_LENGTH = 50;

if (progress >= CERTIFICATE_UNLOCK_PERCENT) { unlockCertificate(); }

// 백엔드(Spring Boot)도 똑같아요:
// application.yml 설정값이나 상수 클래스로 뽑아 두면
// "정책이 코드 어딘가의 숫자"가 아니라 "이름 붙은 한 곳"이 됩니다.`;

const CODE_REVIEW_MANNER = `코드리뷰 대화 번역기 — 같은 지적, 다른 온도

❌ "이 코드 왜 이렇게 짰어요?"
✅ "이 부분을 이렇게 바꾸면 중복이 줄 것 같은데 어떻게 생각하세요?"

❌ "이거 틀렸는데요."
✅ "여기 email이 빈 문자열이면 통과되는 것 같아요.
    검증 조건을 하나 추가하면 어떨까요?"

❌ (리뷰 받고) "제 코드가 뭐가 어때서요?"
✅ (리뷰 받고) "오, 그 경우는 생각 못 했네요. 고쳐서 다시 올릴게요.
    혹시 비슷한 패턴이 다른 파일에도 있으면 알려 주세요!"

기억할 것:
- 리뷰의 과녁은 '코드'지 '사람'이 아니에요. (코드 지적 ≠ 사람 지적)
- 칭찬도 리뷰다: 좋은 코드엔 "이 함수 분리 깔끔하네요" 한 줄을.
- 작성자가 최종 결정권을 가진 게 아니라, '더 나은 코드'가 이깁니다.
  누가 맞느냐가 아니라 무엇이 맞느냐의 게임이에요.`;

const CODE_PRACTICE_BAD = `// ── 리팩터링 실습 재료 ──
// 아래 코드는 '돌아는 가는' 코드예요. 하지만 이 코스에서 배운
// 문제를 최소 5개 품고 있습니다. 직접 고쳐 보세요!

function calc(list) {
  let tmp = 0;
  for (let i = 0; i < list.length; i++) {
    // 진도율을 더한다
    if (list[i].p >= 80) {
      tmp = tmp + 1;
    }
  }
  let a = (tmp / list.length) * 100;
  if (a >= 60) {
    console.log('통과');
    document.title = '축하합니다!';
    return true;
  } else {
    console.log('미달');
    return false;
  }
}`;

const CODE_PRACTICE_HINT = `찾아야 할 문제 (스스로 먼저 찾고 나서 펼쳐 보기!)

1) 이름: calc, tmp, a, p — 전부 '아무 이름' (섹션 2)
2) 매직넘버: 80과 60이 맨몸으로 등장 (섹션 6)
3) 한 가지 일 위반: 계산 + 콘솔 출력 + 화면(title) 변경을
   한 함수가 다 함 (섹션 3)
4) 주석: "진도율을 더한다"는 코드 반복일 뿐, 심지어
   실제로 더하는 건 '기준을 넘긴 사람 수' — 거짓말 주석! (섹션 4)
5) 덤: filter를 쓰면 for문 자체가 사라져요

모범 답안의 뼈대 (세부는 자유):
const CERTIFICATE_PERCENT = 80;
const CLASS_PASS_RATE = 60;

function getPassRate(students) { ... }   // 계산만 해서 숫자 반환
function isClassPassed(students) { ... } // 기준 비교만
// 콘솔 출력·화면 변경은 함수 밖(호출하는 쪽)의 일!`;

// ── 이 페이지 안에서만 쓰는 작은 부품들 ──
// 학습 포인트: 같은 모양이 반복되면 컴포넌트로 뽑는다. props만 바꿔 재사용.
// (섹션 5 '중복 제거'에서 이 컴포넌트 자체가 교재로 다시 등장해요!)
function Section({ n, title, sub, children }) {
  return (
    <section className="step-card" id={`sec-${n}`}>
      <div className="step-head">
        <span className="step-num">{n}</span>
        <div>
          <h3>{title}</h3>
          {sub && <span className="step-sub">{sub}</span>}
        </div>
      </div>
      <div className="step-body">{children}</div>
    </section>
  );
}

function Code({ children }) {
  return <pre className="code-block"><code>{children}</code></pre>;
}

const SECTIONS = [
  { n: 1, label: '읽는 시간이 더 길다' },
  { n: 2, label: '이름 짓기' },
  { n: 3, label: '함수는 한 가지 일만' },
  { n: 4, label: '주석은 "왜"를' },
  { n: 5, label: '중복 제거' },
  { n: 6, label: '매직넘버 추출' },
  { n: 7, label: '코드리뷰 예절' },
  { n: 8, label: '리팩터링 실습' },
];

export default function CleanCodePage() {
  return (
    <div>
      {/* 히어로: 이 코스가 다루는 것 — 잘 '돌아가는' 코드에서 잘 '읽히는' 코드로 */}
      <div className="hero">
        <div className="eyebrow">Course · 소프트웨어</div>
        <h1>클린 코드와 코드리뷰<br />— 동료가 읽을 코드를 쓰는 법</h1>
        <p>
          돌아가는 코드를 만들었다면 절반은 온 거예요. 나머지 절반은 <strong>3주 뒤의 나와
          옆자리 동료가 한 번에 읽을 수 있는 코드</strong>로 만드는 일이고, 이 코스가 그 방법과
          코드리뷰에서 주고받는 예절까지 다룹니다.
        </p>
        <div className="chip-row">
          <span className="chip">예상 소요 50분</span>
          <span className="chip">실습 2개 + 리팩터링 과제</span>
          <span className="chip">연결 과제: FE-07 · BE-05</span>
        </div>
      </div>

      {/* 섹션 바로가기 */}
      <nav className="pill-nav">
        {SECTIONS.map((s) => (
          <a key={s.n} href={`#sec-${s.n}`}>
            <b>{s.n}</b>
            {s.label}
          </a>
        ))}
      </nav>

      <Section n={1} title="코드는 쓰는 시간보다 읽는 시간이 길다" sub="클린 코드가 필요한 진짜 이유">
        <p>
          코딩을 처음 배울 땐 코드를 <strong>쓰는</strong> 일이라고 생각하기 쉬워요. 그런데
          실제 개발자의 시간을 재 보면 정반대입니다 — 한 줄을 쓰기 위해 열 줄을 읽어요.
          내 코드, 동료 코드, 어제의 내 코드까지.
        </p>
        <Code>{CODE_READ_TIME}</Code>
        <p>
          그래서 코드는 <strong>일기</strong>가 아니라 <strong>편지</strong>예요. 일기는 나만
          알아보면 되지만, 편지는 받는 사람이 읽고 이해해야 완성이죠. 여러분의 코드를 받는
          사람은 팀 동료, 리뷰어, 그리고 이 코드를 다 잊어버린 <strong>3주 뒤의 여러분
          자신</strong>입니다. AWESOMEDEV의 코드도 여러 사람이 몇 년을 이어 다듬는 편지예요 —
          지금 여러분이 보는 이 학습 플랫폼 코드도 마찬가지고요.
        </p>
        <div className="tip">
          <b>미리 알려드리면</b> 이 코스의 규칙들은 전부 한 문장으로 요약돼요 —
          <strong> "읽는 사람의 물음표를 줄여라."</strong> 이름 짓기부터 코드리뷰 매너까지
          모두 이 문장의 각론입니다.
        </div>
      </Section>

      <Section n={2} title="이름 짓기 — 변수는 명사, 함수는 동사" sub="a, tmp, data는 이름이 아니라 물음표">
        <p>
          클린 코드의 절반은 <strong>이름</strong>이에요. 이름이 좋으면 주석 없이도 읽히고,
          이름이 나쁘면 그 코드를 읽는 모든 사람이 매번 추리를 해야 합니다. 물건마다
          이름표 대신 "그거", "저거"라고 써 붙인 창고를 상상해 보세요 — 물건을 찾을 때마다
          상자를 전부 열어 봐야겠죠.
        </p>
        <Code>{CODE_NAMING_BAD}</Code>
        <Code>{CODE_NAMING_GOOD}</Code>
        <p>
          이름이 길어지는 걸 겁내지 마세요. <span className="icode">activeMembers</span>가
          <span className="icode">am</span>보다 타자는 열두 배 느려도, 읽기는 백 배 빨라요.
          그리고 요즘 에디터는 자동완성이 다 해 줍니다. 이름 짓다 5분 고민하는 건 시간 낭비가
          아니라 <strong>설계</strong>예요 — 이름이 안 지어지는 코드는 대개 역할이 뒤죽박죽인
          코드거든요.
        </p>
        <div className="tip">
          <b>직접 확인해 보기</b> 내가 최근에 작성한 코드(과제·개인 프로젝트 아무거나)를 열고
          <span className="icode"> a</span>, <span className="icode">tmp</span>,
          <span className="icode"> data</span>, <span className="icode">list</span> 같은 이름을
          찾아 보세요. 에디터에서 <span className="kbd">F2</span>(이름 바꾸기)를 누르면 그 변수를
          쓰는 모든 곳이 한 번에 바뀝니다 — 세 개만 골라 진짜 이름을 지어 주세요.
        </div>
      </Section>

      <Section n={3} title="함수는 한 가지 일만" sub='"그리고"가 나오면 쪼갤 신호'>
        <p>
          함수는 <strong>일의 단위</strong>예요. 한 함수가 검사도 하고, 가공도 하고, 전송도
          하고, 뒷정리도 하면 — 주방에서 한 사람이 주문받고 요리하고 서빙하고 설거지까지 하는
          식당과 같아요. 바쁠 때 뭐 하나가 꼭 사고 나고, 새 직원(동료)에게 일을 나눠 줄 수도 없죠.
        </p>
        <Code>{CODE_ONE_JOB_BAD}</Code>
        <Code>{CODE_ONE_JOB_GOOD}</Code>
        <p>
          쪼개고 나면 좋은 점이 연쇄로 따라와요. <strong>이름 짓기가 쉬워지고</strong>(일이
          하나니까), <strong>테스트하기 쉬워지고</strong>(입력→출력만 보면 되니까),
          <strong> 재사용할 수 있고</strong>(<span className="icode">validateForm</span>은 다른
          화면에서도 쓰겠죠), 버그가 나도 <strong>범인 후보가 좁혀집니다</strong>.
        </p>
        <svg className="diagram" viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="네 가지 일을 하던 handleSubmit 함수를 validateForm, buildMemberPayload, resetForm 세 함수로 쪼개는 before와 after 비교 도해">
          <text x="145" y="34" textAnchor="middle" fontSize="13.5" fontWeight="700" fill="var(--ink)">Before — 한 함수가 네 가지 일</text>
          <rect x="25" y="48" width="240" height="280" rx="10" fill="var(--card)" stroke="var(--rose)" strokeWidth="1.5" />
          <text x="145" y="74" textAnchor="middle" fontSize="13" fontWeight="700" fill="var(--ink)">handleSubmit()</text>
          <text x="145" y="92" textAnchor="middle" fontSize="11" fill="var(--muted)">검사·가공·전송·뒷정리가 한 몸에</text>
          <rect x="45" y="104" width="200" height="40" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="145" y="129" textAnchor="middle" fontSize="12" fill="var(--ink)">① 입력값 검사</text>
          <rect x="45" y="156" width="200" height="40" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="145" y="181" textAnchor="middle" fontSize="12" fill="var(--ink)">② payload 가공</text>
          <rect x="45" y="208" width="200" height="40" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="145" y="233" textAnchor="middle" fontSize="12" fill="var(--ink)">③ 서버 전송</text>
          <rect x="45" y="260" width="200" height="40" rx="8" fill="var(--card)" stroke="var(--line)" />
          <text x="145" y="285" textAnchor="middle" fontSize="12" fill="var(--ink)">④ 화면 뒷정리</text>
          <text x="313" y="175" textAnchor="middle" fontSize="12" fontWeight="700" fill="var(--primary)">쪼개기</text>
          <line x1="278" y1="190" x2="348" y2="190" stroke="var(--primary)" strokeWidth="2" strokeLinecap="round" />
          <polyline points="340,182 352,190 340,198" fill="none" stroke="var(--primary)" strokeWidth="2" strokeLinecap="round" />
          <text x="492" y="34" textAnchor="middle" fontSize="13.5" fontWeight="700" fill="var(--ink)">After — 일 하나 = 함수 하나</text>
          <rect x="370" y="48" width="245" height="46" rx="10" fill="var(--card)" stroke="var(--primary)" strokeWidth="1.5" />
          <text x="492" y="67" textAnchor="middle" fontSize="13" fontWeight="700" fill="var(--ink)">handleSubmit()</text>
          <text x="492" y="85" textAnchor="middle" fontSize="11" fill="var(--muted)">'목차'처럼 부르기만 한다</text>
          <line x1="390" y1="94" x2="390" y2="264" stroke="var(--line)" strokeWidth="1.5" />
          <line x1="390" y1="136" x2="408" y2="136" stroke="var(--line)" strokeWidth="1.5" />
          <line x1="390" y1="200" x2="408" y2="200" stroke="var(--line)" strokeWidth="1.5" />
          <line x1="390" y1="264" x2="408" y2="264" stroke="var(--line)" strokeWidth="1.5" />
          <rect x="408" y="112" width="207" height="48" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="511" y="132" textAnchor="middle" fontSize="12.5" fontWeight="700" fill="var(--ink)">validateForm()</text>
          <text x="511" y="149" textAnchor="middle" fontSize="11" fill="var(--muted)">검사만</text>
          <rect x="408" y="176" width="207" height="48" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="511" y="196" textAnchor="middle" fontSize="12.5" fontWeight="700" fill="var(--ink)">buildMemberPayload()</text>
          <text x="511" y="213" textAnchor="middle" fontSize="11" fill="var(--muted)">가공만</text>
          <rect x="408" y="240" width="207" height="48" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="511" y="260" textAnchor="middle" fontSize="12.5" fontWeight="700" fill="var(--ink)">resetForm()</text>
          <text x="511" y="277" textAnchor="middle" fontSize="11" fill="var(--muted)">뒷정리만</text>
          <text x="320" y="350" textAnchor="middle" fontSize="12" fill="var(--muted)">판별법: 설명에 "~하고, 그리고 ~한다"가 나오면 쪼갤 신호</text>
        </svg>
        <p className="muted" style={{ fontSize: 12.5, textAlign: 'center', marginTop: 2 }}>그림: 네 가지 일을 하던 handleSubmit을 함수 셋으로 쪼갠 before/after</p>
        <div className="warn">
          <b>흔한 오해</b> "함수는 무조건 5줄 이하!" 같은 줄 수 규칙이 핵심이 아니에요.
          기준은 줄 수가 아니라 <strong>"이 함수가 하는 일을 '그리고' 없이 한 문장으로 말할 수
          있는가"</strong>입니다. 한 가지 일을 하는 20줄 함수는 괜찮아요.
        </div>
      </Section>

      <Section n={4} title='주석은 "무엇"이 아니라 "왜"를' sub="코드가 말 못 하는 사정만 적는다">
        <p>
          주석을 많이 달수록 좋은 코드라고 생각하기 쉬운데, 절반만 맞아요. 코드를 그대로
          한국어로 번역한 주석은 소음이고, 심지어 코드를 고친 뒤 주석을 안 고치면
          <strong> 거짓말하는 주석</strong>이 됩니다. 좋은 주석은 코드가 스스로 말할 수 없는
          것 — <strong>왜 이렇게 했는지</strong>(의도·사정·제약)만 말해요.
        </p>
        <Code>{CODE_COMMENT}</Code>
        <p>
          가장 가까운 실례가 <strong>지금 이 파일</strong>이에요. 이 페이지 소스 맨 위엔
          "이 파일이 하는 일" 주석이, 중간엔 "학습 포인트" 주석이 있어요. 둘 다 코드 자체를
          번역한 게 아니라 <strong>왜 이렇게 만들었는지</strong>를 남긴 주석입니다. 우리 플랫폼의
          모든 페이지가 이 규칙을 따르고 있어요 — 여러분이 코드를 열 때마다 지도를 먼저 받도록요.
        </p>
        <div className="tip">
          <b>직접 확인해 보기</b> Gitea(<span className="icode">edu.awesomedevapp.com:3000</span>)에서
          이 플랫폼 저장소를 열고 <span className="icode">frontend/src/pages</span> 폴더의 파일을
          아무거나 3개 골라 맨 위 주석만 읽어 보세요. 코드를 한 줄도 안 읽고도 각 파일의 역할을
          말할 수 있게 되면 — 그게 바로 "왜" 주석의 힘이에요.
        </div>
      </Section>

      <Section n={5} title="중복 제거 — 같은 코드가 두 번 보이면 의심" sub="고칠 곳이 한 곳이어야 안 틀린다">
        <p>
          복사-붙여넣기는 달콤하지만 이자가 붙는 빚이에요. 같은 코드가 세 군데 있으면, 나중에
          그 로직을 고칠 때 <strong>세 군데를 전부 기억해서</strong> 고쳐야 하고 — 사람은 꼭
          한 곳을 잊습니다. 그 잊은 한 곳이 버그가 되죠. 학교 게시판 세 곳에 같은 공지를 붙였는데
          시간이 바뀌어 두 곳만 고친 상황, 상상되시죠?
        </p>
        <Code>{CODE_DRY}</Code>
        <p>
          이 페이지의 <span className="icode">Section</span> 컴포넌트가 살아 있는 예예요.
          8개 섹션의 겉모양(번호·제목·부제 틀)이 전부 똑같아서 컴포넌트 하나로 뽑았고,
          덕분에 섹션 디자인을 바꿀 일이 생기면 <strong>딱 한 곳</strong>만 고치면 됩니다.
        </p>
        <div className="tip">
          <b>과제로 연결</b> 지금 우리 플랫폼 프론트엔드에 카드 마크업이 여러 페이지에 복붙된
          곳이 실제로 있어요. <strong>FE-07 티켓(중복 카드 컴포넌트 추출)</strong>이 바로 그걸
          공용 컴포넌트로 뽑는 과제입니다 — 이 섹션을 이해했다면 이미 절반은 푼 거예요.
        </div>
      </Section>

      <Section n={6} title="매직넘버 추출 — 숫자에 이름표 달기" sub="80이 뭔데? 를 없애는 법">
        <p>
          코드 한복판에 맨몸으로 등장하는 숫자를 <strong>매직넘버</strong>라고 불러요.
          작성자에겐 당연한 숫자지만 읽는 사람에겐 마술처럼 뿅 나타난 수수께끼거든요.
          그 숫자가 <strong>정책</strong>(수료 기준, 제한 길이, 재시도 간격...)이라면
          반드시 이름 있는 상수로 뽑아야 합니다.
        </p>
        <Code>{CODE_MAGIC}</Code>
        <p>
          상수로 뽑으면 세 가지가 공짜로 따라와요. <strong>읽기</strong> — 이름이 곧 설명.
          <strong> 고치기</strong> — 정책이 바뀌면 한 곳만 수정. <strong>찾기</strong> —
          "수료 기준이 어디 있지?" 할 때 상수 이름으로 검색하면 끝.
        </p>
        <div className="tip">
          <b>과제로 연결</b> 우리 백엔드(Spring Boot)에도 맨몸 숫자들이 숨어 있어요.
          <strong> BE-05 티켓(매직넘버 상수 추출)</strong>이 그걸 찾아 이름을 지어 주는
          과제입니다. 힌트: 페이지 크기, 토큰 만료 시간 근처를 뒤져 보세요.
        </div>
      </Section>

      <Section n={7} title="코드리뷰 — 받는 자세, 하는 매너" sub="과녁은 코드지 사람이 아니다">
        <p>
          AWESOMEDEV에서 여러분의 코드는 <strong>코드리뷰</strong>를 거쳐 합쳐져요. 처음 리뷰를
          받으면 내 코드에 달린 빨간 댓글이 꼭 나에 대한 지적처럼 느껴지는데 — 여기서 제일 중요한
          문장을 드릴게요. <strong>코드 지적은 사람 지적이 아닙니다.</strong> 리뷰는 시험 채점이
          아니라, 두 사람이 한 코드를 같이 다듬는 <strong>합주 연습</strong>이에요. 틀린 음을
          짚어 주는 건 연주자를 미워해서가 아니라 무대를 잘 만들고 싶어서죠.
        </p>
        <Code>{CODE_REVIEW_MANNER}</Code>
        <ol className="olist">
            <li><strong>받을 때</strong> — 방어하지 말고 먼저 이해해요. "왜 이렇게 봤을까?"가 첫 질문. 이해가 안 되면 되묻는 게 예의예요(추측으로 고치는 게 무례).</li>
            <li><strong>받을 때</strong> — 리뷰어가 놓친 맥락이 있으면 감정 빼고 설명해요. "이렇게 한 이유는 ~때문인데, 그래도 바꾸는 게 나을까요?"</li>
            <li><strong>할 때</strong> — 명령 대신 질문·제안으로. "바꾸세요" 대신 "이렇게 하면 어떨까요?" 근거(왜)를 꼭 붙이고요.</li>
            <li><strong>할 때</strong> — 좋은 부분엔 칭찬 댓글을. 리뷰가 '혼나는 시간'이 아니라 '배우는 시간'이 되는 비결이에요.</li>
            <li><strong>둘 다</strong> — 취향과 기준을 구분해요. 동작이 틀린 건 고쳐야 하지만, 스타일 취향이 갈리면 팀 규칙을 따르거나 규칙을 새로 정하면 됩니다.</li>
        </ol>
        <div className="warn">
          <b>이것만은 금지</b> 리뷰 코멘트에 사람을 넣지 마세요. "이걸 왜 몰라요?",
          "기본인데요" 같은 말은 코드를 한 글자도 낫게 만들지 못하고 팀만 다치게 해요.
          반대로, 리뷰를 받았는데 아무 반응 없이 잠수하는 것도 매너 위반 — 모든 코멘트엔
          수정이든 답변이든 반응을 남기는 게 원칙입니다.
        </div>
      </Section>

      <Section n={8} title="실습 — 나쁜 코드를 직접 리팩터링" sub="배운 것 전부를 한 코드에 적용하기">
        <p>
          이제 배운 걸 손으로 확인할 시간이에요. 아래 코드는 멀쩡히 돌아가지만, 이 코스에서
          배운 문제를 <strong>최소 5개</strong> 품고 있습니다. 에디터에 붙여 넣고 직접
          고쳐 보세요 — 힌트를 먼저 펼치면 반칙!
        </p>
        <Code>{CODE_PRACTICE_BAD}</Code>
        <div className="tip">
          <b>직접 확인해 보기</b> ① 위 코드를 내 에디터에 붙여 넣고 문제 5개를 주석으로 표시한 뒤
          직접 리팩터링해 보세요. ② 다 고쳤다면 Gitea에 브랜치를 만들어 올리고 <strong>옆자리
          동료와 서로 코드리뷰를 주고받아 보세요</strong> — 섹션 7의 매너를 지켜서 코멘트를
          최소 2개씩! 같은 코드를 고쳤는데 서로 다른 답이 나오는 것까지가 이 실습의 목적이에요.
        </div>
        <Code>{CODE_PRACTICE_HINT}</Code>
        <div className="warn">
          <b>리팩터링의 철칙</b> 고치기 전과 후의 <strong>동작이 같아야</strong> 리팩터링이에요.
          동작을 바꾸고 싶은 유혹이 들면 참으세요 — 그건 리팩터링이 아니라 기능 변경이고,
          따로 나눠서(별도 커밋으로) 해야 리뷰어가 안 헷갈립니다.
        </div>
      </Section>

      <div className="step-card">
        <div className="step-body">
          <h3 style={{ marginBottom: 6 }}>🧹 여기까지 왔다면</h3>
          <p className="muted">
            이제 여러분은 <strong>읽는 사람의 물음표를 줄이는 법</strong>을 알아요 — 이름은
            명사와 동사로, 함수는 한 가지 일만, 주석은 "왜"만, 중복과 매직넘버는 한 곳으로,
            그리고 리뷰의 과녁은 언제나 코드라는 것까지. 배운 걸 바로 써먹을 곳도 준비돼
            있습니다 — <strong>FE-07(중복 카드 컴포넌트 추출)</strong>과
            <strong> BE-05(매직넘버 상수 추출)</strong> 티켓이 여러분을 기다려요. 코드를
            올리기 전에 <Link to="/learn/git-deep"><strong>Git과 협업 워크플로</strong></Link> 코스에서
            브랜치·PR 만드는 법을 먼저 익히면 리뷰 실습까지 한 번에 이어집니다.
          </p>
        </div>
      </div>
    </div>
  );
}
