diff --git a/.gitignore b/.gitignore index 09827ab..76dce5f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ yarn-error.log* # 로컬 실행 플랜 (실행 안내서, PR 본문에 녹임) # docs/ 밖으로 분리 — docs/ 안에 두면 autogenerated 사이드바에 노출됨 (로컬 dev 오염) /plans/ +/docs/plans/ +/docs/brainstorms/ diff --git a/docs/brainstorms/2026-04-20-readme-renewal-requirements.md b/docs/brainstorms/2026-04-20-readme-renewal-requirements.md deleted file mode 100644 index c636812..0000000 --- a/docs/brainstorms/2026-04-20-readme-renewal-requirements.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -date: 2026-04-20 -topic: readme-renewal ---- - -# README 리뉴얼 - -## Problem Frame - -현재 README는 초안 수준 — 비주얼 없음, 챕터 목록이 페이지 범위만 표기, 멤버 사진이 50px로 너무 작음. GitHub에서 프로젝트를 처음 보는 외부 개발자에게 스터디의 정체성과 콘텐츠 목적지를 즉각 전달해야 한다. - -## Requirements - -**비주얼 — 멤버 섹션** - -- R1. `스터디원.png`에서 배경 제거(rembg) → `static/img/members/study-members-nobg.png` 저장, README 최상단 히어로 배너로 사용 -- R2. 멤버 카드를 2열 HTML 테이블로 재구성 — GitHub 프로필 사진 80px + 🐾 이모지 + 이름(한국어) + 닉네임 + 연차 + 한 줄 설명 (hero.png의 캐릭터 설명 텍스트 그대로 사용) - -**README 구조 — 가독성** - -- R3. 중앙 정렬 타이틀 + 뱃지 행 (Docusaurus 사이트 링크 + Notion 링크) -- R4. "📖 스터디 노트 보러 가기" 명확한 CTA를 누끼 배너 아래 배치 -- R5. 챕터 섹션을 파트별 테이블로 교체 — 파트 이름 + 챕터 범위 + 테마 키워드 포함 -- R6. 개발 세팅 섹션 유지 (npm → pnpm으로 정확히 반영) - -**범위 제외** - -- 영문 README 추가 (별도 이슈) -- Docusaurus 사이트 본문 변경 없음 - -## Success Criteria - -- 외부 방문자가 README에서 스터디 성격, 멤버, 콘텐츠 링크를 30초 내 파악 가능 -- 누끼 사진이 GitHub 다크/라이트 모드 둘 다 자연스럽게 표시 - -## Key Decisions - -- 누끼 배너 + 2열 개인 카드 조합 선택: 단체 정체성 + 개인 목소리 동시에 살림 -- hero.png(일러스트)는 Docusaurus 사이트 히어로용으로 유지, README는 실제 사진 사용 - -## Next Steps - -→ 직접 작업 진행 (rembg 처리 + README 작성) diff --git a/docs/foundations/1-construction.mdx b/docs/foundations/1-construction.mdx index 2c8a9aa..0f55229 100644 --- a/docs/foundations/1-construction.mdx +++ b/docs/foundations/1-construction.mdx @@ -10,6 +10,10 @@ ai_assisted: - summary.lead - summary.bullets - verdict.rationale + - chapter1.book_summary + - chapter2.book_summary + - chapter3.book_summary + - chapter4.book_summary source: notion-pull source_page_id: 16dde71a-aa9f-83d2-a989-014e17b8d7de chapters_in_book: [1, 2, 3, 4] @@ -46,6 +50,18 @@ import DevilsAdvocate from '@site/src/components/DevilsAdvocate'; ## Chapter 1. Welcome to Software Construction +### 📖 원문 핵심 + +**구현(Construction)의 범위**: 소프트웨어 구현은 단순히 코딩만을 뜻하지 않아요. 상세 설계, 코딩, 디버깅, 단위 테스트, 통합 테스트가 모두 구현에 포함돼요. + +**구현은 유일하게 반드시 일어나는 활동**: 요구사항 분석이나 아키텍처 설계는 프로젝트 사정에 따라 생략되기도 하지만, 구현은 어떤 프로젝트에서도 건너뛸 수 없어요. + +**구현은 전체 개발 시간의 30~80%를 차지해요**: 프로젝트 규모에 따라 구현이 차지하는 비중이 크기 때문에, 구현 품질이 프로젝트 성패에 직접적인 영향을 미쳐요. + +**소스 코드가 유일하게 항상 최신 상태인 문서예요**: 요구사항 명세서나 설계 문서는 낡아지지만 소스 코드는 언제나 실제 동작을 반영하기 때문에, 코드 품질에 가장 공을 들여야 해요. + +**개인 생산성 격차가 구현 단계에서 가장 크게 벌어져요**: Sackman, Erikson, Grant의 연구에 따르면 프로그래머 간 생산성 차이가 구현 단계에서 10~20배에 달하며, 좋은 구현 기법을 익히면 이 격차를 줄일 수 있어요. + 의견은 저마다 다르지만, 네 장이 한 흐름으로 이어진다는 감각은 공유돼요. - -:::note 생략된 섹션 - -- **VotingBar**: 스터디원 투표 미작성 (votes 전원 null) -- **BestPickCallout**: 베스트 토론 미선정 (content·reason 모두 null) - -::: diff --git a/docs/foundations/2-design.mdx b/docs/foundations/2-design.mdx index 7dc0206..817229a 100644 --- a/docs/foundations/2-design.mdx +++ b/docs/foundations/2-design.mdx @@ -11,6 +11,8 @@ ai_assisted: - summary.bullets - verdict.rationale - checklist.text + - chapter5.book_summary + - chapter6.book_summary source: notion-pull source_page_id: 561de71a-aa9f-8296-b752-8162200acdb6 chapters_in_book: [5, 6] @@ -45,6 +47,18 @@ import DevilsAdvocate from '@site/src/components/DevilsAdvocate'; ## Chapter 5. Design in Construction +### 📖 원문 핵심 + +**설계는 사악한 문제(Wicked Problem)다**: 소프트웨어 설계는 풀어봐야 비로소 명확히 정의할 수 있는 문제로, 틀린 방향을 가보고 되돌아오는 과정 자체가 설계의 본질이에요. + +**소프트웨어의 제1 기술 명령은 복잡성 관리다**: 프로젝트가 기술적 이유로 실패할 때 그 근본 원인은 대부분 통제되지 않은 복잡성이며, 좋은 설계의 목표는 한 번에 다뤄야 할 복잡성의 양을 최소화하는 것이에요. + +**정보 은닉(Information Hiding)**: 각 클래스는 설계·구현 결정을 다른 클래스로부터 숨겨야 하며, 이 원칙이야말로 복잡성을 감추는 가장 강력한 휴리스틱이에요. + +**느슨한 결합(Loose Coupling)**: 클래스 간 연결을 최소화하도록 설계해야 하며, 연결이 늘어날수록 한 부분의 변경이 전체에 미치는 영향이 커져 유지보수 비용이 올라가요. + +**설계 계층(Levels of Design)**: 소프트웨어 설계는 시스템 전체 → 서브시스템/패키지 → 클래스 → 루틴 → 루틴 내부의 5개 수준에서 이뤄지며, 각 수준에서 독립적으로 복잡성을 통제해야 해요. + 의견은 저마다 다르지만, 두 장이 한 흐름으로 이어진다는 감각은 공유돼요. - -:::note 생략된 섹션 - -- **VotingBar**: 스터디원 투표 미작성 (votes 전원 null) -- **BestPickCallout**: 베스트 토론 미선정 (content·reason 모두 null) - -::: diff --git a/docs/good-code/1-routines.mdx b/docs/good-code/1-routines.mdx index c139d11..94cd759 100644 --- a/docs/good-code/1-routines.mdx +++ b/docs/good-code/1-routines.mdx @@ -13,6 +13,9 @@ authors: ai_assisted: - summary.lead - summary.bullets + - chapter7.book_summary + - chapter8.book_summary + - chapter9.book_summary - checklist.text source: notion-pull source_page_id: e6bde71a-aa9f-83d4-b14f-01adf26b8bd6 @@ -48,6 +51,18 @@ import DevilsAdvocate from '@site/src/components/DevilsAdvocate'; ## Chapter 7. High-Quality Routines +### 📖 원문 핵심 + +**루틴을 만드는 가장 중요한 이유**: 복잡도를 줄이기 위해서예요. 루틴 안에 세부 구현을 감춰두면, 호출하는 쪽에서는 내부 동작을 몰라도 사용할 수 있어요. + +**응집도(Cohesion)**: 루틴 내 연산들이 얼마나 밀접하게 관련돼 있는지를 나타내는 척도예요. 가장 좋은 형태는 루틴이 딱 하나의 일만 수행하는 기능적 응집(Functional Cohesion)이에요. + +**루틴 이름은 하는 일 전체를 서술해야 해요**: 이름이 길고 어색해진다면 루틴 자체에 부작용(side effect)이 있다는 신호이므로, 이름을 억지로 줄이기보다 루틴을 다시 설계하는 게 맞아요. + +**루틴 길이**: 연구 결과들을 종합하면 200줄 이내가 안전한 기준이에요. 길이 자체보다 응집도·중첩 깊이·변수 수 같은 복잡도 지표가 적절한 길이를 결정해요. + +**매개변수는 7개 이하로**: 심리학 연구에 따르면 인간이 동시에 추적할 수 있는 정보 덩어리는 약 7개예요. 그 이상이 필요하다면 루틴 간 결합이 너무 강하다는 설계 신호예요. + 의견은 저마다 다르지만, 세 장이 한 흐름으로 이어진다는 감각은 공유돼요. - -:::note 생략된 섹션 - -- **VotingBar**: 스터디원 투표 미작성 (votes 전원 null) -- **BestPickCallout**: 베스트 토론 미선정 (content·reason 모두 placeholder) - -::: diff --git a/docs/good-code/2-quality.mdx b/docs/good-code/2-quality.mdx index 31ed37a..bf60ad9 100644 --- a/docs/good-code/2-quality.mdx +++ b/docs/good-code/2-quality.mdx @@ -12,6 +12,10 @@ ai_assisted: - summary.lead - summary.bullets - checklist.text + - chapter20.book_summary + - chapter21.book_summary + - chapter22.book_summary + - chapter23.book_summary source: notion-pull source_page_id: 9e8de71a-aa9f-8363-b8b3-01ebd395678c chapters_in_book: [20, 21, 22, 23] @@ -48,6 +52,18 @@ import DevilsAdvocate from '@site/src/components/DevilsAdvocate'; ## Chapter 20. The Software-Quality Landscape +### 📖 원문 핵심 + +**품질 특성 간 트레이드오프**: 특정 특성을 최대화하려 하면 다른 특성과 충돌이 생기는데, 정확성을 강조하면 견고성이 낮아지고 적응성을 강조하면 견고성이 높아지는 식의 비대칭 관계가 존재해요. + +**명시적 품질 목표 설정**: Weinberg와 Schulman의 1974년 실험에서 팀에게 최적화할 목표를 명시적으로 알려줬더니 5개 팀 중 4개 팀이 해당 목표에서 1위를 차지했고, 이는 프로그래머가 목표를 알면 그대로 달성한다는 것을 보여줘요. + +**결함 탐지율 비교**: 단일 기법의 결함 탐지율은 최대 75%를 넘지 않으며 평균은 약 40%에 불과해서, 높은 탐지율을 달성하려면 여러 기법을 조합해서 사용해야 해요. + +**검사(Inspection)의 비용 효율성**: 코드 검사는 테스팅보다 결함을 더 많이, 더 저렴하게 발견하며 IBM 연구에서는 검사로 결함 1건 찾는 데 3.5 스태프-시간이 소요된 반면 테스팅은 15~25 스태프-시간이 필요했어요. + +**소프트웨어 품질의 일반 원칙**: 품질을 높이면 개발 비용이 낮아지는데, 디버깅과 재작업이 일반 개발 사이클에서 약 50%를 차지하므로 결함을 줄이는 것이 일정을 단축하는 가장 직접적인 방법이에요. + { ## Chapter 21. Collaborative Construction +### 📖 원문 핵심 + +**협업 구현(Collaborative Construction)의 가치**: 코드 리뷰, 인스펙션, 페어 프로그래밍 같은 협업 기법은 테스트보다 더 높은 비율의 결함을 더 낮은 비용으로 발견해요. + +**페어 프로그래밍 효과**: 비용이 인스펙션과 거의 동일한 수준이면서 결함 검출률은 40~60%에 달하며, 두 사람이 함께 코드를 작성하면 서로의 실수를 즉각 잡아낼 수 있어요. + +**공식 인스펙션(Formal Inspection)**: 사전 준비, 명확한 역할 분담, 결함 탐지에만 집중하는 원칙을 따르며, 모든 협업 기법 중 결함 검출률이 45~70%로 가장 높아요. + +**결함 탐지와 수정의 분리**: 인스펙션 회의 중에는 결함을 찾는 데만 집중하고 수정은 하지 않아요. 수정까지 같이 하면 회의가 길어지고 핵심 목적이 흐려지기 때문이에요. + +**협업 기법과 테스트는 상호 보완적이에요**: 협업 기법은 테스트가 잘 잡지 못하는 종류의 오류를 발견하기 때문에, 두 가지를 함께 사용해야 소프트웨어 품질을 충분히 보장할 수 있어요. + { ## Chapter 22. Developer Testing +### 📖 원문 핵심 + +**개발자 테스팅의 한계**: 테스팅은 오류를 감지하는 수단이지 소프트웨어 품질을 직접 개선하는 수단이 아니며, 개발자 테스트 한 단계가 발견하는 오류는 전체의 50% 미만에 그치는 경우가 많아요. + +**테스트 우선(Test-First) 작성**: 코드를 작성하기 전에 테스트 케이스를 먼저 작성하면 요건 문제를 조기에 발견하고 결함 수정 비용을 낮출 수 있어요. + +**경계값 분석(Boundary Analysis)**: 오류는 경계에 집중되므로 최솟값, 최댓값, 경계의 ±1 값(off-by-one)을 반드시 테스트해야 해요. + +**오류 집중 법칙**: 프로젝트 결함의 80%는 전체 클래스·루틴의 20%에 집중되며, 50%는 단 5%의 클래스에서 발생해요. + +**커버리지 모니터**: 커버리지 측정 없이 테스팅하면 실제로는 50~60%의 코드만 실행되므로, 커버리지 도구를 사용해 미실행 코드를 확인해야 해요. + { ## Chapter 23. Debugging +### 📖 원문 핵심 + +**디버깅 vs 테스팅**: 테스팅이 오류를 탐지하는 과정이라면, 디버깅은 이미 탐지된 오류의 근본 원인을 식별하고 수정하는 과정이에요. + +**결함을 학습 기회로**: 결함은 프로그램을 이해하고, 자신의 실수 패턴을 파악하고, 코드 품질을 점검하고, 문제 해결 방식을 개선할 수 있는 드문 기회예요. + +**의심 영역 좁히기**: 이진 탐색(binary search) 방식으로 프로그램의 절반씩 제거해 가며 결함 위치를 체계적으로 추적하면, 전체 코드를 훑는 것보다 훨씬 빠르게 결함을 찾을 수 있어요. + +**심리적 집합(Psychological Set)**: 개발자는 자신이 작성한 코드에서 보고 싶은 것만 보는 경향이 있어, 결함이 있는 구역을 무의식 중에 건너뛰는 맹점이 생겨요. + +**증상이 아닌 문제를 수정**: 특정 값에 대한 특수 케이스 처리처럼 증상만 덮는 수정은 코드를 점점 더 취약하게 만들므로, 항상 근본 원인을 이해한 후 수정해야 해요. + 의견은 저마다 다르지만, 네 장이 한 흐름으로 이어진다는 감각은 공유돼요. - -:::note 생략된 섹션 - -- **VotingBar**: 스터디원 투표 미작성 (votes 전원 null) -- **BestPickCallout**: 베스트 토론 미선정 (content·reason 모두 placeholder) - -::: diff --git a/docs/growth/1-refactoring.mdx b/docs/growth/1-refactoring.mdx index 689d1b2..824de95 100644 --- a/docs/growth/1-refactoring.mdx +++ b/docs/growth/1-refactoring.mdx @@ -12,6 +12,9 @@ ai_assisted: - summary.bullets - verdict.rationale - checklist.text + - chapter24.book_summary + - chapter25.book_summary + - chapter26.book_summary source: notion-pull source_page_id: a08de71a-aa9f-82e1-9b8b-01bfd7e45852 chapters_in_book: [24, 25, 26] @@ -46,6 +49,18 @@ import DevilsAdvocate from '@site/src/components/DevilsAdvocate'; ## Chapter 24. Refactoring +### 📖 원문 핵심 + +**리팩터링의 정의**: 외부 동작은 그대로 유지하면서 내부 구조를 개선하는 변경으로, Fowler는 이를 "프로그램의 외부 동작을 바꾸지 않으면서 내부 구조를 개선하는 방식으로 소프트웨어 시스템을 변경하는 과정"이라 정의해요. + +**소프트웨어 진화의 기본 원칙(Cardinal Rule)**: 변경이 품질을 향상시켜야 한다는 것이며, 품질이 저하되는 방향으로 시스템이 진화하고 있다면 이는 경고 신호예요. + +**코드 냄새 — 코드 중복**: 같은 코드가 두 곳 이상에 존재하면 한 곳을 수정할 때 나머지도 수정해야 하는 병렬 수정 문제가 생기므로, 중복 코드는 리팩터링의 가장 명확한 신호예요. + +**리팩터링 안전 수칙 — 작게 유지**: 리팩터링은 변경 범위를 작게 유지해야 모든 영향을 파악할 수 있고, 한 번에 하나씩 진행한 뒤 재컴파일과 재테스트를 해야 해요. + +**리팩터링 전략 — 작업 흐름에 통합**: 루틴이나 클래스를 추가하거나 버그를 수정할 때 관련 코드도 함께 리팩터링하면, 별도의 리팩터링 시간을 내지 않고도 코드 품질을 지속적으로 개선할 수 있어요. + 의견은 저마다 다르지만, 세 장이 한 흐름으로 이어진다는 감각은 공유돼요. - -:::note 생략된 섹션 - -- **VotingBar**: 스터디원 투표 미작성 (votes 전원 null) -- **BestPickCallout**: 베스트 토론 미선정 (content·reason 모두 null) - -::: diff --git a/docs/growth/2-craftsmanship.mdx b/docs/growth/2-craftsmanship.mdx index 9a71ba0..78c0e07 100644 --- a/docs/growth/2-craftsmanship.mdx +++ b/docs/growth/2-craftsmanship.mdx @@ -13,6 +13,10 @@ ai_assisted: - summary.bullets - verdict.rationale - checklist.text + - chapter31.book_summary + - chapter32.book_summary + - chapter33.book_summary + - chapter34.book_summary source: notion-pull source_page_id: cd0de71a-aa9f-82bf-bce9-813c189c3181 chapters_in_book: [31, 32, 33, 34] @@ -49,6 +53,18 @@ import DevilsAdvocate from '@site/src/components/DevilsAdvocate'; ## Chapter 31. Layout and Style +### 📖 원문 핵심 + +**레이아웃의 역할**: 레이아웃은 프로그램의 논리적 구조를 시각적으로 드러내는 수단이며, 코드의 동작에는 영향이 없지만 인간 독자의 이해도에는 결정적인 영향을 미쳐요. + +**포매팅의 기본 정리(Fundamental Theorem of Formatting)**: 좋은 레이아웃의 제1목표는 코드를 예쁘게 만드는 것이 아니라 코드의 논리적 구조를 정확하게 드러내는 것이에요. + +**들여쓰기(Indentation)**: 들여쓰기는 논리적으로 하위에 속하는 구문을 상위 구문 아래에 시각적으로 배치하는 방법이며, 연구 결과 2~4칸 들여쓰기가 가독성 점수를 20~30% 높였어요. + +**레이아웃의 일관성**: 특정 레이아웃 스타일의 세부 방식보다 팀 전체가 하나의 스타일을 일관되게 적용하는 것이 가독성과 유지보수성에 더 중요해요. + +**좋은 레이아웃의 4 기준**: 코드의 논리 구조를 정확히 표현하고, 그 표현을 일관되게 유지하고, 가독성을 높이며, 코드 수정 시 레이아웃이 쉽게 무너지지 않아야 해요. + 의견은 저마다 다르지만, 네 장이 한 흐름으로 이어진다는 감각은 공유돼요. - -:::note 생략된 섹션 - -- **VotingBar**: 스터디원 투표 미작성 (votes 전원 null) -- **BestPickCallout**: 베스트 토론 미선정 (content·reason 모두 null) - -::: diff --git a/docs/index.mdx b/docs/index.mdx index df5f824..40f779f 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -10,6 +10,8 @@ import MemberGrid from '@site/src/components/MemberGrid'; + + ## 이 사이트는 무엇인가요 함수랑 산악회 7명이 진행한 Code Complete 2판 스터디 노트를 외부에 공개한 저장소예요. Steve @@ -39,10 +41,6 @@ McConnell이 2004년에 쓴 책이지만 핵심 원칙(복잡도 관리·정보 | ✏️ 좋은 코드 쓰기 | 7-9장, 20-23장 | 좋은 루틴 · 방어적 프로그래밍 · PPP / 품질 · 협력 · 테스트 · 디버깅 | | 🔧 완성과 성장 | 24-26장, 31-34장 | 리팩터링 · 코드 튜닝 / 레이아웃 · 자기 설명 · 성격 · 장인정신 | -## 스터디원 - - - ## 기여하고 싶다면 오타·번역 제안·다른 시각의 의견은 [GitHub diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 8607975..8324d44 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -4,7 +4,7 @@ import type * as Preset from '@docusaurus/preset-classic'; const config: Config = { title: 'Code Complete 2판 한글 스터디', - tagline: '함수랑 동아리 — Code Complete 2nd Edition 함께 읽기', + tagline: 'FE 개발자 7명이 Code Complete 2판을 읽고, 2026년에도 살아있는지 직접 투표했어요', favicon: 'img/favicon.jpeg', future: { diff --git a/src/components/HeroSection.tsx b/src/components/HeroSection.tsx index 93af60e..527bcdc 100644 --- a/src/components/HeroSection.tsx +++ b/src/components/HeroSection.tsx @@ -1,62 +1,6 @@ import useBaseUrl from '@docusaurus/useBaseUrl'; -import MemberCard from './MemberCard'; -import type { MemberName } from './types'; import styles from './HeroSection.module.css'; -interface Member { - nickname: MemberName; - realName: string; - emoji: string; - role: string; - github?: string; - linkedin?: string; -} - -const members: readonly Member[] = [ - { - nickname: 'Alice', - realName: '소현', - emoji: '🦊', - role: '2년차 프론트엔드 개발자 (F-pretence)', - }, - { - nickname: 'Amber', - realName: '도윤', - emoji: '🐵', - role: '5년차 프론트엔드 개발자, 지금은 취준생', - }, - { - nickname: 'Crong', - realName: '규진', - emoji: '🦎', - role: '토큰 없으면 퇴근하는 1년차 프론트엔드 개발자', - }, - { - nickname: 'diego', - realName: '장원', - emoji: '🦉', - role: '운동은 안 하고 Claude에 월 50만원 쓰면서 데이터로 뇌 운동하는 5년차', - }, - { - nickname: 'Jay', - realName: '준근', - emoji: '🦜', - role: '에어팟 없으면 개발 못 하는 3년차 프론트엔드 개발자', - }, - { - nickname: 'Leo', - realName: '승완', - emoji: '🐻', - role: '아침밥 안 먹는 4년차 프론트엔드 개발자', - }, - { - nickname: 'zinii', - realName: '미진', - emoji: '🐿️', - role: 'Claude에게 직장을 빼앗기게 생긴 고민 개발자', - }, -]; - export default function HeroSection() { const heroImage = useBaseUrl('/img/members/hero.png'); @@ -64,20 +8,17 @@ export default function HeroSection() {

함수랑 산악회

-

7명이 읽고 토론한 Code Complete 2판

+

+ FE 개발자 7명이 Code Complete 2판을 읽고, 2026년에도 살아있는지 직접 투표했어요 +

- 2026년 프론트엔드 현업 관점으로 다시 본 Steve McConnell의 고전. 멤버 의견 · 투표 · - Devil's Advocate는 AI가 건드리지 않은 원본 그대로예요. + 2026년 프론트엔드 현업 관점으로 다시 본 Steve McConnell의 고전. 각자의 경험으로 읽고, 직접 + 투표하고, 치열하게 토론했어요.

함수랑 산악회 7인 캐릭터
-
- {members.map((m) => ( - - ))} -
); }