AWESOMEDEV 4d5c6d2e2b feat: 학습센터 '앱 개발' 카테고리 12강좌 추가 (안드로이드·iOS·크로스플랫폼)
다중 에이전트로 하우스 스타일(ReactIntroPage) 그대로 12개 강좌 페이지 생성:
앱의 지형 → 안드로이드 구조 → Kotlin → iOS 구조 → Swift → React Native →
Flutter → 앱 내비게이션 → 상태·데이터 → PWA → 앱 보안 → 스토어 배포

- 프레이밍: '웹 개발자가 보는 모바일' — 학생 React 지식을 다리로(RN·PWA),
  안드로이드·iOS 둘 다 정확히 다루되 인식·literacy 수준
- 각 페이지: hero·pill-nav·6~7섹션·SVG 다이어그램·tip/warn·다음코스 링크,
  색은 전부 테마 변수(하드코딩 0), 386~489줄
- courseCatalog에 lazy import 12 + '앱 개발' 카테고리(라우팅·허브·완료바 자동)
- 확인 퀴즈 60문항(코스당 5) — quizzes.json 병합 + 운영 DB 적재
- 총 코스 71→83

검증: 빌드 통과, 하우스스타일 일괄 점검(12/12 준수), 운영 E2E —
학습센터 앱개발 카테고리 노출·React Native 렌더·PWA 퀴즈 채점(정답 서버보관)·콘솔에러0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 15:36:28 +09:00

4152 lines
324 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[
{
"courseSlug": "ai-tools",
"question": "이 코스에서 AI 코딩 도구를 크게 두 갈래로 나눈 것은 무엇인가?",
"option1": "코드 리뷰형과 배포 자동화형",
"option2": "자동완성형과 챗 어시스턴트형",
"option3": "검색 엔진형과 문서 번역형",
"option4": "디버깅 전용형과 테스트 전용형",
"answerIndex": 1,
"explanation": "섹션 1에서 AI 코딩 도구를 에디터에서 다음 코드를 이어 써 주는 자동완성형(예: GitHub Copilot)과 대화창에 질문하면 답하는 챗 어시스턴트형(예: ChatGPT, Claude)의 두 갈래로 소개했다."
},
{
"courseSlug": "ai-tools",
"question": "코스에서 말하는 '좋은 질문의 3요소'로 올바르게 짝지어진 것은?",
"option1": "맥락 · 속도 · 정확성",
"option2": "목표 · 일정 · 결과",
"option3": "예의 · 간결함 · 끈기",
"option4": "맥락 · 제약 · 예시",
"answerIndex": 3,
"explanation": "섹션 2에서 좋은 질문의 3요소는 맥락(어떤 환경에서 뭘 만들다가), 제약(버전·라이브러리 등 조건), 예시(실제 코드·에러 메시지)라고 정리했다. 30분 룰에서 배운 멘토 질문법과 같은 구조다."
},
{
"courseSlug": "ai-tools",
"question": "다음 중 코스의 'AI 답변 검증 4단계' 체크리스트에 해당하지 않는 것은?",
"option1": "같은 질문을 여러 AI에게 던져서 답이 많이 겹치는 쪽을 고른다",
"option2": "한 줄 한 줄 읽고 무슨 코드인지 스스로 설명할 수 있는지 확인한다",
"option3": "로컬에서 정상 케이스 1개와 이상한 입력 1개로 실제 실행해 본다",
"option4": "낯선 API나 설정이면 공식 문서를 열어 근거를 교차 확인한다",
"answerIndex": 0,
"explanation": "섹션 3의 4단계는 '설명할 수 있는가, 우리 프로젝트에 맞는가, 실제로 돌아가는가, 근거를 교차 확인했는가'다. 여러 AI의 다수결로 고르는 방법은 체크리스트에 없다."
},
{
"courseSlug": "ai-tools",
"question": "AWESOMEDEV AI 사용 보안 수칙에 따르면, AI 입력창에 넣어도 되는 것은 무엇인가?",
"option1": "고객사 프로젝트의 소스 코드",
"option2": "서버 IP와 계정이 함께 적힌 접속 정보",
"option3": "교재용 학습 플랫폼(mirim-app)처럼 공개 가능한 학습 코드",
"option4": ".env 파일에 들어 있는 API 키와 토큰 값",
"answerIndex": 2,
"explanation": "섹션 5의 보안 수칙에서 공개 가능한 학습 코드, 내가 연습용으로 짠 코드, 경로·키 값을 지운 일반적인 에러 메시지는 넣어도 된다고 했다. 고객사 코드·비밀번호·접속 정보·개인정보는 절대 금지다."
},
{
"courseSlug": "ai-tools",
"question": "수습 B가 React 화면이 하얗게 나오면서 콘솔에 \"TypeError: Cannot read properties of undefined (reading 'map')\" 에러를 만났다. 코스의 실습 기준으로 가장 잘 쓴 프롬프트는?",
"option1": "\"에러가 났어요. 급하니까 빨리 고쳐 주세요. 부탁드립니다.\"",
"option2": "\"React로 코스 목록 화면을 만드는 중인데, 화면이 하얗게 나오고 이 에러 전문이 떠요. 12번째 줄 근처 코드와 제가 시도한 것도 붙일게요. 왜 undefined에서 map을 못 읽는지 원리도 설명해 주세요.\"",
"option3": "\"TypeError라는 게 정확히 무엇인지 사전적인 정의부터 하나하나 알려 주세요.\"",
"option4": "\"프로젝트 코드 전체를 붙여넣을 테니 알아서 전부 고친 완성본 파일만 만들어 주세요.\"",
"answerIndex": 1,
"explanation": "섹션 7의 실습처럼 맥락(React로 무엇을 만드는지)·증상(에러 전문)·코드(해당 줄 근처)·시도한 것을 담고 원리 설명까지 요청한 프롬프트가 좋은 질문이다. '고쳐줘'만 보내면 AI도 점쟁이가 된다고 했다."
},
{
"courseSlug": "api",
"question": "코스의 식당 비유에서 '메뉴판'에 해당하는 것은 무엇인가요?",
"option1": "요청(Request) — 손님이 적어 내는 주문서",
"option2": "API 문서 — 뭘 시킬 수 있는지 적힌 목록",
"option3": "백엔드와 DB — 요리를 만드는 주방",
"option4": "응답(Response) — 주방에서 나온 음식",
"answerIndex": 1,
"explanation": "섹션 1의 비유에서 메뉴판은 API 문서에 해당해요. 손님(프론트엔드)은 메뉴판에 있는 것만 주문할 수 있고, 그래서 정해진 요청에 정해진 응답이 오는 예측 가능한 약속이 됩니다."
},
{
"courseSlug": "api",
"question": "REST 규칙에서 '무엇을(자원)'과 '어떻게(행위)'는 각각 어디에 담나요?",
"option1": "자원은 HTTP 메서드에, 행위는 URL에 담는다",
"option2": "자원과 행위를 모두 요청 본문(body)에 담는다",
"option3": "자원은 URL에, 행위는 HTTP 메서드에 담는다",
"option4": "자원은 헤더에, 행위는 상태코드에 담는다",
"answerIndex": 2,
"explanation": "섹션 2의 핵심 두 줄 요약이에요. 자원은 명사로 URL에(/api/checklists/3), 행위는 GET·POST·PUT·DELETE 같은 메서드에 담아서, URL과 메서드만 봐도 무슨 일이 일어날지 읽히게 합니다."
},
{
"courseSlug": "api",
"question": "수습 사원이 로그인한 상태에서 관리자 전용 API를 호출했을 때, 서버가 돌려주는 상태코드는 무엇인가요?",
"option1": "400 — 요청 본문의 문법이 잘못되었다는 뜻",
"option2": "401 — 토큰이 없거나 만료되었다는 뜻",
"option3": "404 — 요청한 자원이 존재하지 않는다는 뜻",
"option4": "403 — 누군지는 알지만 권한이 없다는 뜻",
"answerIndex": 3,
"explanation": "섹션 6에서 401은 인증 실패(너 누구야?), 403은 인가 실패(누군진 아는데 자격이 없어)로 구분했어요. 로그인은 했지만 권한이 없는 경우이므로 403 Forbidden입니다."
},
{
"courseSlug": "api",
"question": "다음 중 코스에서 배운 JSON 문법 규칙으로 올바른 것은 무엇인가요?",
"option1": "이름표(key)는 항상 큰따옴표로 감싸야 한다",
"option2": "문자열에는 작은따옴표를 쓰는 것도 허용된다",
"option3": "마지막 항목 뒤에 쉼표를 붙여도 문제없다",
"option4": "// 를 사용해 주석을 자유롭게 달 수 있다",
"answerIndex": 0,
"explanation": "섹션 3의 규칙 4가지 중 하나로, key는 항상 큰따옴표로 감싸요. 반대로 작은따옴표, 마지막 항목 뒤 쉼표, 주석(//)은 모두 코스에서 '함정 주의'로 짚은 JSON 에러 원인입니다."
},
{
"courseSlug": "api",
"question": "동료가 체크리스트 삭제 기능을 'GET /api/deleteChecklist?id=3' 으로 만들었습니다. 코스 내용에 비추어 이 설계의 가장 큰 문제는 무엇인가요?",
"option1": "GET은 응답 본문을 받을 수 없어서 삭제 결과를 확인할 방법이 없다",
"option2": "GET을 안전하다고 믿는 크롤러가 링크를 따라가며 데이터를 지울 수 있고, 동사는 URL이 아니라 메서드에 담아야 한다",
"option3": "URL에 물음표(?)와 숫자를 함께 쓰면 REST에서 요청 자체가 거부된다",
"option4": "삭제는 반드시 POST로만 보내야 하며 DELETE 메서드는 조회 전용이다",
"answerIndex": 1,
"explanation": "섹션 2에서 배운 두 가지가 모두 어긋난 설계예요. 브라우저·검색엔진은 GET을 안전한 읽기로 믿고 미리 불러가기도 해서 크롤러가 데이터를 전부 지운 사고가 실제로 있었고, 자원은 명사(URL)·행위는 메서드로 표현해 DELETE /api/checklists/3 처럼 써야 합니다."
},
{
"courseSlug": "assembly",
"question": "부품 고르기의 '호환성 3대 체크'에서 CPU와 메인보드의 관계로 옳은 것은?",
"option1": "같은 제조사 제품이면 소켓이 달라도 장착할 수 있다",
"option2": "소켓 이름이 같은 CPU와 메인보드끼리만 장착할 수 있다",
"option3": "CPU가 더 최신 제품이면 어떤 메인보드에든 장착할 수 있다",
"option4": "DDR5를 지원하는 메인보드라면 CPU 종류는 상관없다",
"answerIndex": 1,
"explanation": "코스의 호환성 3대 체크 중 첫 번째로, CPU와 보드는 '같은 소켓 이름'끼리만 결혼할 수 있다고 설명해요. 예를 들어 LGA1700 CPU는 AM5 보드에 아예 꽂히지 않습니다."
},
{
"courseSlug": "assembly",
"question": "파워(PSU) 뒷면 스위치의 I와 O 표시에 대한 설명으로 옳은 것은?",
"option1": "O가 켜짐이고 I가 꺼짐이다",
"option2": "I와 O는 전압을 고르는 선택 스위치다",
"option3": "I가 켜짐이고 O가 꺼짐이다",
"option4": "I는 절전 모드이고 O는 완전 꺼짐이다",
"answerIndex": 2,
"explanation": "코스의 '초보가 자주 하는 실수'에서 파워 뒷면 스위치는 I가 켜짐, O가 꺼짐이라고 알려줘요(이진수의 1과 0). '전원 버튼을 눌러도 반응이 없어요'의 단골 범인입니다."
},
{
"courseSlug": "assembly",
"question": "첫 부팅에서 팬은 도는데 화면이 안 나올 때, 코스에서 가장 먼저 해보라고 안내하는 조치는?",
"option1": "부팅 USB를 만들어 윈도우를 다시 설치한다",
"option2": "CPU 쿨러를 분리해 서멀구리스를 다시 바른다",
"option3": "파워를 더 높은 용량의 제품으로 교체한다",
"option4": "RAM을 뽑았다가 \"딸깍\" 소리가 나게 다시 장착한다",
"answerIndex": 3,
"explanation": "화면이 안 나오는 원인 1위는 RAM이 덜 꽂힌 상태예요. 코스의 점검 순서에서도 팬은 도는데 화면이 안 나오면 RAM을 뽑았다가 '딸깍' 소리가 나게 재장착하라고 안내합니다."
},
{
"courseSlug": "assembly",
"question": "조립 마지막 단계인 '선정리'를 하는 진짜 이유로 코스에서 설명하는 것은?",
"option1": "케이스 안 공기 흐름을 확보해 냉각을 돕기 위해서",
"option2": "케이블끼리 닿으면 합선이 일어날 수 있어서",
"option3": "전면 패널 커넥터를 꽂을 공간을 만들기 위해서",
"option4": "케이블 길이를 줄여 파워 효율을 높이기 위해서",
"answerIndex": 0,
"explanation": "표준 9단계의 마지막인 선정리는 예쁘라고 하는 게 아니라 공기 흐름, 즉 냉각을 위해서라고 코스에서 설명해요. 케이블을 케이스 뒷면 공간으로 넘기고 케이블타이로 묶습니다."
},
{
"courseSlug": "assembly",
"question": "동아리 후배의 PC는 RAM 8GB에 SSD 256GB인데, IntelliJ와 도커를 같이 켜면 버벅인다고 해요. 코스의 '가상 업그레이드 계획' 기준으로 1순위 업그레이드는?",
"option1": "외장 그래픽카드 추가 — 화면을 그리는 건 GPU의 일이니까",
"option2": "RAM을 32GB로 증설 — 개발 도구는 메모리 대식가이고 가장 싸고 체감이 크니까",
"option3": "CPU 교체 — 컴파일 속도가 곧 개발 체감 속도니까",
"option4": "SSD를 1TB로 교체 — 저장 공간이 커지면 속도도 빨라지니까",
"answerIndex": 1,
"explanation": "코스의 업그레이드 계획 예시에서 개발 공부용 PC의 1순위는 RAM 8GB→32GB예요. 개발 도구는 메모리 대식가라서 가장 싸고 체감이 큰 업그레이드이기 때문이고, CPU는 소켓 문제로 사실상 새 PC가 되어 3순위입니다."
},
{
"courseSlug": "aws-intro",
"question": "코스에서 말하는 클라우드의 핵심 발상 전환으로 가장 알맞은 것은?",
"option1": "서버 컴퓨터를 더 싸게 대량 구매해서 소유하는 것",
"option2": "컴퓨터를 소유하는 대신 컴퓨팅 파워를 쓴 만큼 구독하는 것",
"option3": "모든 소프트웨어를 무료로 내려받아 쓰는 것",
"option4": "회사마다 데이터센터를 직접 지어 운영하는 것",
"answerIndex": 1,
"explanation": "코스 섹션 1은 공장이 발전기를 버리고 전기를 사 쓰게 된 것처럼, '컴퓨터를 소유'하는 시대에서 '컴퓨팅 파워를 구독'하는 시대로 바뀐 것이 클라우드 혁명의 핵심이라고 설명합니다."
},
{
"courseSlug": "aws-intro",
"question": "코스에서 S3(Simple Storage Service)를 한 줄로 소개한 내용은 무엇인가요?",
"option1": "DB를 AWS가 대신 설치하고 백업해 주는 관리형 데이터베이스",
"option2": "클릭 몇 번으로 만드는 가상 서버 인스턴스",
"option3": "이미지·백업·로그를 파일 단위로 넣고 꺼내는 용량 무제한 웹 창고",
"option4": "코드만 올리면 실행 환경을 알아서 준비해 주는 서비스",
"answerIndex": 2,
"explanation": "섹션 5에서 S3는 '용량 무제한 파일 창고'로, 서버 디스크와 달리 파일 단위로 넣고 꺼내는 웹 창고라고 소개합니다. DB를 대신 관리해 주는 것은 RDS입니다."
},
{
"courseSlug": "aws-intro",
"question": "인스턴스 이름 t3.medium에서 숫자 '3'이 뜻하는 것은?",
"option1": "3세대라는 뜻으로, 숫자가 클수록 최신이다",
"option2": "vCPU가 3개 달려 있다는 뜻이다",
"option3": "메모리가 3GB라는 뜻이다",
"option4": "크기 등급 중 3번째로 크다는 뜻이다",
"answerIndex": 0,
"explanation": "섹션 3의 '자동차 모델명 읽기' 비유에서 t는 패밀리(차종), 3은 세대(연식), medium은 크기(배기량)입니다. 숫자가 클수록 최신 세대로 보통 더 빠르고 저렴하다고 설명합니다."
},
{
"courseSlug": "aws-intro",
"question": "EC2 인스턴스를 중지(Stop)했을 때에도 계속 나가는 요금은 무엇인가요?",
"option1": "인스턴스의 시간당 사용료",
"option2": "프리 티어 가입 시 내는 기본 요금",
"option3": "t 패밀리의 CPU 버스트 크레딧 요금",
"option4": "EBS 디스크와 서버에 연결 안 된 탄력적 IP 요금",
"answerIndex": 3,
"explanation": "섹션 4에서 인스턴스를 끄면 시간당 사용료는 멈추지만, 데이터를 보관 중인 EBS 디스크와 서버에 연결되지 않은 탄력적 IP는 계속 과금된다고 설명합니다. '켜 놓고 잊어버림'과 함께 대표적인 요금 함정입니다."
},
{
"courseSlug": "aws-intro",
"question": "수습 A가 nslookup으로 edu.awesomedevapp.com의 IP를 확인해 두었다. 며칠 뒤 서버가 재시작됐는데도 같은 IP로 잘 접속된다. 코스 내용상 이를 가능하게 하는 부품은?",
"option1": "보안 그룹이 허락된 포트를 고정해 주기 때문",
"option2": "탄력적 IP가 '영구 도로명 주소'처럼 서버에 붙어 있기 때문",
"option3": "Caddy가 HTTPS 현관에서 요청을 대신 받아 주기 때문",
"option4": "EBS 디스크에 서버의 IP 주소가 저장되어 있기 때문",
"answerIndex": 1,
"explanation": "섹션 6에서 EC2는 재시작하면 IP가 바뀔 수 있는데, 탄력적 IP는 '영구 도로명 주소'를 서버에 붙여 두는 것이라 도메인이 늘 같은 곳을 가리킬 수 있다고 설명합니다. 보안 그룹은 경비실(방화벽), Caddy는 HTTPS 처리 담당입니다."
},
{
"courseSlug": "bandwidth",
"question": "이 코스의 도로 비유에서 '대역폭(bandwidth)'은 무엇에 해당할까요?",
"option1": "차 한 대가 달리는 최고 속도",
"option2": "도로의 폭, 즉 동시에 지나갈 수 있는 차선 수",
"option3": "출발지에서 목적지까지의 거리",
"option4": "도로 위에 있는 신호등의 개수",
"answerIndex": 1,
"explanation": "섹션 1에서 배웠듯 신호가 이동하는 속도는 어느 회선이나 거의 비슷하고, 진짜 차이는 동시에 얼마나 많은 데이터를 흘려보낼 수 있느냐입니다. 그래서 대역폭은 차의 빠르기가 아니라 도로의 폭(차선 수)에 비유됩니다."
},
{
"courseSlug": "bandwidth",
"question": "통신사 500Mbps 상품을 쓸 때, 브라우저 다운로드 창에 뜰 수 있는 이론상 최대 속도는 약 얼마일까요?",
"option1": "약 50 MB/s",
"option2": "약 125 MB/s",
"option3": "약 62.5 MB/s",
"option4": "약 500 MB/s",
"answerIndex": 2,
"explanation": "Mbps의 b는 bit, MB/s의 B는 Byte이고 1바이트는 8비트이므로 500Mbps ÷ 8 = 62.5MB/s입니다. 섹션 2의 '8배의 비밀' — 다운로드 창 숫자가 작아 보이는 건 고장이 아니라 단위 착시예요."
},
{
"courseSlug": "bandwidth",
"question": "기가 인터넷을 쓰는데도 온라인 게임에서 랙이 걸릴 수 있는 이유로 가장 알맞은 것은?",
"option1": "게임은 작은 데이터를 자주 주고받아서 대역폭보다 지연시간(ping)의 영향을 크게 받기 때문",
"option2": "게임은 큰 데이터를 한꺼번에 받아야 해서 기가 회선으로도 대역폭이 부족하기 때문",
"option3": "기가 회선은 다운로드 전용이라 게임의 업로드 데이터를 처리하지 못하기 때문",
"option4": "핑이 낮아질수록 대역폭이 함께 줄어드는 반비례 관계가 있기 때문",
"answerIndex": 0,
"explanation": "섹션 4에서 배운 내용으로, 게임은 '내 캐릭터 움직였어!' 같은 작은 메시지를 아주 자주 주고받는 왕복 시간(ping) 싸움입니다. 도로가 아무리 넓어도 서버가 멀면 지연시간은 높을 수 있어요."
},
{
"courseSlug": "bandwidth",
"question": "인터넷 속도를 '제대로' 측정하는 방법으로 옳은 것은?",
"option1": "숫자가 가장 크게 나오도록 해외 측정 서버를 골라서 잰다",
"option2": "저녁 8~11시에 한 번만 측정해서 그 값을 기준으로 삼는다",
"option3": "다운로드 숫자 하나만 기록하면 업로드와 핑은 볼 필요가 없다",
"option4": "다른 기기·앱의 다운로드를 끄고, 시간대를 바꿔 2~3번 측정해 경향을 본다",
"answerIndex": 3,
"explanation": "섹션 7의 체크리스트대로 측정도 조건 통제가 생명입니다. 다운로드·업로드·핑을 모두 기록하고, 혼잡 시간(저녁 8~11시)을 피해 시간대를 바꿔 여러 번 재서 한 번의 숫자가 아니라 경향으로 읽어야 해요."
},
{
"courseSlug": "bandwidth",
"question": "500Mbps 상품을 쓰는 집에서 벽 너머 방에서 와이파이로 측정했더니 다운로드 90Mbps, 핑 5ms가 나왔습니다. 가장 의심되는 병목 구간은?",
"option1": "통신사 회선 구간 — 계약 상품이 실제보다 낮게 설정되어 있다",
"option2": "내 PC와 공유기 사이 구간 — 벽 너머 와이파이가 속도를 깎고 있다",
"option3": "상대 서버 구간 — 해외 서버라 국제 구간에서 느려지고 있다",
"option4": "측정 도구 구간 — 핑이 5ms로 낮게 나온 것 자체가 측정 오류다",
"answerIndex": 1,
"explanation": "섹션 7의 마지막 예시처럼 '다운로드는 낮은데 핑은 좋은' 패턴이면 회선(②)이 아니라 집 안 구간(①)이 병목일 가능성이 큽니다. 섹션 6에서 가정의 1순위 용의자는 거의 항상 벽·거리에 약해지는 와이파이라고 배웠어요."
},
{
"courseSlug": "binary",
"question": "컴퓨터가 0과 1, 딱 두 가지 상태만 사용하는 가장 큰 이유는 무엇인가요?",
"option1": "2진수는 10진수보다 계산 공식이 단순해서 CPU 설계 비용이 줄어들기 때문",
"option2": "켜짐과 꺼짐 두 상태만 있으면 전압이 조금 흔들려도 확실히 구분할 수 있기 때문",
"option3": "전기의 세기를 10단계로 나누면 스위치(트랜지스터)가 10배 더 필요하기 때문",
"option4": "0과 1만 쓰면 데이터가 자동으로 압축되어 저장 용량이 줄어들기 때문",
"answerIndex": 1,
"explanation": "섹션 1 '왜 0과 1인가'의 핵심입니다. 상태가 딱 2개면 헷갈릴 수가 없어서, 전압이 살짝 흔들려도 켜짐인지 꺼짐인지 확실히 구분됩니다. 반대로 0~9를 전압 10단계로 표현하면 6이 7로 읽히는 사고가 납니다."
},
{
"courseSlug": "binary",
"question": "2진수 1011을 10진수로 바꾸면 얼마인가요?",
"option1": "9",
"option2": "10",
"option3": "11",
"option4": "13",
"answerIndex": 2,
"explanation": "섹션 2의 자리값 계산입니다. 2진수는 오른쪽 끝부터 자리값이 1, 2, 4, 8로 커지고, 1이 켜진 자리의 값만 골라 더하면 됩니다. 1011은 8 + 0 + 2 + 1 = 11입니다."
},
{
"courseSlug": "binary",
"question": "1KB가 1,000바이트가 아니라 1,024바이트인 이유로 코스가 설명한 것은 무엇인가요?",
"option1": "컴퓨터는 2의 거듭제곱으로 세는 게 편해서, 1,000에 가장 가까운 2¹⁰ = 1,024를 한 묶음으로 삼았기 때문",
"option2": "하드디스크 제조사들이 용량을 더 크게 보이게 하려고 국제 규격을 1,024로 정했기 때문",
"option3": "1바이트가 8비트이므로, 1,000에 가장 가까운 8의 거듭제곱이 1,024이기 때문",
"option4": "초기 컴퓨터의 메모리가 1,024바이트 단위로만 생산되어 그 관습이 굳어졌기 때문",
"answerIndex": 0,
"explanation": "섹션 3 '1024의 비밀'입니다. 컴퓨터는 2진수 세상에 살기 때문에 2를 10번 곱한 1,024가 1,000에 아주 가까운 '2진수식 천 단위'가 되어 한 묶음으로 씁니다. 참고로 제조사는 1,000 기준으로 계산해서 1TB 디스크가 윈도우에선 약 931GB로 보입니다."
},
{
"courseSlug": "binary",
"question": "'뷁' 같은 글자 깨짐(외계어) 현상이 생기는 원인으로 코스가 설명한 것은 무엇인가요?",
"option1": "글자 수가 128개를 넘으면 ASCII가 넘치는 글자를 자동으로 잘라내기 때문",
"option2": "한글은 3바이트라서 전송 중에 마지막 바이트가 자주 손실되기 때문",
"option3": "유니코드 번호표가 나라마다 달라서 같은 글자에 다른 번호가 붙기 때문",
"option4": "UTF-8로 포장한 데이터를 EUC-KR 같은 다른 규칙으로 풀어서 번호표가 엉뚱한 글자에 매칭되기 때문",
"answerIndex": 3,
"explanation": "섹션 4의 UTF-8 설명입니다. 인코딩은 유니코드 번호를 바이트로 담는 '포장법'이라서, 포장 규칙과 개봉 규칙이 같아야 합니다. 우리 회사가 인코딩을 처음부터 끝까지 UTF-8로 통일하는 이유이기도 합니다."
},
{
"courseSlug": "binary",
"question": "수민이는 코스에서 배운 대로 한 손의 손가락 5개를 스위치처럼 써서(접힘=0, 펴짐=1) 수를 표현하려고 합니다. 한 손으로 셀 수 있는 가장 큰 수는 얼마인가요?",
"option1": "15",
"option2": "31",
"option3": "32",
"option4": "63",
"answerIndex": 1,
"explanation": "섹션 1의 손가락 비유입니다. 스위치 5개는 2×2×2×2×2 = 32가지 상태를 만들 수 있어 0부터 31까지 셀 수 있습니다. 생일의 '일'(1~31)이 반드시 2진수 5자리 안에 들어가는 이유이기도 합니다."
},
{
"courseSlug": "cache-nosql",
"question": "코스에서 설명한 '캐시 히트(hit)'에 해당하는 상황은 무엇인가?",
"option1": "캐시에 데이터가 없어 DB까지 다녀온 뒤 응답하는 경우",
"option2": "원본 DB가 바뀌어 캐시의 낡은 사본을 지워야 하는 경우",
"option3": "캐시에 찾는 데이터가 있어 DB에 가지 않고 바로 응답하는 경우",
"option4": "브라우저가 강력 새로고침으로 캐시를 무시하고 요청하는 경우",
"answerIndex": 2,
"explanation": "섹션 2의 사물함 비유처럼 캐시에 찾는 게 있으면 히트, 없으면 미스입니다. 미스일 때는 DB에 다녀오면서 캐시에 사본을 복사해 두어 다음 요청부터 히트가 납니다."
},
{
"courseSlug": "cache-nosql",
"question": "코스에서 Redis가 빠른 비결로 든 두 가지 이유를 바르게 묶은 것은?",
"option1": "데이터를 메모리(RAM)에 두고, 키를 해시 계산 한 번으로 바로 찾기 때문",
"option2": "데이터를 디스크에 압축해 저장하고, 인덱스를 미리 정렬해 두기 때문",
"option3": "데이터를 표(테이블) 구조로 저장해 JOIN 연산이 강력하기 때문",
"option4": "모든 데이터를 브라우저에 복사해 두어 네트워크를 타지 않기 때문",
"answerIndex": 0,
"explanation": "섹션 3에서 Redis는 디스크보다 훨씬 빠른 메모리(RAM)에 데이터를 두고, 키를 해시로 계산해 위치를 바로 알아내서 데이터가 백만 개여도 찾는 시간이 거의 같다고 설명합니다."
},
{
"courseSlug": "cache-nosql",
"question": "캐시의 유통기한(TTL)을 1시간처럼 길게 잡았을 때 생기는 문제로 코스가 설명한 것은?",
"option1": "DB에 너무 자주 다녀오게 되어 캐시 효과가 떨어진다",
"option2": "메모리 대신 디스크에 저장되어 읽기 속도가 크게 느려진다",
"option3": "키를 해시로 찾을 수 없게 되어 검색 시간이 점점 늘어난다",
"option4": "원본이 바뀌어도 낡은 정보를 계속 보여줄 위험이 커진다",
"answerIndex": 3,
"explanation": "섹션 4의 우유 유통기한 비유입니다. TTL이 짧으면 신선하지만 DB에 자주 다녀오고, 길면 빠르지만 낡은 정보를 보여줄 위험이 커지는 트레이드오프가 캐시 무효화가 어려운 이유입니다."
},
{
"courseSlug": "cache-nosql",
"question": "실습에서 확인한 상태 코드 304 Not Modified가 뜻하는 것은 무엇인가?",
"option1": "서버가 요청받은 파일 전체를 본문에 담아 새로 보내 주었다",
"option2": "파일이 안 바뀌었으니 브라우저가 가진 사본을 그대로 쓰라는 답장이다",
"option3": "서버에 묻지 않고 메모리 캐시에서 바로 꺼내 썼다는 표시이다",
"option4": "요청한 파일이 서버에서 삭제되어 더 이상 찾을 수 없다는 뜻이다",
"answerIndex": 1,
"explanation": "섹션 8에서 304는 서버가 ETag 등으로 버전을 비교해 보고 '안 바뀌었으니 네 사본을 써'라고 본문 없이 답장만 보내는 신호, 즉 브라우저 캐시 히트의 영수증이라고 설명합니다."
},
{
"courseSlug": "cache-nosql",
"question": "학습 플랫폼을 설계한다. 학생마다 형식이 제각각인 자유 양식 학습일지, 날아가도 다시 만들 수 있는 로그인 세션, 절대 사라지면 안 되는 수강 기록 — 섹션 7의 결정 기준에 맞는 배치는?",
"option1": "학습일지는 Redis, 세션은 PostgreSQL, 수강 기록은 MongoDB",
"option2": "학습일지는 PostgreSQL, 세션은 MongoDB, 수강 기록은 Redis",
"option3": "학습일지는 MongoDB, 세션은 Redis, 수강 기록은 PostgreSQL",
"option4": "학습일지는 Redis, 세션은 MongoDB, 수강 기록은 PostgreSQL",
"answerIndex": 2,
"explanation": "섹션 7의 세 질문 그대로입니다. 사라지면 안 되는 원본(수강 기록)은 PostgreSQL, 날아가도 재생성 가능한 것(세션)은 Redis, 문서마다 모양이 다른 것(자유 양식 학습일지)은 MongoDB가 맡습니다."
},
{
"courseSlug": "cicd",
"question": "코스에서 설명하는 CI(Continuous Integration, 지속적 통합)의 핵심 의미로 가장 알맞은 것은?",
"option1": "서버에 새 버전을 올린 뒤 사람이 브라우저를 새로고침하며 직접 확인하는 것",
"option2": "코드를 저장소에 합칠 때마다(push할 때마다) 로봇이 자동으로 빌드하고 테스트하는 것",
"option3": "여러 사람의 코드를 한 달 치씩 모아 두었다가 한꺼번에 몰아서 검사하는 것",
"option4": "새 버전에서 장애가 났을 때 이전 버전으로 1분 안에 되돌리는 것",
"answerIndex": 1,
"explanation": "섹션 2의 내용으로, CI는 push될 때마다 로봇이 빌드와 테스트를 자동으로 하는 것입니다. '가끔 크게'가 아니라 '자주 조금씩' 검사하기 때문에 버그를 일찍, 싸게 잡을 수 있어요."
},
{
"courseSlug": "cicd",
"question": "CD(지속적 배포)가 도입된 뒤 사람에게 남는 일은 무엇이라고 코스는 설명하나?",
"option1": "빌드 결과물을 scp 명령으로 서버에 직접 올리는 일",
"option2": "서버에 SSH로 접속해서 돌고 있던 옛 버전을 중지하는 일",
"option3": "git push 명령 하나를 실행하는 일",
"option4": "배포가 끝난 뒤 헬스체크 로그를 사람이 눈으로 검사하는 일",
"answerIndex": 2,
"explanation": "섹션 3에서 CD 이후에는 빌드·검사·업로드·교체·확인이 전부 로봇 몫이 되고, 사람이 하는 일은 git push 하나만 남는다고 설명합니다. 손빨래가 세탁기 버튼이 되는 비유가 여기에 해당해요."
},
{
"courseSlug": "cicd",
"question": "코스가 파이프라인의 가장 중요한 성질로 꼽는 것은?",
"option1": "한 정거장이라도 실패하면 그 자리에서 멈춰 배포 단계까지 가지 않는다",
"option2": "모든 단계를 사람보다 훨씬 빠른 속도로 처리해 배포 시간을 줄인다",
"option3": "빌드와 테스트를 병렬로 동시에 실행해서 기다리는 시간을 아낀다",
"option4": "장애가 나면 원인을 자동으로 분석해서 코드까지 고쳐 준다",
"answerIndex": 0,
"explanation": "섹션 4의 핵심으로, 파이프라인은 컨베이어 벨트처럼 '실패하면 멈추는' 구조입니다. 그래서 테스트가 깨진 코드는 배포 단계에 구조적으로 도착할 수 없고, 불량품이 사용자에게 가기 전에 벨트가 멈춥니다."
},
{
"courseSlug": "cicd",
"question": "코스에서 우리 스택의 롤백(되돌리기)을 빠르게 만들어 주는 열쇠로 꼽은 것은?",
"option1": "장애가 나면 서버에 접속해 코드를 그 자리에서 고치고 다시 빌드하는 것",
"option2": "배포 전에 테스트를 여러 번 반복 실행해서 장애 자체를 아예 막는 것",
"option3": "Caddy가 이전 버전의 화면을 캐시로 저장해 두었다가 대신 보여 주는 것",
"option4": "Docker 이미지에 버전 태그를 붙여 보관해 두고 이전 이미지로 다시 실행하는 것",
"answerIndex": 3,
"explanation": "섹션 6에서 롤백의 열쇠는 Docker라고 설명합니다. v1.2, v1.3처럼 버전마다 이미지를 태그로 보관하면, 되돌리기가 '옛 이미지로 컨테이너 다시 실행' 한 줄이 되기 때문이에요."
},
{
"courseSlug": "cicd",
"question": "수습 A가 마지막 실습대로 우리 플랫폼의 배포 지도를 그리고 각 단계에 [사람]·[자동]·[위험] 표시를 붙였다. 코스의 기준에 따르면 ★(자동화 1순위)을 쳐야 하는 단계는?",
"option1": "[자동] 표시가 붙은, 이미 로봇이 처리하고 있는 단계",
"option2": "[사람]과 [위험] 표시가 함께 붙은, 실수가 잦고 실수하면 아픈 단계",
"option3": "[사람] 표시만 붙은 단계 중에서 시간이 가장 오래 걸리는 단계",
"option4": "지도의 맨 앞에 있는, 코드 수정 직후의 첫 번째 단계",
"answerIndex": 1,
"explanation": "섹션 7 실습의 3단계 규칙으로, [사람]+[위험]이 겹치는 단계에 ★을 칩니다. 사람 손이 필요해 실수가 잦고, 실수하면 사이트가 죽는 아픈 곳부터 자동화하는 것이 1순위이기 때문이에요."
},
{
"courseSlug": "clean-code",
"question": "이 코스는 모든 규칙이 한 문장으로 요약된다고 소개합니다. 그 문장은 무엇인가요?",
"option1": "코드는 무조건 짧게 써라",
"option2": "동작만 같으면 스타일은 자유다",
"option3": "읽는 사람의 물음표를 줄여라",
"option4": "주석은 많이 달수록 안전하다",
"answerIndex": 2,
"explanation": "섹션 1의 팁에서 이름 짓기부터 코드리뷰 매너까지 이 코스의 규칙 전부가 '읽는 사람의 물음표를 줄여라' 한 문장의 각론이라고 설명합니다."
},
{
"courseSlug": "clean-code",
"question": "코스에서 제시한 이름 짓기 규칙으로 올바른 것은 무엇인가요?",
"option1": "변수는 동사로, 함수는 명사로 짓는다",
"option2": "변수·상수는 명사로, 함수는 동사로 시작한다",
"option3": "모든 이름은 타자 속도를 위해 짧게 줄인다",
"option4": "임시 값에는 tmp, data 같은 이름을 쓴다",
"answerIndex": 1,
"explanation": "섹션 2의 규칙 3줄 요약 — 변수·상수는 명사(activeMembers 등), 함수는 동사로 시작(fetchCourses 등), a·tmp·data 같은 '아무 이름'은 금지입니다."
},
{
"courseSlug": "clean-code",
"question": "함수를 쪼개야 할지 판단할 때 코스가 제시한 진짜 기준은 무엇인가요?",
"option1": "함수가 5줄을 넘으면 무조건 쪼갠다",
"option2": "주석이 세 개 이상 달리면 쪼갠다",
"option3": "매개변수가 두 개를 넘으면 쪼갠다",
"option4": "하는 일을 한 문장으로 말할 때 '그리고'가 나오면 쪼갠다",
"answerIndex": 3,
"explanation": "섹션 3에서 기준은 줄 수가 아니라 \"이 함수가 하는 일을 '그리고' 없이 한 문장으로 말할 수 있는가\"라고 했습니다. 한 가지 일을 하는 20줄 함수는 괜찮습니다."
},
{
"courseSlug": "clean-code",
"question": "코스가 말하는 '좋은 주석'의 예로 가장 알맞은 것은 무엇인가요?",
"option1": "서버가 페이지 번호를 0이 아니라 1부터 세기 때문에 보정한다",
"option2": "i 값을 1만큼 증가시키는 코드다",
"option3": "activeMembers는 회원 목록을 담는 변수다",
"option4": "아래 반복문은 배열을 처음부터 끝까지 돈다",
"answerIndex": 0,
"explanation": "섹션 4에 따르면 좋은 주석은 코드만 봐서는 알 수 없는 '왜'(의도·사정·제약)를 남기는 주석입니다. 나머지 셋은 코드가 이미 말하는 '무엇'을 반복한 소음 주석입니다."
},
{
"courseSlug": "clean-code",
"question": "수습 동료가 handleSubmit 함수 하나에서 입력 검사, 데이터 가공, 서버 전송, 화면 뒷정리를 전부 처리하고 있습니다. 이 상황을 코스의 비유로 표현하면 무엇인가요?",
"option1": "받는 사람 없이 나만 알아보면 되는 일기 같은 코드다",
"option2": "이름표 대신 '그거, 저거'라고 써 붙인 창고다",
"option3": "한 사람이 주문받고 요리하고 서빙하고 설거지까지 하는 식당이다",
"option4": "게시판 세 곳에 같은 공지를 붙여 둔 학교다",
"answerIndex": 2,
"explanation": "섹션 3 '함수는 한 가지 일만'의 비유입니다. 한 함수가 네 가지 일을 하면 사고 나기 쉽고 일을 나눠 줄 수도 없으니, 일 하나당 함수 하나로 쪼개야 합니다."
},
{
"courseSlug": "cloud-network",
"question": "우리 학습 플랫폼의 EC2 서버가 실제로 위치한 AWS 리전은 어디인가?",
"option1": "ap-northeast-1 (도쿄 리전)",
"option2": "us-east-1 (미국 버지니아 리전)",
"option3": "ap-northeast-2 (서울 리전)",
"option4": "ap-northeast-2a (서울의 가용영역)",
"answerIndex": 2,
"explanation": "코스 1섹션에서 우리 서버는 사용자와 물리적으로 가까운 서울 리전(ap-northeast-2)에 있다고 배웠다. ap-northeast-2a는 리전이 아니라 그 안의 독립된 건물 그룹인 가용영역(AZ)이다."
},
{
"courseSlug": "cloud-network",
"question": "코스에서 설명한 VPC(Virtual Private Cloud)의 개념으로 가장 알맞은 것은?",
"option1": "클라우드 안에 친 가상의 울타리로, 다른 회사와 서로 전혀 보이지 않게 분리된 나만의 네트워크",
"option2": "서버 여러 대 앞에서 요청을 골고루 나눠 주며 교통정리를 하는 장치",
"option3": "전 세계 곳곳의 엣지 서버에 복사본을 미리 배치해 두는 전송 네트워크",
"option4": "도시 단위로 데이터센터 건물들을 묶어 놓은 지리적 구역",
"answerIndex": 0,
"explanation": "2섹션에서 VPC는 거대한 데이터센터 단지 안에 울타리를 치고 '여기부터는 우리 땅'이라 선언한 가상 네트워크로, 다른 회사 VPC와는 서로 절대 보이지 않는다고 설명했다. 지난 코스의 공유기 사설 네트워크(192.168.x.x)의 회사·클라우드 버전이다."
},
{
"courseSlug": "cloud-network",
"question": "데이터베이스처럼 절대 외부에 노출되면 안 되는 서버를 배치할 서브넷과 그 이유로 옳은 것은?",
"option1": "퍼블릭 서브넷 — 인터넷 게이트웨이와 연결되어 있어 관리자가 접속하기 편하기 때문",
"option2": "퍼블릭 서브넷 — 손님(사용자)의 요청을 가장 빠르게 받아 처리할 수 있기 때문",
"option3": "프라이빗 서브넷 — 퍼블릭 서브넷보다 IP 주소를 더 많이 확보할 수 있기 때문",
"option4": "프라이빗 서브넷 — 인터넷에서 들어오는 길 자체가 없어 해커가 두드려도 접근할 수 없기 때문",
"answerIndex": 3,
"explanation": "3섹션의 핵심 원칙 '손님 맞을 것만 대로변에, 금고(DB)는 안쪽 방에'에 해당한다. 프라이빗 서브넷은 인터넷 게이트웨이(정문)와 이어지지 않아 외부에서 직접 들어올 길이 없으며, DB를 퍼블릭에 두는 것은 실무에서 가장 흔한 보안 사고 중 하나라고 경고했다."
},
{
"courseSlug": "cloud-network",
"question": "코스에서 탄력적 IP(Elastic IP)를 '서버의 평생 전화번호'에 비유했다. 탄력적 IP가 해결해 주는 문제는 무엇인가?",
"option1": "서버가 살아 있는지 주기적으로 확인해 쓰러진 서버를 배분 명단에서 빼는 문제",
"option2": "EC2 서버를 껐다 켜면 공인 IP가 바뀌어 도메인이 허공을 가리키게 되는 문제",
"option3": "지구 반대편 사용자에게는 물리적 거리 때문에 응답이 느려지는 문제",
"option4": "한 데이터센터 건물에 정전이나 화재가 나면 서비스 전체가 멈추는 문제",
"answerIndex": 1,
"explanation": "4섹션에서 EC2는 껐다 켜면 공인 IP가 바뀔 수 있어 도메인이 가리키던 주소가 어긋나는 사고가 나는데, 탄력적 IP(우리 플랫폼은 3.36.160.246)를 고정으로 붙이면 재부팅하거나 새 서버로 갈아타도 같은 주소를 유지한다고 배웠다. 휴대폰 번호이동과 같은 원리다."
},
{
"courseSlug": "cloud-network",
"question": "우리 플랫폼에 브라질 지사가 생겨 CDN을 도입하기로 했다. 코스의 '편의점 체인' 비유에 따른 올바른 배치는 무엇인가?",
"option1": "개인별 학습 기록을 각 엣지 서버에 미리 복사해 두고, 이미지는 서울 서버가 매번 새로 보낸다",
"option2": "모든 데이터를 브라질 엣지 서버로 옮기고 서울의 원본 서버는 더 이상 쓰지 않는다",
"option3": "이미지·JS/CSS처럼 모두에게 똑같은 파일은 엣지에 두고, 사람마다 다른 학습 기록은 서울 원본 서버가 만든다",
"option4": "HTTPS 암호 해제만 엣지 서버에 맡기고, 이미지를 포함한 모든 요청은 전부 서울 서버로 보낸다",
"answerIndex": 2,
"explanation": "7섹션에서 CDN에는 이미지·동영상·JS/CSS처럼 자주 바뀌지 않는 것을 두고, 개인 학습 기록처럼 매번 달라지는 데이터는 원본 서버가 만들어야 한다고 했다. 본사 공장(원본 서버)은 그대로 두고 동네 편의점(엣지)에 똑같은 물건을 미리 깔아 두는 비유와 같다."
},
{
"courseSlug": "coding",
"question": "이 코스에서는 '코딩'을 무엇이라고 정의하나요?",
"option1": "컴퓨터가 스스로 배우도록 데이터를 주는 일",
"option2": "컴퓨터에게 일을 시키는 글쓰기",
"option3": "컴퓨터 부품을 조립해 성능을 높이는 작업",
"option4": "컴퓨터 화면을 예쁘게 꾸미는 디자인 작업",
"answerIndex": 1,
"explanation": "섹션 ①에서 코딩은 '컴퓨터에게 일을 시키는 글쓰기'라고 정의합니다. 컴퓨터는 적힌 대로만 움직이므로 무엇을, 어떤 순서로, 어떤 조건에서 할지 빠짐없이 적어야 합니다."
},
{
"courseSlug": "coding",
"question": "로그인 페이지 코드에서 setUsername 같은 set 함수로 상태(state) 값을 바꾸면 React는 어떤 일을 하나요?",
"option1": "바뀐 값을 서버에 자동으로 저장한다",
"option2": "브라우저 전체를 새로고침해서 초기화한다",
"option3": "값이 바뀐 것을 알아채고 화면을 다시 그린다",
"option4": "에러가 없는지 검사해 콘솔에 결과를 출력한다",
"answerIndex": 2,
"explanation": "섹션 ②의 useState 설명대로, set 함수로 값을 바꾸면 React가 '값이 바뀌었네? 화면도 다시 그리자'라고 알아챕니다. 입력창에 한 글자 칠 때마다 이 일이 일어납니다."
},
{
"courseSlug": "coding",
"question": "대시보드 체크리스트 코드에 나오는 done ? ' done' : '' 한 줄의 의미로 알맞은 것은?",
"option1": "체크된 항목이면 done이라는 CSS 클래스를 붙이고, 아니면 붙이지 않는다",
"option2": "체크된 항목이면 그 항목을 목록에서 바로 삭제한다",
"option3": "체크 여부와 상관없이 모든 항목에 done 클래스를 붙인다",
"option4": "체크된 항목이면 서버에 완료 알림 요청을 보낸다",
"answerIndex": 0,
"explanation": "섹션 ③에서 이 조건식은 '체크됐으면 done 클래스를 붙이고, 아니면 붙이지 마라'는 if문과 같다고 설명합니다. 체크할 때 글자에 취소선이 생기는 이유가 바로 이 한 줄입니다."
},
{
"courseSlug": "coding",
"question": "이 앱에서 '비밀번호가 맞는지' 같은 믿을 수 있는 판단을 프론트엔드가 아니라 백엔드(서버)가 맡는 이유는 무엇인가요?",
"option1": "브라우저에서는 자바스크립트로 비교 연산을 할 수 없기 때문",
"option2": "서버가 브라우저보다 계산 속도가 훨씬 빠르기 때문",
"option3": "프론트엔드는 화면을 그리는 기능이 아예 없기 때문",
"option4": "브라우저에서 도는 코드는 사용자가 열어보고 고칠 수 있기 때문",
"answerIndex": 3,
"explanation": "섹션 ④에서 브라우저 코드는 사용자가 얼마든지 열어보고 고칠 수 있어, 검사 코드를 지워버리면 통과할 수 있다고 설명합니다. 그래서 로그인·권한·저장 같은 판단은 전부 서버가 합니다."
},
{
"courseSlug": "coding",
"question": "수습생 A가 회원가입 화면에서 이미 다른 사람이 쓰고 있는 아이디를 입력하자 '이미 사용 중인 아이디예요'라는 문구가 떴습니다. 이 동작을 만들어 낸 규칙은 코스의 어느 부분일까요?",
"option1": "passwordHash 필드가 비밀번호를 해시로만 저장하는 보안 수칙",
"option2": "User 엔티티의 username 컬럼에 붙은 unique = true 규칙",
"option3": ".map()이 배열의 각 항목마다 화면을 하나씩 만들어 내는 반복 규칙",
"option4": "try/catch 구조로 실패 상황을 미리 준비해 두는 함수 작성법",
"answerIndex": 1,
"explanation": "섹션 ⑤의 '직접 확인해 보기'에서 다룬 상황입니다. users 테이블의 username에 unique = true가 붙어 있어 같은 아이디로 두 명이 가입할 수 없다는 규칙이 데이터베이스 차원에서 강제됩니다."
},
{
"courseSlug": "color",
"question": "색의 3속성 중 채도(Saturation)가 답하는 질문으로 가장 알맞은 것은?",
"option1": "\"무슨 색이야?\"",
"option2": "\"얼마나 밝아?\"",
"option3": "\"얼마나 쨍해?\"",
"option4": "\"얼마나 투명해?\"",
"answerIndex": 2,
"explanation": "섹션 1의 HSL 좌표에서 채도(S)는 0%(회색)부터 100%(쨍함)까지 색이 얼마나 쨍한지를 나타냅니다. \"무슨 색이야?\"는 색상(H), \"얼마나 밝아?\"는 명도(L)의 질문이에요."
},
{
"courseSlug": "color",
"question": "60-30-10 법칙에서 포인트색인 브랜드 블루 #2159C5를 쓰기에 알맞은 곳은?",
"option1": "배경과 카드 같은 넓은 바탕",
"option2": "버튼·링크 같은 강조 요소",
"option3": "본문 텍스트와 경계선 전체",
"option4": "아이콘을 포함한 화면의 절반",
"answerIndex": 1,
"explanation": "섹션 3에서 포인트색은 화면의 10%만 차지하는 '주인공'으로, 버튼·링크·강조에 씁니다. 파랑이 귀하니까(희소성) 눈에 띄는 것이고, 60%를 차지하면 아무것도 강조되지 않아요."
},
{
"courseSlug": "color",
"question": "색상환에서 보색(Complementary)에 대한 설명으로 옳은 것은?",
"option1": "정반대(180° 차이)의 색으로, 강조가 필요한 한 곳에만 쓴다",
"option2": "이웃(±30° 안팎)의 색으로, 배경 같은 넓은 면적에 어울린다",
"option3": "같은 색상에서 명도만 바꾼 색으로, 다크모드 전환에 쓴다",
"option4": "채도가 같은 색끼리의 묶음으로, 그래프 계열색에 쓴다",
"answerIndex": 0,
"explanation": "섹션 2에서 보색은 색상환에서 정반대(180° 차이)에 있는 색으로 대비가 강렬해 강조·경고에 딱이라고 배웁니다. 이웃한 색은 유사색으로, 넓은 면적에 어울려요. 암기법은 \"싸울 땐 맞은편, 친할 땐 옆자리\"."
},
{
"courseSlug": "color",
"question": "WCAG 기준으로 본문 텍스트가 통과해야 하는 최소 대비비(AA 등급)는?",
"option1": "3 : 1 이상",
"option2": "1.8 : 1 이상",
"option3": "21 : 1 이상",
"option4": "4.5 : 1 이상",
"answerIndex": 3,
"explanation": "섹션 6에서 WCAG AA 등급의 본문 텍스트 최소 기준은 4.5:1입니다. 3:1은 큰 텍스트(18pt+)의 기준이고, 흰 배경 위 #2159C5는 약 6.3:1로 본문 합격이에요."
},
{
"courseSlug": "color",
"question": "다크모드 화면에서 브랜드 블루 #2159C5 버튼이 어두운 배경에 묻혀 잘 안 보인다. 코스의 원칙대로 고치는 방법은?",
"option1": "채도를 100%로 올려 형광처럼 쨍하게 만든다",
"option2": "눈에 잘 띄는 주황 같은 다른 색상으로 교체한다",
"option3": "색상(H)은 그대로 두고 명도(L)만 올린 밝은 파랑을 쓴다",
"option4": "버튼 글자를 순수 흰색 #FFFFFF로 바꿔 번쩍이게 한다",
"answerIndex": 2,
"explanation": "섹션 7에서 다크모드용 파랑은 색상(H)을 유지한 채 명도(L)만 올린 색입니다. 색상까지 바꾸면 '다른 브랜드'가 되니 정체성은 지키고 조명 대응만 하는 것 — \"같은 사람인데 무대 조명에 맞춰 옷만 갈아입는\" 비유 그대로예요."
},
{
"courseSlug": "cpu-deep",
"question": "CPU가 명령어 하나를 처리할 때 반복하는 명령어 사이클의 올바른 순서는 무엇인가요?",
"option1": "해석(Decode) → 가져오기(Fetch) → 실행(Execute)",
"option2": "실행(Execute) → 해석(Decode) → 가져오기(Fetch)",
"option3": "가져오기(Fetch) → 해석(Decode) → 실행(Execute)",
"option4": "가져오기(Fetch) → 실행(Execute) → 해석(Decode)",
"answerIndex": 2,
"explanation": "섹션 1의 명령어 사이클입니다. CPU는 메모리에서 명령어를 가져오고(Fetch), 무슨 뜻인지 해석한 뒤(Decode), 실행하는(Execute) 세 박자를 1초에 수십억 번 반복해요."
},
{
"courseSlug": "cpu-deep",
"question": "코스의 주방 비유에서 '코어(Core)'와 '클럭(Clock)'은 각각 무엇에 해당하나요?",
"option1": "코어는 요리사 수, 클럭은 손 놀리는 속도",
"option2": "코어는 도마 옆 재료 선반, 클럭은 요리사 수",
"option3": "코어는 손 놀리는 속도, 클럭은 요리사의 손 놀림",
"option4": "코어는 주문 창구 수, 클럭은 냉장고까지의 거리",
"answerIndex": 0,
"explanation": "섹션 2의 주방 비유예요. 코어는 주방의 요리사 수(8코어 = 요리사 8명), 클럭은 손 놀리는 속도(4.5GHz = 1초에 45억 박자)에 해당합니다. 재료 선반은 캐시, 냉장고는 RAM이었죠."
},
{
"courseSlug": "cpu-deep",
"question": "캐시 3층 구조(L1~L3)에 대한 설명으로 옳은 것은 무엇인가요?",
"option1": "L3가 코어에서 가장 가깝고, 셋 중 가장 빠르다",
"option2": "L1은 코어들이 공유하는 큰 선반이라 용량이 가장 크다",
"option3": "CPU는 데이터를 RAM에서 먼저 찾고 없으면 L1으로 내려간다",
"option4": "코어에서 가까울수록 작고 빠르며, 멀수록 크고 느리다",
"answerIndex": 3,
"explanation": "섹션 3의 층수 규칙입니다. L1은 손 안의 재료처럼 가장 작고 빠르고, L3는 코어들이 공유하는 큰 선반이에요. CPU는 L1 → L2 → L3 → RAM 순서로 찾아봅니다."
},
{
"courseSlug": "cpu-deep",
"question": "CPU 온도가 90℃를 넘었을 때 일어나는 '스로틀링'에 대한 설명으로 옳은 것은 무엇인가요?",
"option1": "CPU가 고장 나기 직전이라는 신호이므로 즉시 교체해야 한다",
"option2": "CPU가 타 버리는 걸 막으려고 스스로 클럭을 낮추는 자기 보호 동작이다",
"option3": "쿨링 팬이 멈추면서 CPU가 강제로 전원을 차단하는 현상이다",
"option4": "온도를 낮추기 위해 CPU가 클럭을 오히려 더 높여서 일을 빨리 끝내는 기능이다",
"answerIndex": 1,
"explanation": "섹션 4의 스로틀링입니다. 마라톤 선수가 무리가 오면 스스로 페이스를 낮추듯, CPU가 클럭을 낮춰(예: 4.5 → 3.0GHz) 타 버리는 걸 막는 정상적인 자기 보호 동작이에요. 고장이 아닙니다."
},
{
"courseSlug": "cpu-deep",
"question": "친구가 \"내 컴퓨터는 i7인데 최신 i5를 쓰는 네 컴퓨터보다 왜 느리지?\"라고 물었습니다. 코스에서 배운 내용으로 가장 알맞은 대답은 무엇인가요?",
"option1": "i7이 i5보다 항상 빠르니까 다른 부품이 고장 난 게 분명하다",
"option2": "클럭(GHz) 숫자만 비교하면 되고, 등급 숫자는 성능과 관계없다",
"option3": "등급만큼 세대가 중요해서, 최신 세대 i5가 구형 i7을 이기는 건 흔한 일이다",
"option4": "인텔과 라이젠은 이름 문법이 달라서 두 CPU는 애초에 비교할 수 없다",
"answerIndex": 2,
"explanation": "섹션 5의 중고차 비유를 적용한 문제예요. 체급(그랜저냐 아반떼냐)만큼 연식(세대)이 중요해서, 최신 연식 중형차가 10년 된 대형차보다 잘 달리듯 최신 세대 i5가 구형 i7을 이기는 일은 아주 흔합니다."
},
{
"courseSlug": "data-modeling",
"question": "이 코스가 '미리 보는 핵심 문장'으로 제시한, 코스 전체를 한 줄로 줄인 문장은 무엇인가요?",
"option1": "테이블은 무조건 잘게 쪼갤수록 좋은 설계다",
"option2": "모든 데이터는 하나의 테이블에 모아서 관리한다",
"option3": "같은 사실은 딱 한 곳에만 적고, 필요한 곳에서는 번호(FK)로 가리킨다",
"option4": "관계는 종류와 상관없이 항상 중간 테이블로 표현한다",
"answerIndex": 2,
"explanation": "섹션 1의 팁에서 코스 전체를 한 줄로 줄인 문장으로 \"같은 사실은 딱 한 곳에만 적고, 필요한 곳에서는 번호(FK)로 가리킨다\"를 제시합니다. 무조건 쪼개는 것은 오히려 섹션 5에서 경계한 내용이에요."
},
{
"courseSlug": "data-modeling",
"question": "코스에서 기본키(PK)를 설명할 때 사용한 비유로 알맞은 것은 무엇인가요?",
"option1": "이름 — 누구나 알아보기 쉬운 값",
"option2": "학번 — 학교 안에서 절대 겹치지 않는 번호",
"option3": "지도 — 테이블 전체의 구조를 보여 주는 것",
"option4": "다리 — 두 테이블을 이어 주는 연결값",
"answerIndex": 1,
"explanation": "섹션 3에서 기본키는 '학번'에 비유됩니다. 이름은 동명이인이 있을 수 있지만 학번은 절대 겹치지 않아 모든 줄을 유일하게 찍어낼 수 있기 때문이에요. 지도는 ERD, 다리는 중간 테이블의 비유입니다."
},
{
"courseSlug": "data-modeling",
"question": "1:N 관계(예: 멘토 1명이 수습 여러 명을 담당)를 테이블로 표현할 때, 코스가 알려 준 규칙으로 옳은 것은 무엇인가요?",
"option1": "항상 N쪽(여럿 쪽) 테이블에 FK 한 칸을 둔다",
"option2": "항상 1쪽 테이블에 담당 대상 칸을 개수만큼 늘려 간다",
"option3": "두 테이블 사이에 반드시 중간 테이블을 새로 만든다",
"option4": "양쪽 테이블 모두에 서로를 가리키는 FK를 하나씩 둔다",
"answerIndex": 0,
"explanation": "섹션 4의 규칙은 \"1:N에서는 항상 N쪽(여럿 쪽)에 FK를 둔다\"입니다. 1쪽에 '담당수습1, 담당수습2...' 칸을 늘리는 것은 섹션 6의 나쁜 설계 냄새 2에 해당하고, 중간 테이블은 N:M 관계에서 필요해요."
},
{
"courseSlug": "data-modeling",
"question": "코스에서 이메일을 기본키(PK)로 쓰지 말라고 한 핵심 이유는 무엇인가요?",
"option1": "이메일은 문자열이라 숫자보다 검색 속도가 크게 느리기 때문",
"option2": "이메일은 동명이인처럼 여러 사람이 겹칠 수 있는 값이기 때문",
"option3": "이메일은 민감한 개인정보라 테이블에 저장하면 안 되기 때문",
"option4": "이메일은 바뀔 수 있는 값이라, 바뀌면 그걸 가리키던 FK가 모두 흔들리기 때문",
"answerIndex": 3,
"explanation": "섹션 3의 경고 박스에서 이메일은 유일하긴 하지만 '바뀔 수 있는 값'이라 PK가 바뀌면 그걸 가리키던 모든 FK가 함께 흔들린다고 설명합니다. 그래서 PK는 의미 없는 번호(id)로 두는 것이 정석이에요."
},
{
"courseSlug": "data-modeling",
"question": "실습에서 '쪽지 기능'을 설계하던 수습이 한 쪽지를 여러 명에게 보내는 단체 쪽지까지 지원하기로 했습니다. 코스에서 배운 대로라면 가장 알맞은 설계는 무엇인가요?",
"option1": "쪽지 테이블에 받는사람1, 받는사람2, 받는사람3 칸을 추가한다",
"option2": "받는 사람들의 이메일을 쉼표로 이어 붙여 한 칸에 저장한다",
"option3": "쪽지와 users 사이에 수신자 중간 테이블을 만들어 N:M로 잇는다",
"option4": "받는 사람 수만큼 쪽지 제목과 내용을 통째로 복사해 저장한다",
"answerIndex": 2,
"explanation": "섹션 7의 '흔한 함정 미리보기'에서 단체 쪽지(한 쪽지 → 여러 수신자)는 N:M 관계이므로 섹션 4의 중간 테이블이 답이라고 알려 줍니다. 번호 붙은 칸의 행진과 한 칸에 여러 값은 섹션 6의 나쁜 설계 냄새예요."
},
{
"courseSlug": "data-structures",
"question": "코스에서 브라우저의 '뒤로가기' 버튼과 똑같은 방식으로 동작한다고 소개한 자료구조는 무엇인가요?",
"option1": "큐 — 먼저 방문한 페이지부터 꺼낸다",
"option2": "배열 — 방문한 순서대로 번호를 붙인다",
"option3": "스택 — 나중에 쌓은 페이지부터 꺼낸다",
"option4": "트리 — 페이지를 부모-자식으로 잇는다",
"answerIndex": 2,
"explanation": "스택은 접시 탑처럼 맨 위에 쌓고 맨 위부터 꺼내는 LIFO(Last In, First Out) 구조입니다. 코스 섹션 3에서 브라우저 뒤로가기, Ctrl+Z, 콜 스택을 모두 스택의 예로 들었습니다."
},
{
"courseSlug": "data-structures",
"question": "해시맵(Map)이 배열과 달리 값을 '한 번에' 찾을 수 있는 이유로 코스가 설명한 것은 무엇인가요?",
"option1": "데이터를 항상 이름 순서로 정렬해 두기 때문에",
"option2": "해시 함수가 열쇠(key)로 보관 위치를 바로 계산해 주기 때문에",
"option3": "자주 찾는 값을 맨 앞 칸으로 미리 옮겨 두기 때문에",
"option4": "같은 데이터를 여러 칸에 복사해서 나눠 담아 두기 때문에",
"answerIndex": 1,
"explanation": "섹션 4의 사물함 비유처럼, 해시 함수는 열쇠를 넣으면 보관 위치가 계산되어 나오는 기계입니다. 저장할 때와 찾을 때 같은 계산을 하므로 뒤지지 않고 바로 그 칸으로 직행합니다."
},
{
"courseSlug": "data-structures",
"question": "자바스크립트 배열로 스택과 큐를 흉내낼 때, 코스에서 설명한 메서드 조합을 바르게 짝지은 것은 무엇인가요?",
"option1": "스택은 push와 shift, 큐는 push와 pop을 쓴다",
"option2": "스택은 pop과 shift, 큐는 push와 at을 쓴다",
"option3": "스택은 shift와 pop, 큐는 pop과 push를 쓴다",
"option4": "스택은 push와 pop, 큐는 push와 shift를 쓴다",
"answerIndex": 3,
"explanation": "두 그릇 모두 넣을 때는 push로 같고, 꺼내는 쪽만 다릅니다. 스택은 뒤에서 꺼내는 pop(LIFO), 큐는 앞에서 꺼내는 shift(FIFO)를 쓴다고 섹션 3에서 정리했습니다."
},
{
"courseSlug": "data-structures",
"question": "코스의 시간복잡도 설명에 따르면, O(n²)인 코드에서 데이터가 10배로 늘어나면 해야 하는 일의 양은 대략 몇 배가 되나요?",
"option1": "약 100배로 늘어난다",
"option2": "약 10배로 늘어난다",
"option3": "약 2배로 늘어난다",
"option4": "거의 그대로 유지된다",
"answerIndex": 0,
"explanation": "섹션 6의 '반 전체 악수' 비유처럼 O(n²)는 데이터가 10배면 일은 100배가 됩니다(30명 약 450번, 300명 약 45,000번). 그래서 반복문 안의 반복문이 데이터가 커질 때 화면을 버벅이게 만듭니다."
},
{
"courseSlug": "data-structures",
"question": "학교 매점 프로그램을 만든다고 해 봅시다. 주문이 들어온 순서 그대로, 먼저 주문한 학생부터 빵을 받아야 합니다. 코스의 비유에 따르면 이 주문 목록에 가장 어울리는 그릇은 무엇인가요?",
"option1": "스택 — 접시 탑처럼 최근 주문부터 처리한다",
"option2": "해시맵 — 사물함처럼 학생 이름으로 바로 찾는다",
"option3": "큐 — 급식 줄처럼 먼저 선 사람이 먼저 받는다",
"option4": "트리 — 폴더처럼 주문을 종류별 가지로 나눈다",
"answerIndex": 2,
"explanation": "먼저 온 주문이 먼저 처리되어야 하므로 FIFO(First In, First Out)인 큐가 맞습니다. 코스 섹션 3에서 큐를 '새치기 없는 급식 줄'에 비유하며 프린터 대기열, 서버의 요청 처리 줄을 예로 들었습니다."
},
{
"courseSlug": "debugging",
"question": "코스에서는 에러 메시지를 '사건 보고서'에 비유하며 세 가지 질문에 답해 준다고 했다. 다음 중 그 세 가지에 해당하지 않는 것은?",
"option1": "무슨 일이야? — 에러의 종류 (NullPointerException, TypeError 등)",
"option2": "왜 그랬는데? — 에러 옆의 설명 문장 (\"... is null\" 등)",
"option3": "어디서? — 파일 이름과 줄 번호 (UserService.java:42 등)",
"option4": "어떻게 고쳐? — 에러를 해결할 수정 코드 제안",
"answerIndex": 3,
"explanation": "섹션 1 '에러 = 단서'에서 에러 메시지는 종류(무슨 일)·설명 문장(왜)·파일과 줄 번호(어디서) 세 가지에 답해 준다고 했다. 고치는 방법까지 알려 주지는 않으며, 이 셋만 읽어도 문제의 절반은 푼 것이라고 설명한다."
},
{
"courseSlug": "debugging",
"question": "Spring Boot 콘솔에 수십 줄짜리 스택트레이스가 여러 덩어리로 이어져 나올 때, 코스가 알려 준 '진짜 원인'을 찾는 치트키는?",
"option1": "맨 위의 NestedServletException을 자세히 분석한다",
"option2": "Ctrl+F로 검색해 가장 아래쪽 \"Caused by\"를 찾는다",
"option3": "org.springframework로 시작하는 줄부터 차례로 읽는다",
"option4": "\"... 47 more\"로 접힌 부분을 모두 펼쳐서 읽는다",
"answerIndex": 1,
"explanation": "섹션 2에서 에러는 양파처럼 겹겹이 포장돼 올라오며, 맨 위 예외는 겉포장(증상)이고 진범은 거의 항상 가장 아래쪽 Caused by에 있다고 했다. 그래서 긴 로그에서는 Ctrl+F로 Caused by부터 검색하라고 안내한다."
},
{
"courseSlug": "debugging",
"question": "의심 가는 함수 안에 라벨을 붙여 console.log를 찍었는데, 콘솔에 그 로그가 아예 나타나지 않았다. 코스에 따르면 이 상황의 올바른 해석은?",
"option1": "그 함수 자체가 호출되지 않았다는 뜻으로, 용의자 절반을 지워 준 중요한 단서다",
"option2": "로그 출력이 실패한 것이므로 console.log를 다른 문법으로 다시 찍어야 한다",
"option3": "변수 값이 undefined라서 로그가 출력되지 못한 것이다",
"option4": "브라우저 캐시 문제이므로 시크릿 창에서 다시 확인해야 한다",
"answerIndex": 0,
"explanation": "섹션 4의 주의 박스에서 로그가 아예 안 찍히는 것도 중요한 단서라고 했다. '값이 이상하다'가 아니라 '이 함수 자체가 호출되지 않는다'는 뜻이며, 실패가 아니라 용의자 절반을 지워 준 수확이라고 설명한다."
},
{
"courseSlug": "debugging",
"question": "브라우저 F12 콘솔에 \"500 Internal Server Error\"가 떠 있다. 코스에서 배운 '프론트 문제인지 서버 문제인지 가르는 감각'에 따르면 다음으로 열어 봐야 할 곳은?",
"option1": "React 컴포넌트의 JSX에서 오타가 없는지 코드를 다시 읽는다",
"option2": "브라우저 콘솔에서 TypeError가 함께 떴는지 계속 지켜본다",
"option3": "백엔드(Spring Boot) 콘솔을 열어 스택트레이스를 확인한다",
"option4": "새로고침한 뒤 다른 브라우저에서도 같은 화면을 띄워 본다",
"answerIndex": 2,
"explanation": "섹션 3에서 TypeError·ReferenceError는 내 JS 코드 문제지만 404·500 같은 숫자는 서버와의 통신 문제라고 했다. 500은 서버 쪽에서 터진 것이므로 브라우저가 아니라 Spring Boot 콘솔의 스택트레이스를 봐야 한다."
},
{
"courseSlug": "debugging",
"question": "버튼을 누르면 화면이 하얗게 죽는다. 처리 흐름은 A(이벤트 핸들러) → B(fetch 호출) → C(응답 가공) → D(화면 그리기)이고, B와 C 사이에 찍어 둔 로그가 콘솔에 정상적으로 나타났다. 코스의 이분 탐색 요령대로라면 다음 한 수는?",
"option1": "A의 첫 줄에 로그를 찍어 이벤트가 들어오는지부터 다시 확인한다",
"option2": "범인을 C·D로 좁혔으니 그 남은 절반의 가운데에 로그를 찍는다",
"option3": "A부터 D까지 모든 줄에 로그를 찍어 전체 흐름을 한 번에 본다",
"option4": "fetch 호출(B)의 코드를 처음부터 한 줄씩 자세히 읽어 본다",
"answerIndex": 1,
"explanation": "섹션 6의 이분 탐색에서 가운데 검문소(로그)를 통과했으면 앞 구간(A·B)은 무죄이고 범인은 C·D 중에 있다고 했다. 이후에도 남은 절반의 가운데에 또 로그를 찍어 용의자를 반씩 줄여 가는 것이 요령이다."
},
{
"courseSlug": "design-refs",
"question": "코스에서는 3대 레퍼런스 사이트를 각각 비유로 소개해요. '미술관 전시장'에 비유되며, 완성도 높은 '한 장면'을 보기 좋지만 실제 서비스가 아닌 컨셉 작업이 많은 곳은 어디인가요?",
"option1": "비핸스",
"option2": "드리블",
"option3": "핀터레스트",
"option4": "피그마",
"answerIndex": 1,
"explanation": "섹션 2에서 드리블은 '미술관 전시장'으로, 색·타이포·분위기 같은 한 장면의 완성도를 보기 좋지만 보여주기용 컨셉이 많다고 설명해요. 비핸스는 발표회장, 핀터레스트는 스크랩북에 비유됩니다."
},
{
"courseSlug": "design-refs",
"question": "피그마 무드보드 만들기 4단계 중, 코스가 '이게 무드보드의 절반'이라고 할 만큼 중요하다고 강조한 단계는 무엇인가요?",
"option1": "새 파일을 만들고 이름 짓기",
"option2": "스크린샷을 캔버스에 붙여넣기",
"option3": "이미지 옆에 태그 메모 붙이기",
"option4": "비슷한 것끼리 프레임으로 묶기",
"answerIndex": 2,
"explanation": "섹션 4에서 가장 중요한 건 ③ 태그라고 말해요. 태그 없는 무드보드는 제목 없는 도서관 같아서 100장을 모아도 필요할 때 못 찾기 때문에, 저장하는 순간 한 단어라도 붙이는 습관이 무드보드의 절반이라고 강조합니다."
},
{
"courseSlug": "design-refs",
"question": "코스에서 '베끼기'와 '참고'를 스스로 구분해 보라며 제시한 판별 테스트 질문은 무엇인가요?",
"option1": "원본을 안 보고도 내 디자인을 다시 그릴 수 있는가?",
"option2": "결과물에 원본의 출처 URL을 표기했는가?",
"option3": "레퍼런스를 세 개 이상 섞어서 참고했는가?",
"option4": "색과 폰트를 원본과 다르게 바꿨는가?",
"answerIndex": 0,
"explanation": "섹션 3의 판별 테스트는 '원본을 안 보고도 다시 그릴 수 있는가'예요. YES면 원리를 이해한 참고, NO면 그림을 외운 것이라 베끼기에 가깝다고 설명하며, 출처 표기는 사용 허락이 아니라고 못 박습니다."
},
{
"courseSlug": "design-refs",
"question": "'나만의 수집 루틴' 섹션에서 디자인 실력이 자라는 공식으로 제시한 것은 무엇인가요?",
"option1": "하루 스크롤 시간 × 저장한 이미지 수",
"option2": "팔로우한 디자이너 수 × 활동 기간",
"option3": "무드보드 페이지 수 × 붙인 태그 수",
"option4": "많이 본 총량 × 분석한 횟수",
"answerIndex": 3,
"explanation": "섹션 6의 루틴 다이어그램은 실력이 '많이 본 총량 × 분석한 횟수'로 자란다고 말해요. 모으기만 하고 분석하지 않으면 그냥 스크랩 중독이라고 경고합니다."
},
{
"courseSlug": "design-refs",
"question": "수습생 지민이는 드리블에서 본 학습 앱 화면을 밑에 깔고 그대로 따라 그린 뒤, 이미지 아래에 원본 출처 URL을 적어 포트폴리오에 넣었어요. 코스의 기준으로 가장 옳은 판단은 무엇인가요?",
"option1": "출처를 밝혔으므로 문제없는 '참고'에 해당한다",
"option2": "연습 삼아 그린 것이므로 포트폴리오에 넣어도 괜찮다",
"option3": "출처 표기는 사용 허락이 아니므로, 트레이싱을 포트폴리오에 쓰면 안 된다",
"option4": "색과 문구만 바꾸면 저작권 문제가 사라지므로 수정 후 올리면 된다",
"answerIndex": 2,
"explanation": "섹션 3에서 트레이싱은 연습장 안에서만 허용되고 제출물·포트폴리오·실제 서비스에 쓰는 순간 문제가 된다고 해요. 또 '출처 표기 ≠ 사용 허락'이므로 URL을 적었다고 베끼기가 참고가 되지는 않습니다."
},
{
"courseSlug": "design-system",
"question": "코스에서는 디자인 시스템을 색·글꼴·간격·부품·사용 규칙을 모아 둔 것이라고 소개합니다. 이를 한마디로 무엇에 비유했나요?",
"option1": "제품의 설계 도면",
"option2": "제품의 부품 창고",
"option3": "제품의 문법책",
"option4": "제품의 사용 설명 영상",
"answerIndex": 2,
"explanation": "섹션 1에서 디자인 시스템을 '제품의 문법책'에 비유합니다. 문법이 있어야 여러 사람이 써도 한 사람이 쓴 글처럼 읽히듯, 약속이 있어야 열 명이 만들어도 한 사람이 만든 화면처럼 보이기 때문이에요."
},
{
"courseSlug": "design-system",
"question": "코스에서 말하는 '디자인 토큰(token)'의 뜻으로 가장 알맞은 것은 무엇인가요?",
"option1": "색·간격·글꼴 같은 디자인 결정에 이름을 붙인 변수",
"option2": "피그마 파일에 접근할 때 쓰는 인증 키",
"option3": "컴포넌트의 버전을 관리하는 고유 번호",
"option4": "버튼의 상태를 저장해 두는 자바스크립트 객체",
"answerIndex": 0,
"explanation": "섹션 2에서 토큰은 '디자인 결정에 이름을 붙인 변수'라고 정의합니다. #3B82F6 같은 값 대신 --color-primary라는 이름으로 부르기로 약속하는 것으로, global.css의 :root에 실물이 살고 있어요."
},
{
"courseSlug": "design-system",
"question": "피그마 컴포넌트와 React 컴포넌트의 짝이 어긋나기 시작하는 것을 막기 위해 코스가 제시한 규칙은 무엇인가요?",
"option1": "부품 변경은 디자이너가 먼저 끝낸 뒤 개발자에게 문서로 전달한다",
"option2": "React props 이름은 피그마 variant와 다르게 지어 역할을 구분한다",
"option3": "variant 추가는 분기별로 모아 두었다가 한꺼번에 코드에 반영한다",
"option4": "부품을 바꿀 땐 피그마와 코드를 같은 PR·같은 티켓에서 함께 바꾼다",
"answerIndex": 3,
"explanation": "섹션 4의 경고 박스에서, 피그마에만 variant가 추가되고 코드에는 없으면 두 세계가 갈라지기 시작하므로 '피그마와 코드를 같은 PR·같은 티켓에서 함께 바꾸는 것'이 규칙이라고 설명합니다."
},
{
"courseSlug": "design-system",
"question": "코스에서 소개한 '좋은 컴포넌트 문서에 꼭 들어가는 4가지'에 해당하지 않는 것은 무엇인가요?",
"option1": "언제 쓰는 부품인지 알려 주는 When",
"option2": "누가 언제 만들었는지 적는 제작자·날짜",
"option3": "하지 말아야 할 사용법을 적는 Don't",
"option4": "복사해서 바로 쓰는 예제 코드인 How",
"answerIndex": 1,
"explanation": "섹션 5에서 좋은 문서의 4요소는 When(언제 쓰나), How(예제 코드), Don't(하지 말 것), 그리고 상태·변형 전체 목록입니다. 제작자와 날짜는 이 목록에 없어요."
},
{
"courseSlug": "design-system",
"question": "수습 A가 과제 제출 버튼을 눌렀는데, 서버가 처리하는 동안에도 버튼이 그대로 눌려서 과제가 두 번 제출되는 사고가 났습니다. 버튼의 다섯 상태 중 어떤 설계가 빠진 걸까요?",
"option1": "hover — 마우스를 올리면 살짝 어두워지는 상태",
"option2": "loading — 스피너를 보여 주고 다시 못 누르게 잠그는 상태",
"option3": "active — 누르는 순간 꺼진 느낌을 주는 상태",
"option4": "default — 평소의 또렷한 기본 모습",
"answerIndex": 1,
"explanation": "섹션 3의 상태표에서 loading은 '처리 중(제출 직후 등)에 스피너를 띄우고 다시 못 누르게 잠그는 상태'입니다. 이 상태가 빠지면 제출 직후 버튼이 두 번 눌려 과제가 중복 제출되는 사고로 이어져요."
},
{
"courseSlug": "dns-deep",
"question": "재귀 조회의 여행에서 도메인의 진짜 IP를 최종적으로 답해 주는 서버는 무엇인가요?",
"option1": "루트 서버 — 여행의 출발점으로 전 세계 도메인을 다 외우고 있다",
"option2": "TLD 서버 — .com 같은 최상위 도메인을 관리하는 안내소이므로",
"option3": "리졸버 — 내 PC 대신 뛰어다니는 심부름꾼이 답을 만들어 낸다",
"option4": "권한(Authoritative) 서버 — 그 도메인의 진짜 명부를 가진 최종 담당자",
"answerIndex": 3,
"explanation": "섹션 1의 여행에서 루트와 TLD 서버는 \"담당자는 저쪽\"이라고 안내만 하고, 실제 IP는 도메인의 명부를 가진 권한 서버가 답합니다. 우리 도메인은 Route53이 그 역할이에요."
},
{
"courseSlug": "dns-deep",
"question": "DNS 레코드 타입 중 CNAME에 대한 설명으로 옳은 것은 무엇인가요?",
"option1": "이름을 IPv4 주소로 바꿔 주는, 여행이 끝나는 종착역 레코드다",
"option2": "이 도메인의 메일이 어디로 가야 하는지 알려 주는 레코드다",
"option3": "이름을 다른 이름으로 연결하는 별명 레코드로, 사슬 끝에는 A 레코드가 필요하다",
"option4": "도메인 소유 확인이나 스팸 방지 정책 같은 증명 문자열을 담는 레코드다",
"answerIndex": 2,
"explanation": "섹션 2에서 CNAME은 \"이름 → 다른 이름\"인 별명이라 한 정거장 더 가야 하고, 사슬의 맨 끝에는 반드시 A 레코드가 있어야 실제 IP에 도착한다고 배웠어요."
},
{
"courseSlug": "dns-deep",
"question": "TTL을 길게(예: 86400 = 하루) 설정하면 어떤 일이 생기나요?",
"option1": "DNS 질문이 줄어 빠르고 서버 부담이 적지만, IP를 바꿔도 최대 하루 동안 옛 주소로 가는 사람이 남는다",
"option2": "변경이 금방 퍼지는 대신 질문이 잦아져서 Route53 과금이 늘어난다",
"option3": "리졸버가 캐시를 아예 쓰지 않게 되어 매번 풀코스 여행을 다녀와야 한다",
"option4": "권한 서버가 하루에 한 번만 레코드를 갱신할 수 있도록 제한된다",
"answerIndex": 0,
"explanation": "섹션 3에서 TTL은 \"이 답을 몇 초 동안 믿고 재사용해도 되는지\"를 뜻하며, 길면 질문이 줄어 빠르지만 변경 사항이 캐시 만료 전까지 퍼지지 않는다고 배웠어요."
},
{
"courseSlug": "dns-deep",
"question": "hosts 파일에 적은 이름은 왜 DNS 서버 설정과 상관없이 항상 이길까요?",
"option1": "hosts 파일의 내용이 리졸버의 캐시를 강제로 덮어써서 바꾸기 때문이다",
"option2": "OS가 리졸버(DNS)에 물어보기 전에 hosts 파일을 먼저 확인하고, 답을 찾으면 뒤에는 묻지 않기 때문이다",
"option3": "hosts 파일에 적은 내용이 루트 서버의 명부에 자동으로 등록되기 때문이다",
"option4": "관리자 권한으로 저장한 파일은 네트워크 설정보다 항상 우선 적용되기 때문이다",
"answerIndex": 1,
"explanation": "섹션 4에서 이름 → IP 변환은 브라우저 캐시 → OS 캐시 → hosts 파일 → 리졸버 순서로 진행되고, 먼저 답을 찾으면 뒤에는 안 물어본다고 배웠어요."
},
{
"courseSlug": "dns-deep",
"question": "서버 IP를 바꾼 직후 사무실 PC에서는 새 사이트가 열리는데, 친구 폰에서는 아직 옛 주소로 접속됩니다. 코스 내용에 따른 가장 알맞은 진단은 무엇인가요?",
"option1": "서버 고장이므로 Route53의 레코드를 삭제하고 처음부터 다시 만들어야 한다",
"option2": "친구 폰의 hosts 파일이 조작된 것이므로 즉시 파일을 초기화해야 한다",
"option3": "친구 쪽 통신사 리졸버가 옛 답을 TTL 동안 캐시 중인 것으로, 캐시가 만료되면 자연히 해결된다",
"option4": "두 기기가 서로 다른 권한 서버를 쓰고 있으므로 통신사를 바꿔야 한다",
"answerIndex": 2,
"explanation": "섹션 3의 우리 회사 실화처럼 \"DNS 전파가 느리다\"의 정체는 세계 곳곳의 리졸버 캐시가 각자 만료되기를 기다리는 것이라, 고장이 아니며 기다리면 풀립니다."
},
{
"courseSlug": "docker-intro",
"question": "이 코스는 이미지와 컨테이너를 붕어빵에 비유해 설명합니다. 두 개념의 관계로 옳은 것은 무엇인가요?",
"option1": "이미지는 실행 중인 프로그램이고, 컨테이너는 그 프로그램의 설계도다",
"option2": "이미지와 컨테이너는 같은 것을 가리키는 두 가지 다른 이름이다",
"option3": "이미지는 붕어빵틀처럼 읽기 전용 설계도이고, 컨테이너는 그 틀로 찍어낸 실행 실체다",
"option4": "이미지는 컨테이너가 종료된 뒤에 남는 실행 기록(로그)을 모아 둔 것이다",
"answerIndex": 2,
"explanation": "섹션 2의 붕어빵 비유 그대로, 이미지는 실행에 필요한 모든 것을 구워 놓은 읽기 전용 틀이고 컨테이너는 그 이미지를 실행한 실체입니다. 틀 하나(postgres:17)로 여러 개의 컨테이너를 찍어낼 수 있어요."
},
{
"courseSlug": "docker-intro",
"question": "도커 5대 기본 명령 중, 실행 중인 컨테이너 '안으로 직접 들어갈' 때 쓰는 명령은 무엇인가요?",
"option1": "docker ps -a — 멈춘 컨테이너까지 전부 확인한다",
"option2": "docker exec -it <이름> bash — 컨테이너 안으로 들어간다",
"option3": "docker logs -f <이름> — 로그를 실시간으로 따라가며 본다",
"option4": "docker stop <이름> — 컨테이너를 정중하게 멈춘다",
"answerIndex": 1,
"explanation": "섹션 4에서 exec은 '문 열고 들어가기'로 기억하라고 했어요. 문제가 생기면 먼저 logs로 일기장을 읽고, 더 파야 할 때 exec으로 컨테이너 안에 직접 들어갑니다."
},
{
"courseSlug": "docker-intro",
"question": "실습에서 docker compose down으로 DB 컨테이너를 지웠다가 다시 띄웠는데, 어제 만든 hello 테이블과 데이터가 그대로 남아 있었습니다. 코스 내용에 따르면 그 이유는 무엇인가요?",
"option1": "컨테이너를 삭제하면 도커가 내부 데이터를 자동으로 백업해 두기 때문",
"option2": "postgres:17 이미지 자체에 사용자가 만든 데이터가 함께 저장되기 때문",
"option3": "docker compose가 삭제 직전에 데이터를 Git 저장소로 옮겨 두기 때문",
"option4": "데이터가 컨테이너 밖의 볼륨(practice-data)에 저장되어 컨테이너와 운명을 같이하지 않기 때문",
"answerIndex": 3,
"explanation": "섹션 6의 핵심입니다. 컨테이너는 지우면 안이 통째로 사라지는 일회용 도시락통이라, 데이터는 컨테이너 밖의 외장하드인 볼륨에 두어 컨테이너가 죽어도 살아남게 합니다."
},
{
"courseSlug": "docker-intro",
"question": "우리 docker-compose.yml에서 backend의 DB 주소가 IP가 아니라 jdbc:postgresql://db:5432/mirim처럼 그냥 'db'로 적혀 있습니다. 이게 동작하는 이유는 무엇인가요?",
"option1": "compose로 띄운 컨테이너들은 같은 가상 네트워크에 들어가고, 서비스 이름이 그대로 도메인 이름이 되기 때문",
"option2": "도커가 모든 컨테이너의 IP 주소를 항상 'db'라는 고정 별칭 하나로 통일해 주기 때문",
"option3": "'db'는 호스트 PC의 localhost를 가리키도록 도커가 예약해 둔 특별한 키워드이기 때문",
"option4": ".env 파일에 'db'라는 이름으로 실제 IP 주소가 미리 등록되어 주입되기 때문",
"answerIndex": 0,
"explanation": "섹션 5의 ⑪번 해설 내용입니다. compose가 만든 같은 가상 네트워크 안에서는 서비스 이름(db, backend)이 곧 도메인 이름이 되어, 네트워크 코스에서 배운 DNS가 컨테이너 세계 안에서도 작동하는 셈입니다."
},
{
"courseSlug": "docker-intro",
"question": "수습 개발자 A가 실습대로 docker compose up -d를 실행했더니 'port is already allocated' 에러가 났습니다. 알고 보니 A의 PC에는 로컬 PostgreSQL이 이미 5432번 포트를 쓰고 있었어요. 코스에서 배운 해결 방법은 무엇인가요?",
"option1": "ports를 \"5432:15432\"로 바꿔 컨테이너 안의 포스트그레스가 다른 포트를 듣게 한다",
"option2": "docker compose down -v로 볼륨까지 전부 지운 뒤 처음부터 다시 올린다",
"option3": "ports를 \"15432:5432\"처럼 바깥쪽(호스트) 번호만 바꿔서 포트 충돌을 피한다",
"option4": "depends_on 목록에 로컬 PostgreSQL을 추가해서 켜지는 순서를 맞춰 준다",
"answerIndex": 2,
"explanation": "포트 매핑은 '바깥:안쪽' 순서라서, 내 PC 쪽 포트가 이미 쓰이고 있으면 바깥 번호만 15432처럼 바꾸면 됩니다. 섹션 7의 회피 기술이자 섹션 8의 '흔한 막힘 포인트'로 소개된 내용이에요."
},
{
"courseSlug": "figma",
"question": "피그마 화면은 크게 세 부분으로 나뉩니다. 지금 선택한 요소의 크기·색·글꼴 같은 세부 정보를 보고 고치는 곳은 어디인가요?",
"option1": "왼쪽 레이어 패널",
"option2": "가운데 캔버스",
"option3": "오른쪽 속성 패널",
"option4": "상단 메뉴 바",
"answerIndex": 2,
"explanation": "섹션 2에서 배운 3분할 구조입니다. \"왼쪽에서 찾고, 가운데서 그리고, 오른쪽에서 다듬는다\" — 선택한 요소의 세부 속성은 오른쪽 속성 패널에서 고칩니다."
},
{
"courseSlug": "figma",
"question": "코스에서 \"섹션 4의 주인공\"이라고 소개한 단축키 Shift + A는 무엇을 하는 키인가요?",
"option1": "선택한 것들을 그룹으로 묶는다",
"option2": "선택한 것에 오토레이아웃을 씌운다",
"option3": "방금 만든 요소를 하나 더 복제한다",
"option4": "새 프레임(화면)을 하나 만든다",
"answerIndex": 1,
"explanation": "단축키 표에서 Shift+A는 오토레이아웃 씌우기입니다. 그룹 묶기는 Ctrl+G, 복제는 Ctrl+D, 프레임은 F가 맡습니다."
},
{
"courseSlug": "figma",
"question": "코스는 오토레이아웃을 \"피그마의 flexbox\"라고 설명하며 CSS와 짝지어 줍니다. 다음 중 옳게 짝지어진 것은 무엇인가요?",
"option1": "간격(Spacing) ↔ gap",
"option2": "패딩(Padding) ↔ flex-direction",
"option3": "방향(가로/세로) ↔ justify-content",
"option4": "정렬(Alignment) ↔ padding",
"answerIndex": 0,
"explanation": "섹션 4의 대응표에 따르면 간격(Spacing)은 CSS의 gap과 같은 개념입니다. 방향은 flex-direction, 패딩은 padding, 정렬은 justify-content/align-items와 짝을 이룹니다."
},
{
"courseSlug": "figma",
"question": "로그인 버튼을 Ctrl+Alt+K로 컴포넌트로 만들고 인스턴스를 여러 화면에 배치했습니다. 코스가 말하는 컴포넌트의 가장 큰 이점은 무엇인가요?",
"option1": "인스턴스마다 서로 다른 색을 자동으로 입혀 준다",
"option2": "버튼이 자동으로 CSS 코드 파일로 저장된다",
"option3": "인스턴스를 복제할 때마다 이름이 자동으로 정리된다",
"option4": "원본 하나만 고치면 모든 인스턴스가 한꺼번에 바뀐다",
"answerIndex": 3,
"explanation": "섹션 5의 \"마법 도장\" 비유처럼, 컴포넌트는 복사본(인스턴스)이 원본과 연결되어 원본만 수정하면 이미 찍힌 모든 자국이 함께 바뀝니다."
},
{
"courseSlug": "figma",
"question": "개발 수습생이 디자이너의 시안을 구현하다가 버튼의 정확한 파란색 색상 코드가 필요해졌습니다. 코스가 \"협업 매너이자 여러분의 속도\"라고 권한 행동은 무엇인가요?",
"option1": "디자이너에게 바로 메시지를 보내 색상 값을 물어본다",
"option2": "화면을 캡처해서 눈으로 가장 비슷한 색을 골라 쓴다",
"option3": "우측 상단 </> 토글로 Dev Mode를 켜고 요소를 클릭해 값을 직접 읽는다",
"option4": "버튼 이미지를 PNG로 내보내서 그대로 프로젝트에 붙여 넣는다",
"answerIndex": 2,
"explanation": "섹션 7 핸드오프에서 배운 내용입니다. Dev Mode를 켜고 요소를 클릭하면 색상 코드·글꼴·간격이 숫자와 CSS 형태로 표시되므로, 물어보기 전에 직접 읽는 것이 협업 매너입니다."
},
{
"courseSlug": "files",
"question": "코스에서는 파일시스템을 '디스크의 사서'에 비유합니다. 이 비유에서 파일시스템이 하는 핵심 역할은 무엇인가요?",
"option1": "디스크의 0과 1을 사람이 읽을 수 있는 글자로 번역해 준다",
"option2": "어떤 데이터가 디스크의 어느 구역에 있는지 장부(메타데이터)로 관리한다",
"option3": "파일을 저장할 때마다 자동으로 압축해서 공간을 아껴 준다",
"option4": "바이러스가 들어오지 못하게 디스크 입구를 지키는 보안 검사를 한다",
"answerIndex": 1,
"explanation": "섹션 1에서 디스크는 그냥 0과 1의 바다이고, 파일시스템(사서)이 '보고서.docx는 #4021부터'처럼 장부(메타데이터)를 얹어 관리한다고 배웠어요. 사서가 없으면 책(데이터)이 있어도 찾을 수 없습니다."
},
{
"courseSlug": "files",
"question": "photo.jpg 파일의 이름을 photo.txt로 바꾸면 어떤 일이 벌어지나요?",
"option1": "내용물은 그대로이고, Windows가 여는 프로그램만 메모장으로 바뀐다",
"option2": "파일 맨 앞의 매직 넘버가 텍스트용 바이트로 다시 쓰인다",
"option3": "JPG 데이터가 손상되어 다시 .jpg로 바꿔도 열리지 않는다",
"option4": "확장자와 내용을 맞추기 위해 사진이 자동으로 텍스트로 변환된다",
"answerIndex": 0,
"explanation": "섹션 2의 핵심: 확장자는 내용물이 아니라 이름표라서, 이름을 바꿔도 바이트는 1도 안 변해요. 단지 Windows가 어떤 프로그램으로 열지 판단하는 기준만 달라질 뿐이라 다시 .jpg로 되돌리면 멀쩡히 열립니다."
},
{
"courseSlug": "files",
"question": "현재 위치가 frontend/src/pages/ 폴더일 때, 코스 내용에 따르면 ../App.jsx 라는 상대 경로가 가리키는 것은?",
"option1": "pages 폴더 안에 있는 App.jsx",
"option2": "두 층 위로 올라간 frontend 폴더의 App.jsx",
"option3": "한 층 올라간 부모 폴더(src)에 있는 App.jsx",
"option4": "뿌리(루트)부터 시작하는 절대 경로라서 위치와 무관하다",
"answerIndex": 2,
"explanation": "섹션 3에서 ..은 부모 폴더, .은 현재 폴더를 뜻한다고 배웠어요. pages/에서 ../App.jsx는 한 층 올라간 src 폴더의 App.jsx를 가리키며, 상대 경로는 '지금 서 있는 곳' 기준이라는 게 포인트입니다."
},
{
"courseSlug": "files",
"question": "휴지통을 비우거나 Shift+Delete로 지운 파일을 복구 프로그램이 되살릴 수 있는 이유로, 코스의 설명과 맞는 것은?",
"option1": "Windows가 모든 파일을 자동으로 클라우드에 백업해 두기 때문에",
"option2": "휴지통 비우기는 파일을 C:\\$Recycle.Bin 폴더로 옮기기만 하기 때문에",
"option3": "삭제된 파일이 압축된 형태로 디스크 한쪽에 따로 보관되기 때문에",
"option4": "장부에서 '자리 비었음'만 표시할 뿐, 데이터는 덮어쓰기 전까지 그대로 남기 때문에",
"answerIndex": 3,
"explanation": "섹션 5에서 휴지통 비우기는 사서의 장부에서 지우개질만 하는 것이고, 책(데이터)은 새 파일이 덮어쓰기 전까지 서가에 그대로 남는다고 했어요. 복구 프로그램은 이 '장부엔 없지만 서가엔 남은 책'을 찾아냅니다. (휴지통으로 이사하는 건 Delete 단계의 일이에요.)"
},
{
"courseSlug": "files",
"question": "수습사원 A가 회의록.txt를 zip으로 압축하니 크기가 크게 줄었는데, 사진.jpg는 압축해도 거의 안 줄었습니다. 코스 내용으로 이 차이를 가장 잘 설명한 것은?",
"option1": "텍스트는 반복 패턴이 많아 잘 줄지만, JPG는 이미 자체 압축이 되어 더 짜낼 반복이 없어서다",
"option2": "zip은 글자 데이터 전용 형식이라 사진 파일은 원래 압축 대상이 아니어서다",
"option3": "사진 파일은 시스템 파일로 분류되어 Windows가 압축을 막아 두기 때문이다",
"option4": "텍스트는 손실 압축을 허용하지만 사진은 무손실만 가능해서 압축률이 낮은 것이다",
"answerIndex": 0,
"explanation": "섹션 6에서 압축은 '반복되는 패턴을 짧은 표현으로 바꿔치기'하는 것이라 반복 많은 글은 팍팍 줄고, 사진·영상은 이미 자기 방식으로 압축돼 있어 거의 안 줄어든다고 배웠어요. '직접 확인해 보기' 실습이 바로 이 실험입니다."
},
{
"courseSlug": "firewall",
"question": "코스에서 방화벽을 '건물 정문의 문지기'에 비유한 이유로 가장 알맞은 것은?",
"option1": "서버에 몰리는 트래픽 속도를 조절해 여러 서버로 분산해 주기 때문에",
"option2": "드나드는 데이터에게 출처와 목적지 포트를 물어 규칙표와 대조한 뒤 통과시키거나 차단하기 때문에",
"option3": "서버에 저장된 데이터를 암호화해서 도둑이 훔쳐도 읽지 못하게 만들기 때문에",
"option4": "바이러스에 감염된 파일을 찾아내 자동으로 치료까지 해 주기 때문에",
"answerIndex": 1,
"explanation": "섹션 1에서 방화벽은 드나드는 모든 데이터에게 \"어디서 왔죠? 몇 호(포트)에 가시죠?\"를 묻고 규칙표와 대조해 통과·차단하는 문지기로 설명됩니다. 규칙표에 없으면 기본은 차단이에요."
},
{
"courseSlug": "firewall",
"question": "코스 설명에 따르면 '인바운드(Inbound)' 검사에 대한 설명으로 옳은 것은?",
"option1": "서버에서 밖으로 나가는 연결을 검사하며, 악성코드의 정보 유출을 잡는 마지막 그물이다",
"option2": "같은 서버 안의 프로그램끼리 주고받는 내부 연결을 검사하는 것이다",
"option3": "관리자가 SSH로 접속할 때만 예외적으로 동작하는 특별 검사다",
"option4": "밖에서 서버로 들어오는 연결을 검사하며, 공격 대부분이 이 방향이라 규칙이 빡빡하다",
"answerIndex": 3,
"explanation": "섹션 1에서 인바운드는 밖에서 안으로 '들어오는 손님' 검사이고, 공격이 대부분 이 방향으로 오기 때문에 규칙을 빡빡하게 둔다고 설명합니다. 밖으로 나가는 연결을 검사하는 쪽은 아웃바운드예요."
},
{
"courseSlug": "firewall",
"question": "포트가 진짜로 '열려 있다'고 말하려면 동시에 성립해야 하는 두 가지 조건은?",
"option1": "그 포트에서 귀 기울이는 프로그램이 실행 중이고, 방화벽이 그 포트로의 접속을 허용해야 한다",
"option2": "그 포트 번호가 1024보다 작아야 하고, HTTPS 인증서가 미리 발급되어 있어야 한다",
"option3": "방화벽에 허용 규칙이 있어야 하고, 최근에 그 포트로 접속한 기록이 남아 있어야 한다",
"option4": "관리자가 서버에 로그인해 있어야 하고, 아웃바운드 규칙도 함께 열려 있어야 한다",
"answerIndex": 0,
"explanation": "섹션 2의 핵심입니다. 방 안에 손님을 맞을 프로그램이 실제로 실행 중이고(방에 사람이 있고), 방화벽이 그 포트로 가는 길을 허용해야(문지기가 통과시켜야) 해요. 둘 중 하나라도 아니면 밖에서는 연결할 수 없습니다."
},
{
"courseSlug": "firewall",
"question": "AWESOMEDEV 서버(AWS EC2)의 보안그룹에서 전 세계(0.0.0.0/0)가 아니라 지정한 IP에서만 접속을 허용하는 포트는?",
"option1": "443 — 웹 서비스를 제공하는 HTTPS 창구",
"option2": "3000 — Gitea 웹과 clone에 쓰이는 문",
"option3": "22 — 서버를 원격 조종하는 SSH 관리자 전용 뒷문",
"option4": "80 — Caddy가 443으로 안내해 주는 HTTP 입구",
"answerIndex": 2,
"explanation": "섹션 4의 실제 규칙표에서 80·443·3000은 전 세계에 공개하지만, SSH(22)는 뚫리면 서버 전체를 내주는 관리자 전용 뒷문이라 지정한 IP에서 온 접속만 통과시키도록 잠가 두었습니다."
},
{
"courseSlug": "firewall",
"question": "수습 개발자가 기능 테스트를 위해 서버의 PostgreSQL 포트(5432)를 전 세계에 잠깐 열어 두고 그대로 퇴근했다. 코스 내용에 비추어 가장 올바른 판단은?",
"option1": "DB는 계정과 비밀번호로 보호되므로 다음 출근 때 닫아도 위험은 거의 없다",
"option2": "포트 스캔 봇이 열린 문을 금방 찾아내므로, 최소 권한 원칙에 따라 즉시 다시 닫아야 한다",
"option3": "아웃바운드 규칙만 잠겨 있으면 데이터가 밖으로 나갈 수 없으니 그대로 둬도 된다",
"option4": "5432는 원래 전 세계 공개가 기본값이라 보안그룹 방침과 어긋나는 일이 아니다",
"answerIndex": 1,
"explanation": "섹션 5의 경고 그대로예요 — 잠깐 연 문은 다시 닫는 것까지가 한 세트입니다. 공격 봇은 모든 서버의 포트를 자동으로 두드리고 있고(섹션 6의 포트 스캔), 우리 방침에서 5432는 외부에 존재 자체를 숨기는 닫힌 문이어야 합니다."
},
{
"courseSlug": "git-deep",
"question": "이 코스에서 설명하는 '커밋'의 본질로 가장 알맞은 것은?",
"option1": "마지막 커밋 이후 바뀐 부분(변경분)만 골라 저장한 기록",
"option2": "브랜치 하나를 통째로 압축해 보관해 두는 백업 파일",
"option3": "그 순간 프로젝트 전체를 통째로 찍은 스냅샷(사진) 한 장",
"option4": "원격 저장소에 올리기 위해 임시로 묶어 둔 파일 묶음",
"answerIndex": 2,
"explanation": "섹션 1 '커밋 = 스냅샷'에서 커밋은 변경분 기록이 아니라 프로젝트 전체를 찍은 사진 한 장이라고 설명해요. 안 바뀐 파일은 이전 사진 것을 재활용해서 빠르고 용량도 작습니다."
},
{
"courseSlug": "git-deep",
"question": "단체 사진 비유에서 \"사진 찍을 사람 이리 모여!\" 하고 줄을 세운 상태에 해당하는 Git 단계는?",
"option1": "스테이지 — git add로 커밋에 담을 파일을 골라 둔 상태",
"option2": "작업 폴더 — 교실에서 각자 코드를 고치고 있는 상태",
"option3": "저장소 — 커밋되어 사진첩에 정식 보관된 상태",
"option4": "원격 저장소 — push가 끝나 서버에 올라간 상태",
"answerIndex": 0,
"explanation": "섹션 1의 3단계 비유에서 작업 폴더는 교실에서 노는 상태, 스테이지는 줄 세운 상태, 커밋은 사진첩 보관이에요. git add를 따로 두는 이유는 고친 것 중 일부만 골라 한 커밋에 담기 위해서입니다."
},
{
"courseSlug": "git-deep",
"question": "머지 중 충돌이 난 파일에서 <<<<<<< HEAD 부터 ======= 사이에 적혀 있는 내용은 무엇인가?",
"option1": "합치려고 하는 상대 브랜치에서 고친 내용",
"option2": "내 우주, 즉 현재 브랜치에서 고친 내용",
"option3": "Git이 두 내용을 자동으로 합쳐 제안한 절충안 코드",
"option4": "두 브랜치가 갈라지기 전의 원래 공통 코드",
"answerIndex": 1,
"explanation": "섹션 4에서 <<<<<<< HEAD부터 =======까지는 내 우주(현재 브랜치)의 내용, =======부터 >>>>>>>까지는 상대 우주(합치려는 브랜치)의 내용이라고 읽는 법을 알려 줘요."
},
{
"courseSlug": "git-deep",
"question": "이미 push해서 팀과 공유한 브랜치에서 \"그 기능 롤백해 주세요\" 요청을 받았다. 코스가 권하는 가장 안전한 방법은?",
"option1": "git reset --hard로 그 커밋 이전 시점으로 역사를 되돌린다",
"option2": "git checkout으로 과거 커밋 시점에 다녀오며 상태만 구경한다",
"option3": "git stash로 해당 기능의 코드를 서랍에 임시 보관해 둔다",
"option4": "git revert로 그 커밋의 정반대 내용을 새 커밋으로 추가한다",
"answerIndex": 3,
"explanation": "섹션 7 '되돌리기 3형제'에서 revert는 역사를 지우지 않고 반대 내용을 새 커밋으로 추가하므로 공유한 브랜치에서도 안전하다고 해요. 실무의 롤백 요청은 대부분 revert이고, 공유 후 reset은 대참사입니다."
},
{
"courseSlug": "git-deep",
"question": "기능 브랜치에서 코드를 고치던 중(커밋하기엔 애매한 미완성 상태) 멘토가 \"급한 버그부터 고쳐줘!\"라고 요청했다. 코스에서 배운 도구로 가장 알맞은 대처는?",
"option1": "git reset --hard로 미완성 수정을 전부 지우고 버그 수정부터 시작한다",
"option2": "git stash로 수정 중인 내용을 서랍에 넣어 두고, 버그를 고친 뒤 git stash pop으로 꺼낸다",
"option3": "미완성 코드라도 일단 main 브랜치에 바로 커밋해 두고 버그를 고친다",
"option4": "git revert로 마지막 커밋을 되돌려 놓고 버그 수정 작업을 이어 간다",
"answerIndex": 1,
"explanation": "섹션 6에서 stash는 커밋하기 애매한 미완성 코드를 '서랍에 임시 보관'했다가 pop으로 도로 꺼내는 도구이며, 작업 중에 급한 버그 요청이 왔을 때가 바로 쓰는 순간이라고 설명해요."
},
{
"courseSlug": "gpu",
"question": "코스에서 GPU를 '만 명의 일꾼'에 비유한 이유로 가장 알맞은 것은?",
"option1": "코어 하나하나가 CPU 코어보다 복잡한 판단을 더 잘하기 때문",
"option2": "프로그램의 전체 흐름과 순서를 GPU가 직접 결정하기 때문",
"option3": "단순한 계산을 수천~수만 개의 코어가 동시에 처리하기 때문",
"option4": "코어 수는 적지만 코어 한 개의 성능이 매우 강력하기 때문",
"answerIndex": 2,
"explanation": "섹션 1의 핵심 비유입니다. GPU는 단순한 덧셈·곱셈만 하는 코어 수천~수만 개가 '동시에' 달려들어, 같은 계산이 대량으로 필요한 일에서 천재 한 명(CPU)을 압도합니다."
},
{
"courseSlug": "gpu",
"question": "코스에서 VRAM을 무엇에 비유했고, VRAM이 부족하면 어떤 일이 생긴다고 설명했나요?",
"option1": "창고 — 부족하면 GPU가 데이터를 압축해서 쌓아 두게 된다",
"option2": "작업 책상 — 부족하면 창고(일반 RAM)를 왔다 갔다 하느라 느려진다",
"option3": "냉각 팬 — 부족하면 GPU가 뜨거워져 스스로 속도를 낮춘다",
"option4": "두뇌 — 부족하면 복잡한 판단을 전부 CPU에 넘기게 된다",
"answerIndex": 1,
"explanation": "섹션 4에서 VRAM은 GPU 전용 '작업 책상'으로 비유됩니다. 책상이 좁으면 재료를 창고(일반 RAM)에서 자꾸 가져와야 해서 일꾼 만 명이 놀게 되고, 연산 속도가 충분해도 느려집니다."
},
{
"courseSlug": "gpu",
"question": "\"모니터가 144Hz면 화면이 무조건 부드럽다\"는 말에 대해 코스가 설명한 올바른 내용은?",
"option1": "GPU가 1초에 60장밖에 못 그리면 모니터가 갈아 끼울 그림이 없으므로, 주사율과 GPU 성능은 세트로 맞아야 한다",
"option2": "주사율은 화면의 색 표현 개수를 정하는 값이라서 화면의 부드러움과는 아무 관계가 없다",
"option3": "144Hz 모니터는 해상도를 자동으로 낮춰 주기 때문에 어떤 GPU를 써도 항상 부드럽다",
"option4": "부드러움은 오직 VRAM 용량이 결정하므로 모니터 주사율은 신경 쓰지 않아도 된다",
"answerIndex": 0,
"explanation": "섹션 2의 '흔한 오해'입니다. 주사율은 모니터가 1초에 그림을 갈아 끼우는 횟수일 뿐, GPU가 프레임을 제때 만들어 주지 못하면 갈아 끼울 그림이 없어 부드러워지지 않습니다."
},
{
"courseSlug": "gpu",
"question": "게임용으로 태어난 GPU가 AI 학습의 표준 장비가 된 이유로 코스가 설명한 것은?",
"option1": "AI 전용 명령어가 게임 그래픽 명령어보다 훨씬 단순하게 만들어졌기 때문",
"option2": "GPU가 CPU보다 전력을 적게 써서 데이터센터 운영 비용이 줄어들기 때문",
"option3": "GPU에 달린 VRAM이 일반 RAM보다 용량이 언제나 더 크기 때문",
"option4": "AI는 사실상 거대한 행렬 곱셈 덩어리라, 픽셀 수백만 개를 동시에 계산하는 게임 작업과 하는 일이 사실상 같기 때문",
"answerIndex": 3,
"explanation": "섹션 5의 핵심입니다. AI 학습·실행은 '단순한 곱셈·덧셈을 수십억 번' 반복하는 일이고, 이는 픽셀을 동시에 계산하던 GPU(만 명의 일꾼)가 세상에서 제일 잘하는 일과 같아서 GPU가 AI의 표준 장비가 됐습니다."
},
{
"courseSlug": "gpu",
"question": "실습 중 작업 관리자 [성능] 탭을 옆에 띄워 두고 유튜브에서 4K 영상을 재생했더니 Video Decode 그래프가 쑥 올라갔다. 코스에 따르면 이 현상이 의미하는 것은?",
"option1": "브라우저가 CPU 대신 3D 게임 엔진을 실행하기 시작했다는 뜻이다",
"option2": "VRAM이 부족해서 일반 RAM에서 재료를 빌려 오고 있다는 뜻이다",
"option3": "영상 압축을 푸는 일을 GPU의 전용 회로가 담당하고 있다는 뜻이다",
"option4": "외장 GPU가 고장 나서 내장 GPU가 대신 일을 떠맡았다는 뜻이다",
"answerIndex": 2,
"explanation": "섹션 7의 실습 ②입니다. 4K 영상을 재생하면 영상 압축을 푸는 일(디코딩)을 GPU 전용 회로가 담당해 Video Decode 그래프가 올라가며, GPU가 게임할 때만 쓰이는 게 아님을 숫자로 확인하는 실습입니다."
},
{
"courseSlug": "hardware",
"question": "컴퓨터가 하는 5가지 일(입력·기억·계산·저장·출력) 중에서 '계산'을 담당하는 부품은 무엇인가?",
"option1": "RAM(메모리)",
"option2": "SSD/HDD(저장장치)",
"option3": "CPU",
"option4": "메인보드",
"answerIndex": 2,
"explanation": "코스 1섹션의 다이어그램에서 CPU는 '두뇌'로서 계산(생각하기)을 담당한다. RAM은 기억(펼쳐 놓기), SSD/HDD는 저장, 메인보드는 부품들이 꽂히는 판이다."
},
{
"courseSlug": "hardware",
"question": "코스에서 설명한 RAM(메모리)의 중요한 특징으로 올바른 것은?",
"option1": "전원을 꺼도 저장한 자료가 그대로 남는다",
"option2": "전원을 끄면 내용이 싹 비워진다",
"option3": "윈도우와 프로그램 파일이 설치되는 보관 창고다",
"option4": "책장처럼 넓지만 자료를 꺼내는 속도가 가장 느리다",
"answerIndex": 1,
"explanation": "코스 3섹션에서 RAM은 '지금 하는 일을 펼쳐 놓는 작업 책상'이라 전원을 끄면 싹 비워진다고 설명한다. 전원을 꺼도 남는 보관은 저장장치(SSD/HDD)의 역할이다."
},
{
"courseSlug": "hardware",
"question": "CPU 모델명 '인텔 코어 i5-14400F'에서 맨 뒤의 'F'가 뜻하는 것은 무엇인가?",
"option1": "오버클럭이 가능한 고급형 모델이라는 표시",
"option2": "노트북용 저전력 모델이라는 표시",
"option3": "같은 세대 안에서 가장 최신 모델이라는 표시",
"option4": "내장그래픽이 없어 외장 그래픽카드가 꼭 필요하다는 표시",
"answerIndex": 3,
"explanation": "코스 2섹션의 CPU 스펙표 읽기에서 'F'는 내장그래픽 없음을 뜻하며, 이 경우 외장 그래픽카드가 필수라고 설명한다. i5는 등급, 14는 세대, 400은 세부 모델이다."
},
{
"courseSlug": "hardware",
"question": "코스에서 PC 견적을 짤 때 '세 개가 한 세트로 맞아야 한다'고 강조한 조합은 무엇인가?",
"option1": "CPU ↔ 메인보드 소켓 ↔ RAM 세대(DDR4/DDR5)",
"option2": "CPU ↔ 파워 정격 출력 ↔ 케이스 색상",
"option3": "그래픽카드 ↔ 모니터 크기 ↔ SSD 용량",
"option4": "RAM 용량 ↔ HDD 회전 속도 ↔ 케이스 팬 개수",
"answerIndex": 0,
"explanation": "5섹션에서 소켓이 맞아야 CPU가 꽂히고 RAM 규격(DDR4/DDR5)도 메인보드가 정하므로, 'CPU ↔ 보드 소켓 ↔ RAM 세대' 세 가지가 한 세트로 맞아야 한다고 설명한다."
},
{
"courseSlug": "hardware",
"question": "크롬 탭 30개에 게임과 디스코드까지 켰더니 컴퓨터가 뚝뚝 끊긴다. 코스의 주방·책상 비유로 이 현상의 원인을 가장 잘 설명한 것은?",
"option1": "요리사(CPU)의 손 빠르기(GHz)가 절반으로 줄어들었기 때문",
"option2": "책상(RAM)이 꽉 차서 자료를 책장(저장장치)으로 치웠다 꺼내는 스왑이 일어나기 때문",
"option3": "냉장고(저장장치)가 가득 차서 새 파일을 저장할 공간이 없기 때문",
"option4": "배전반(파워)의 전력이 모자라 부품 일부가 꺼졌다 켜지기 때문",
"answerIndex": 1,
"explanation": "3섹션의 '스왑' 설명에 나오는 상황이다. RAM(책상)이 꽉 차면 덜 쓰는 자료를 SSD/HDD(책장)로 잠시 치워 두는데, 책상에서 바로 집는 것보다 수백~수천 배 느려서 끊김이 생긴다."
},
{
"courseSlug": "history",
"question": "1946년에 등장한 에니악(ENIAC)에서 실행할 프로그램을 바꾸려면 어떻게 해야 했나요?",
"option1": "천공카드를 새로 뚫어서 기계에 읽혔다",
"option2": "메모리에 저장된 파일을 교체해 실행했다",
"option3": "케이블 배선을 손으로 다시 꽂았다",
"option4": "진공관을 다른 종류로 갈아 끼웠다",
"answerIndex": 2,
"explanation": "코스 1섹션에 나오듯 에니악은 \"프로그램을 바꾼다 = 배선을 다시 꽂는다\"였던 시대의 기계입니다. 파일을 바꿔 실행하는 방식은 이후 폰 노이만 구조가 등장하면서 가능해졌어요."
},
{
"courseSlug": "history",
"question": "코스에서 소개한 무어의 법칙(1965, 고든 무어의 관찰)의 내용으로 옳은 것은?",
"option1": "칩의 가격은 2년마다 절반으로 떨어진다",
"option2": "칩 하나에 들어가는 트랜지스터 수는 약 2년마다 2배가 된다",
"option3": "컴퓨터의 전력 소모는 매년 2배씩 늘어난다",
"option4": "소프트웨어의 크기는 하드웨어 성능만큼 빠르게 커진다",
"answerIndex": 1,
"explanation": "무어의 법칙은 트랜지스터 수가 약 2년마다 2배가 된다는 관찰로, 코스에서는 \"2배 × 25번\"이 50년간 수백만 배라는 지수적 성장을 만들었다고 설명합니다."
},
{
"courseSlug": "history",
"question": "코스에서 '헷갈리기 쉽다'며 따로 구분한 인터넷과 웹의 관계로 옳은 것은?",
"option1": "인터넷은 전 세계 컴퓨터를 잇는 도로망이고, 웹은 그 도로 위에서 HTTP로 문서와 앱을 주고받는 서비스다",
"option2": "웹이 물리적 연결망이고, 인터넷은 그 연결망 위에서 돌아가는 여러 서비스 중 하나다",
"option3": "인터넷과 웹은 같은 것을 시대에 따라 다르게 부르는 두 가지 이름일 뿐이다",
"option4": "인터넷은 한 나라 안의 연결망을, 웹은 나라와 나라를 잇는 국제 연결망을 가리킨다",
"answerIndex": 0,
"explanation": "섹션 4의 핵심 구분입니다. 인터넷은 도로망(물리적 연결), 웹은 그 도로 위를 달리는 서비스 중 하나(HTTP로 문서·앱 주고받기)라고 코스가 설명해요."
},
{
"courseSlug": "history",
"question": "클라우드 섹션에서 소개한 우리 회사(AWESOMEDEV)의 실제 서버 구성 중, Caddy가 맡고 있는 역할은?",
"option1": "앱을 컨테이너(규격 화물)로 포장해 실행한다",
"option2": "백엔드 API의 비즈니스 로직을 처리한다",
"option3": "서비스의 데이터를 저장하고 관리한다",
"option4": "HTTPS 현관 안내데스크 역할을 한다",
"answerIndex": 3,
"explanation": "코스의 실제 구성도에서 Docker는 컨테이너 포장, Spring Boot는 백엔드, PostgreSQL은 데이터베이스, Caddy는 'HTTPS 현관 안내데스크'로 소개됩니다."
},
{
"courseSlug": "history",
"question": "수습사원 A가 학습 플랫폼 페이지에서 F12를 눌러 기기 툴바를 켜고 화면 폭을 천천히 줄였더니, 어느 지점에서 레이아웃이 '뚝' 하고 다시 배치되었습니다. 코스에 따르면 이 지점의 이름과, 이런 설계가 기본기가 된 시대는?",
"option1": "렌더링 포인트 — 클라우드 시대",
"option2": "분기점(breakpoint) — 스마트폰 시대",
"option3": "체크포인트 — PC 혁명 시대",
"option4": "접속점(access point) — 인터넷·웹 시대",
"answerIndex": 1,
"explanation": "섹션 5의 '직접 확인해 보기' 실습 그대로입니다. 배치가 바뀌는 지점이 반응형의 분기점(breakpoint)이며, \"사용자가 어떤 화면으로 볼지 모른다\"는 전제를 만든 스마트폰 시대가 반응형 디자인을 기본기로 남겼어요."
},
{
"courseSlug": "home-network",
"question": "공유기 관리자 페이지에 들어가려면 먼저 공유기의 주소를 알아내야 한다. 코스에서 안내한 방법은 무엇인가?",
"option1": "브라우저 주소창에 8.8.8.8을 입력해서 관리 화면을 연다",
"option2": "속도 측정 사이트에서 우리 집 공인 IP를 확인해 입력한다",
"option3": "터미널에서 ipconfig를 실행해 기본 게이트웨이 주소를 확인한다",
"option4": "공유기 밑면 스티커에 적힌 SSID를 주소창에 입력한다",
"answerIndex": 2,
"explanation": "섹션 1에서 배운 3단계의 첫걸음이다. ipconfig로 나오는 기본 게이트웨이(예: 192.168.0.1)가 곧 공유기의 주소이고, 그 주소를 브라우저에 입력하면 관리자 페이지에 들어갈 수 있다."
},
{
"courseSlug": "home-network",
"question": "코스에서 2.4GHz 대역을 저음(우퍼) 스피커에 비유했다. 2.4GHz의 특징으로 맞는 것은?",
"option1": "속도는 느리지만 멀리 도달하고 벽을 잘 통과한다",
"option2": "속도가 빠르고 벽도 잘 통과하지만 도달 거리가 짧다",
"option3": "도달 거리는 짧지만 전자레인지 간섭이 거의 없다",
"option4": "채널이 수십 개라 이웃 간 간섭 걱정이 적은 대역이다",
"answerIndex": 0,
"explanation": "저음이 벽 너머까지 웅웅 울려 퍼지듯, 낮은 주파수인 2.4GHz는 멀리 가고 벽을 잘 뚫는 대신 속도가 느리고 전자레인지·블루투스 등 간섭이 많다. 빠르지만 여린 쪽은 5GHz다."
},
{
"courseSlug": "home-network",
"question": "2.4GHz 대역에는 채널 1~13번이 있지만 서로 겹치는 구조다. 실제로 겹치지 않게 쓸 수 있는 채널 조합은?",
"option1": "2번 · 7번 · 12번",
"option2": "1번 · 6번 · 11번",
"option3": "1번 · 5번 · 9번",
"option4": "3번 · 6번 · 9번",
"answerIndex": 1,
"explanation": "섹션 3의 핵심이다. 2.4GHz 채널은 이웃 번호끼리 겹치는 구조라 안 겹치는 조합은 1·6·11 세 개뿐 — 왕복 6차선 도로에서 실제로 안 부딪히는 차선이 3개뿐인 상황에 비유했다."
},
{
"courseSlug": "home-network",
"question": "외부에서 내 기기로 접속을 허용해야 할 때, 코스가 권장한 순서를 안전한 것부터 바르게 나열한 것은?",
"option1": "DMZ → UPnP → 필요한 포트만 포트포워딩",
"option2": "UPnP → 필요한 포트만 포트포워딩 → DMZ",
"option3": "DMZ → 필요한 포트만 포트포워딩 → UPnP",
"option4": "필요한 포트만 포트포워딩 → UPnP → DMZ",
"answerIndex": 3,
"explanation": "좁게 열수록 안전하다는 원칙이다. 필요한 포트만 여는 포트포워딩이 1순위, 자동문인 UPnP가 2순위, 모든 문을 열어 버리는 DMZ는 최후 수단(사실상 쓰지 말 것)이다. 서버 보안의 최소 권한 원칙과 같다."
},
{
"courseSlug": "home-network",
"question": "내 PC(192.168.0.5)에서 Spring Boot 서버를 8080 포트로 켰다. 친구가 우리 집 공인 IP의 8080 포트로 접속했지만 공유기에서 막혀 실패했다. 코스의 원칙에 맞는 가장 안전한 해결 방법은?",
"option1": "공유기 DMZ에 내 PC를 지정해 모든 외부 요청을 받게 한다",
"option2": "외부 8080 포트를 192.168.0.5의 8080으로 보내는 포트포워딩 규칙을 등록한다",
"option3": "PC를 5GHz SSID로 옮겨 접속해 무선 속도를 끌어올린다",
"option4": "무선 채널을 1·6·11 중 이웃이 덜 쓰는 번호로 수동 변경한다",
"answerIndex": 1,
"explanation": "경비실(NAT) 비유처럼 공유기는 밖에서 먼저 온 손님을 몇 호로 보낼지 몰라 돌려보내므로, 필요한 포트 하나만 정확히 여는 포트포워딩 규칙을 등록해야 한다. DMZ도 되긴 하지만 문을 전부 여는 위험한 방법이다."
},
{
"courseSlug": "htmlcss",
"question": "이 코스에서는 웹페이지의 세 가지 재료를 사람에 비유합니다. CSS는 무엇에 해당하나요?",
"option1": "골격 — 몸의 구조를 잡아 준다",
"option2": "옷과 화장 — 겉모습을 꾸며 준다",
"option3": "근육 — 몸을 움직이게 한다",
"option4": "신경 — 자극에 반응하게 한다",
"answerIndex": 1,
"explanation": "섹션 1 '웹페이지의 정체'에서 HTML은 골격, CSS는 옷과 화장, JS는 근육에 비유합니다. 같은 뼈대(HTML)에 옷(CSS)만 갈아입혀도 완전히 다른 사이트처럼 보인다고 설명해요."
},
{
"courseSlug": "htmlcss",
"question": "박스 모델의 택배 상자 비유에서 '뽁뽁이'(물건과 상자 벽 사이의 완충재)에 해당하는 CSS 속성은 무엇인가요?",
"option1": "margin — 옆 상자와의 간격",
"option2": "border — 상자의 벽",
"option3": "padding — 벽과 내용 사이의 안쪽 여백",
"option4": "box-shadow — 상자가 떠 있는 느낌",
"answerIndex": 2,
"explanation": "섹션 4 박스 모델에서 content는 물건, padding은 뽁뽁이, border는 상자 벽, margin은 옆 상자와의 간격에 비유합니다. 뽁뽁이는 상자 '안'에 있으므로 안쪽 여백인 padding이에요."
},
{
"courseSlug": "htmlcss",
"question": "우리 플랫폼은 컴포넌트 코드를 한 줄도 바꾸지 않고 다크 모드를 지원합니다. 코스에서 설명한 그 원리는 무엇인가요?",
"option1": "모든 색이 :root 변수에 모여 있어, @media 블록이 변수 값만 갈아끼우기 때문",
"option2": "다크 모드 전용 CSS 파일을 페이지마다 하나씩 따로 만들어 두었기 때문",
"option3": "JS가 화면의 모든 색 속성을 찾아서 어두운 색으로 바꿔 주기 때문",
"option4": "브라우저가 페이지의 모든 색을 자동으로 반전시켜 주기 때문",
"answerIndex": 0,
"explanation": "섹션 5에서 global.css의 :root에 색 '이름표'(--bg, --ink, --primary)를 붙여 두고, @media (prefers-color-scheme: dark)에서 이름표의 값만 바꿔치기하면 사이트 전체가 옷을 갈아입는다고 설명합니다."
},
{
"courseSlug": "htmlcss",
"question": "겉보기엔 <div onClick=...>도 클릭이 됩니다. 그런데 코스에서 \"누르는 것은 반드시 <button>\"이라고 강조하는 이유는 무엇인가요?",
"option1": "div는 클릭 이벤트를 처리하는 속도가 button보다 훨씬 느려서",
"option2": "div에 onClick을 달면 화면에 아예 표시되지 않아서",
"option3": "키보드 Tab으로 접근할 수 없고 스크린리더도 버튼인 줄 몰라서",
"option4": "button 태그가 아니면 CSS 스타일을 적용할 수 없어서",
"answerIndex": 2,
"explanation": "섹션 2의 '클릭은 button에게' 경고 내용입니다. div에 onClick을 달면 키보드 Tab으로 접근이 안 되고 스크린리더도 버튼인 줄 모르기 때문에, 우리 코드 리뷰에서도 자주 나오는 지적이라고 해요."
},
{
"courseSlug": "htmlcss",
"question": "수습 티켓 FE-06 상황입니다. 폰(화면 폭 640px 이하)에서 두 칸짜리 카드 바둑판이 깨져서, 좁은 화면에서만 한 칸으로 바꾸려 합니다. 코스 내용대로라면 어떻게 고쳐야 할까요?",
"option1": ".card-grid에 display: flex와 align-items: center를 추가한다",
"option2": ":root의 --primary 변수 값을 더 밝은 색으로 바꾼다",
"option3": ".card-grid의 padding과 margin을 크게 늘려 간격을 조정한다",
"option4": "@media (max-width: 640px) 블록 안에서 grid-template-columns를 1fr로 바꾼다",
"answerIndex": 3,
"explanation": "섹션 7 반응형에서 @media (max-width: 640px)는 화면 폭이 640px 이하일 때만 CSS를 적용하는 조건문이고, 그 안에서 grid-template-columns: 1fr로 두 칸 바둑판을 한 칸으로 접는 예시를 그대로 보여 줍니다."
},
{
"courseSlug": "http",
"question": "HTTP 요청과 응답이 공통으로 갖는 세 부분 구조는 무엇인가요?",
"option1": "주소줄, 본문, 서명",
"option2": "메서드, 상태코드, 쿠키",
"option3": "시작줄, 헤더, 바디",
"option4": "헤더, 푸터, 첨부파일",
"answerIndex": 2,
"explanation": "섹션 1에서 배웠듯 HTTP 편지는 요청이든 응답이든 똑같이 시작줄·헤더·바디 세 부분으로 이루어집니다. 헤더는 편지 겉봉의 메모, 바디는 진짜 내용물이에요."
},
{
"courseSlug": "http",
"question": "로그인은 되어 있지만 학생 계정으로 관리자 API를 호출했을 때 서버가 돌려주는 상태코드는 무엇인가요?",
"option1": "401 Unauthorized",
"option2": "403 Forbidden",
"option3": "404 Not Found",
"option4": "500 Internal Server Error",
"answerIndex": 1,
"explanation": "섹션 2의 학생증 비유로, 403은 학생증은 있지만 교무실 출입증이 아닌 경우(권한 부족)입니다. 401은 학생증 자체가 없어 로그인부터 해야 하는 상황이에요."
},
{
"courseSlug": "http",
"question": "쿠키와 세션의 역할 분담을 카페 비유로 옳게 설명한 것은 무엇인가요?",
"option1": "쿠키는 서버가 적는 장부이고, 세션은 브라우저가 드는 번호표다",
"option2": "쿠키와 세션 모두 서버가 보관하고 브라우저는 아무것도 저장하지 않는다",
"option3": "쿠키에는 비밀번호가 담겨 매 요청마다 그대로 전송된다",
"option4": "쿠키는 브라우저가 드는 번호표이고, 세션은 서버가 적어 두는 장부다",
"answerIndex": 3,
"explanation": "섹션 3의 비유대로 쿠키는 손에 든 번호표(브라우저 보관), 세션은 카운터 뒤의 장부(서버 보관)입니다. 비밀번호는 로그인 그 한 번만 전송되고 이후엔 번호표만 오가요."
},
{
"courseSlug": "http",
"question": "Set-Cookie에 붙는 HttpOnly 옵션이 하는 일은 무엇인가요?",
"option1": "자바스크립트가 쿠키를 읽지 못하게 해서 악성 스크립트의 번호표 탈취를 막는다",
"option2": "HTTPS 연결일 때만 쿠키를 전송하도록 제한한다",
"option3": "다른 사이트에서 시작된 요청에는 쿠키를 붙이지 않게 한다",
"option4": "쿠키의 유효 기간을 90일마다 자동으로 갱신해 준다",
"answerIndex": 0,
"explanation": "섹션 3에서 배운 번호표 도난 방지 장치 중 HttpOnly는 자바스크립트가 쿠키를 못 읽게 하는 옵션입니다. HTTPS 전용 전송은 Secure, 타 사이트 요청 차단은 SameSite의 역할이에요."
},
{
"courseSlug": "http",
"question": "카페 공용 와이파이에서 http:// 사이트에 아이디와 비밀번호를 입력해 로그인하면 위험한 이유는 무엇인가요?",
"option1": "공용 와이파이는 속도가 느려서 세션 쿠키가 도중에 만료되기 때문이다",
"option2": "http 사이트는 서버 인증서 검사를 두 번 해서 로그인이 자주 끊기기 때문이다",
"option3": "HTTP는 엽서와 같아서 길을 지나는 누구나 아이디와 비밀번호를 그대로 읽을 수 있기 때문이다",
"option4": "브라우저가 http 사이트에는 쿠키를 아예 저장하지 않아 로그인이 불가능하기 때문이다",
"answerIndex": 2,
"explanation": "섹션 4의 엽서 비유입니다. HTTP는 봉인이 없는 엽서라 와이파이 주인 같은 중간 지점에서 내용이 그대로 노출되고, HTTPS는 TLS 봉투로 밀봉되어 훔쳐봐도 암호문 덩어리만 보여요."
},
{
"courseSlug": "icons-images",
"question": "비트맵과 벡터의 가장 근본적인 차이는 무엇인가요?",
"option1": "비트맵은 색을 적게 쓰고, 벡터는 수백만 가지 색을 쓴다",
"option2": "비트맵은 웹 전용 포맷이고, 벡터는 인쇄 전용 포맷이다",
"option3": "비트맵은 픽셀마다 색을 전부 기록하고, 벡터는 '어떻게 그리는지'를 기록한다",
"option4": "비트맵은 압축이 불가능하고, 벡터는 항상 자동으로 압축된다",
"answerIndex": 2,
"explanation": "코스 1섹션의 핵심입니다. 비트맵(PNG·JPG)은 칸(픽셀)마다 무슨 색인지 전부 기록하고, 벡터(SVG)는 '중심에 반지름 40 원을 그려' 같은 설계도를 기록해서 확대해도 항상 매끈합니다."
},
{
"courseSlug": "icons-images",
"question": "코스의 포맷 선택 기준표에 따르면, 아이콘과 로고에 가장 알맞은 포맷은 무엇인가요?",
"option1": "JPG — 색이 많은 이미지에 최적이라서",
"option2": "SVG — 벡터라 어떤 크기에서도 매끈해서",
"option3": "PNG — 투명 배경을 지원하는 비트맵이라서",
"option4": "WebP — 같은 품질에 용량이 더 작아서",
"answerIndex": 1,
"explanation": "기준표에서 사진은 JPG(또는 WebP), 아이콘·로고는 SVG, '투명 배경 + 비트맵'이면 PNG로 정리했습니다. 아이콘·로고는 도형 몇 개로 이루어져 벡터인 SVG가 최적입니다."
},
{
"courseSlug": "icons-images",
"question": "비트맵 아이콘은 @2x 버전을 따로 만들어야 하는데, SVG는 그럴 필요가 없습니다. 그 이유는 무엇인가요?",
"option1": "SVG는 파일 용량이 항상 1KB 이하로 작기 때문에",
"option2": "브라우저가 SVG를 미리 2배 크기로 확대해 저장해 두기 때문에",
"option3": "SVG는 고해상도 화면에서 자동으로 비트맵으로 변환되기 때문에",
"option4": "SVG는 '그리는 법'의 기록이라 어떤 화면 밀도에서도 다시 계산해 매끈하게 그려지기 때문에",
"answerIndex": 3,
"explanation": "2섹션 '해상도와 @2x'의 내용입니다. 고해상도 화면은 CSS 1px을 화소 2~3개로 그리므로 비트맵은 2배 크기 파일이 필요하지만, SVG는 설계도라 어떤 밀도에서도 스스로 매끈하게 그려집니다."
},
{
"courseSlug": "icons-images",
"question": "'개인/비상업용 무료'라고 표시된 이미지를 우리 회사 서비스에 쓰면 안 되는 이유는 무엇인가요?",
"option1": "회사 서비스에 쓰는 것은 전부 상업적 이용에 해당하기 때문에",
"option2": "무료 이미지는 해상도가 낮아 서비스 품질을 떨어뜨리기 때문에",
"option3": "개인용 이미지는 파일 형식이 회사 시스템과 호환되지 않기 때문에",
"option4": "무료 이미지는 색을 바꾸는 등 수정이 기술적으로 불가능하기 때문에",
"answerIndex": 0,
"explanation": "4섹션 '무료 소스와 저작권'에서 강조한 첫 번째 확인 사항입니다. 회사 서비스에 쓰는 건 전부 상업적 이용이므로 '개인/비상업용 무료' 이미지는 쓸 수 없고, 어기면 저작권 침해로 손해배상까지 이어질 수 있습니다."
},
{
"courseSlug": "icons-images",
"question": "수습 개발자가 화면에 200px로 보일 프로필 사진 자리에 폰 카메라 원본(4000px, 약 5MB)을 그대로 올렸습니다. 코스의 최적화 순서에 따라 가장 먼저 해야 할 일은 무엇인가요?",
"option1": "F12의 Network 탭을 열어 실제 전송 용량부터 확인한다",
"option2": "압축 도구에 넣어 눈에 안 띄는 수준으로 용량을 줄인다",
"option3": "보여줄 크기에 맞게 이미지를 리사이즈한다",
"option4": "파일 확장자만 WebP로 바꿔서 다시 저장한다",
"answerIndex": 2,
"explanation": "5섹션 '이미지 최적화'의 순서는 1) 리사이즈 → 2) 포맷 선택 → 3) 압축 → 4) 확인입니다. 보여줄 크기보다 큰 이미지를 올리지 않는 리사이즈가 첫 단계로, 200px 자리에 4000px 원본을 올리면 쓰지도 않을 픽셀 수백만 개를 내려받게 됩니다."
},
{
"courseSlug": "ip-deep",
"question": "IPv4 주소의 구조에 대한 설명으로 옳은 것은?",
"option1": "16비트를 4비트씩 4칸으로 나눈 것으로, 한 칸은 0~15까지 가능하다",
"option2": "32비트를 8비트씩 4칸으로 나눈 것으로, 한 칸은 0~255까지 가능하다",
"option3": "64비트를 16비트씩 4칸으로 나눈 것으로, 한 칸은 0~65535까지 가능하다",
"option4": "128비트를 16진수 8덩어리로 나눈 것으로, 콜론(:)으로 구분해 표기한다",
"answerIndex": 1,
"explanation": "섹션 1의 핵심 — IPv4는 32비트를 8비트(옥텟)씩 4칸으로 끊어 점으로 표기하며, 한 칸은 2^8=256가지라 0~255까지만 가능합니다. 그래서 192.168.0.300 같은 주소는 존재할 수 없어요."
},
{
"courseSlug": "ip-deep",
"question": "새 기기가 와이파이에 붙을 때 DHCP가 IP를 빌려주는 4단계(DORA)의 올바른 순서는?",
"option1": "Offer → Discover → Request → Acknowledge",
"option2": "Discover → Request → Offer → Acknowledge",
"option3": "Request → Offer → Discover → Acknowledge",
"option4": "Discover → Offer → Request → Acknowledge",
"answerIndex": 3,
"explanation": "섹션 5의 DORA — 세입자가 \"방 있나요?\"(Discover) 외치면 임대인이 \"이 방 어때요?\"(Offer) 제안하고, \"계약할게요!\"(Request) 뒤 \"도장 쾅!\"(Acknowledge)으로 확정되는 순서입니다."
},
{
"courseSlug": "ip-deep",
"question": "다음 중 사설 IP 대역에 속하는 주소는 무엇인가?",
"option1": "172.20.10.3",
"option2": "172.15.10.3",
"option3": "172.32.10.3",
"option4": "192.169.0.5",
"answerIndex": 0,
"explanation": "섹션 2의 함정 포인트 — 172 대역은 172.16.x.x부터 172.31.x.x까지만 사설입니다. \"172는 16층부터 31층까지만 우리 것\"이라는 암기법대로 172.20은 사설이고, 172.15·172.32·192.169는 남의 공인 IP예요."
},
{
"courseSlug": "ip-deep",
"question": "서브넷마스크가 255.255.255.0(/24)인 네트워크에서 실제로 기기에 배정할 수 있는 호스트 주소는 몇 개인가?",
"option1": "256개 — 호스트 비트 8개의 모든 조합을 쓸 수 있다",
"option2": "255개 — 네트워크 주소(.0) 하나만 빼면 된다",
"option3": "254개 — 네트워크 주소(.0)와 방송용(.255)을 빼야 한다",
"option4": "252개 — 게이트웨이와 DNS 서버 몫까지 미리 빼야 한다",
"answerIndex": 2,
"explanation": "섹션 3의 아파트 단지 비유 — /24는 호스트 비트가 8개라 2^8=256개 조합이 나오지만, 단지 자체를 가리키는 .0과 단지 전체 방송용 .255를 빼면 실제 입주 가능한 세대는 254개입니다."
},
{
"courseSlug": "ip-deep",
"question": "서울 EC2에서 돌던 서버를 중지(stop)했다가 다시 시작(start)했더니 도메인 edu.awesomedevapp.com으로 접속이 안 된다. 코스 내용에 비추어 가장 가능성이 높은 원인은?",
"option1": "서브넷마스크가 /24에서 /16으로 바뀌어 네트워크 경계선이 달라졌기 때문",
"option2": "탄력적 IP를 연결해 두지 않아 재시작 때 공인 IP가 바뀌었는데, DNS는 여전히 옛 IP를 가리키고 있기 때문",
"option3": "DHCP 임대 기간이 절반쯤 지나 서버가 자동으로 임대 갱신을 요청했기 때문",
"option4": "IPv6 주소가 :: 축약 표기로 바뀌어 브라우저가 주소를 해석하지 못하기 때문",
"answerIndex": 1,
"explanation": "섹션 8 — EC2의 공인 IP는 기본이 유동이라 중지 후 시작하면 바뀝니다. 가게가 이사 다니면 단골이 못 찾아오듯 DNS 전화번호부가 틀려지므로, 탄력적 IP를 못 박아 두어야 재시작해도 같은 주소로 열려요."
},
{
"courseSlug": "java-basics",
"question": "JavaScript에서는 let age = 17; 뒤에 age = \"열일곱\";처럼 다른 타입을 넣어도 허용되지만, Java에서 int age = 17; 뒤에 age = \"열일곱\";을 쓰면 어떻게 되는가?",
"option1": "실행 중에 오류가 발생해 프로그램이 그때 멈춘다",
"option2": "문자열이 자동으로 숫자로 변환되어 그대로 실행된다",
"option3": "컴파일 단계에서 에러가 나서 실행조차 할 수 없다",
"option4": "경고 메시지만 표시되고 정상적으로 실행된다",
"answerIndex": 2,
"explanation": "Java는 변수를 만들 때 타입을 미리 선언하고, 약속을 어기면 실행 전에(컴파일 때) 막는 언어다. 섹션 1 'JS와 뭐가 다를까'에서 배운 타입 선언과 컴파일 검사의 핵심이다."
},
{
"courseSlug": "java-basics",
"question": "코스의 붕어빵 비유에서 클래스, 객체, new 키워드를 올바르게 짝지은 것은?",
"option1": "클래스=붕어빵, 객체=붕어빵 틀, new=틀을 새로 만드는 것",
"option2": "클래스=붕어빵 틀, 객체=붕어빵, new=틀에 반죽을 부어 하나 굽는 것",
"option3": "클래스=반죽, 객체=붕어빵 틀, new=틀에 팥을 채우는 것",
"option4": "클래스=붕어빵 틀, 객체=반죽, new=다 구운 붕어빵을 꺼내는 것",
"answerIndex": 1,
"explanation": "섹션 3에서 클래스는 붕어빵 틀, 객체는 그 틀로 구운 붕어빵, new는 '틀에 반죽 부어서 하나 굽기'라고 배웠다. 틀은 하나여도 붕어빵(객체)은 원하는 만큼 만들 수 있다."
},
{
"courseSlug": "java-basics",
"question": "List<String> mentors에 멘토 3명이 들어 있을 때, 마지막(세 번째) 멘토를 꺼내는 올바른 코드는?",
"option1": "mentors.get(2)",
"option2": "mentors.get(3)",
"option3": "mentors.get(-1)",
"option4": "mentors.get(\"이선배\")",
"answerIndex": 0,
"explanation": "List의 첫 번째 칸은 get(0)부터 시작하므로, 3명이 든 리스트의 마지막은 get(3)이 아니라 get(2)다. 섹션 7에서 '몇 번을 배워도 헷갈리는 함정'으로 강조한 부분이다."
},
{
"courseSlug": "java-basics",
"question": "Java 클래스 안의 여러 메서드 중에서 어떤 것이 '생성자'인지 알아보는 기준은 무엇인가?",
"option1": "이름이 main이고 앞에 static이 붙어 있다",
"option2": "반환 타입이 void이고 이름이 new로 시작한다",
"option3": "public이 붙어 있고 매개변수를 하나도 받지 않는다",
"option4": "클래스와 이름이 똑같고 반환 타입이 없다",
"answerIndex": 3,
"explanation": "섹션 5에서 배운 대로, 클래스와 이름이 같고 반환 타입이 없는 특별한 메서드가 생성자다. 생성자는 '아이디 없는 회원' 같은 반쯤 만들어진 객체가 생기지 않게 막는 안전장치 역할을 한다."
},
{
"courseSlug": "java-basics",
"question": "동아리 회계 프로그램에서 잔액 필드를 프로젝트 아무 데서나 직접 고칠 수 있어서, 버그가 나도 누가 언제 바꿨는지 추적이 안 된다. 코스에서 배운 습관대로 고치는 방법은?",
"option1": "잔액 필드를 public으로 열어 어디서든 값을 바로 확인하고 고치게 한다",
"option2": "잔액 필드를 private으로 잠그고, 값을 바꾸는 public 메서드 하나만 열어 검증을 그 창구에 단다",
"option3": "잔액을 바꾸는 코드를 전부 try-catch로 감싸 사고가 나도 멈추지 않게 한다",
"option4": "잔액 필드를 String 타입으로 바꿔 숫자가 아닌 값이 들어오면 거부하게 한다",
"answerIndex": 1,
"explanation": "섹션 6의 캡슐화 습관 — 데이터는 금고(private)에 잠그고 창구(public 메서드) 하나로만 만지게 하면, 값이 바뀌는 통로가 한 곳뿐이라 검사와 추적을 거기에만 달면 된다."
},
{
"courseSlug": "javascript",
"question": "F12 콘솔에 \"1\" + 1 을 붙여넣고 Enter를 치면 어떤 결과가 나올까요?",
"option1": "숫자 2",
"option2": "문자열 \"2\"",
"option3": "문자열 \"11\"",
"option4": "빨간 에러 메시지",
"answerIndex": 2,
"explanation": "+ 연산자는 문자열이 끼어 있으면 이어붙이기로 동작해서 \"11\"이 됩니다. 섹션 1의 '콘솔의 재미있는 함정'에서 다룬 자동 형변환 예제예요."
},
{
"courseSlug": "javascript",
"question": "const로 선언한 변수에 대한 설명으로 옳은 것은 무엇일까요?",
"option1": "한 번 선언하면 재할당할 수 없다",
"option2": "선언하기 전 줄에서 사용해도 에러가 나지 않는다",
"option3": "값이 정말 바뀌어야 할 때만 골라 쓰는 이름표다",
"option4": "옛날 문법이라 현대 코드에서는 쓰지 않는다",
"answerIndex": 0,
"explanation": "const는 바꿀 수 없는 이름표라서 재할당하면 에러가 납니다. 섹션 2의 기본 규칙은 '일단 전부 const로 쓰고, 정말 바뀌어야 할 때만 let'이에요. 나머지 보기는 var와 let에 대한 설명입니다."
},
{
"courseSlug": "javascript",
"question": "콘솔에서 typeof null 을 실행하면 어떤 값이 나올까요?",
"option1": "\"null\"",
"option2": "\"undefined\"",
"option3": "\"boolean\"",
"option4": "\"object\"",
"answerIndex": 3,
"explanation": "null인데도 \"object\"가 나오는 것은 섹션 2에서 소개한 유명한 역사적 버그입니다. null은 '여긴 비워 뒀음'이라고 사람이 일부러 붙여 둔 팻말이라는 점도 함께 기억하세요."
},
{
"courseSlug": "javascript",
"question": "코스에서 정리한 'map과 for 중 무엇을 쓸까?'의 기준으로 옳은 것은 무엇일까요?",
"option1": "반복 횟수가 많으면 map, 적으면 for를 쓴다",
"option2": "새 배열(결과물)이 필요하면 map, 각각에 행동만 하면 되면 for를 쓴다",
"option3": "배열에는 map만 쓸 수 있고 for는 숫자 세기 전용이다",
"option4": "for가 더 최신 문법이라 가능하면 map 대신 for를 쓴다",
"answerIndex": 1,
"explanation": "섹션 5의 정리 그대로, 배열을 새 배열로 변환할 때는 map, 변환 결과 없이 각각에 뭔가 하거나 break로 멈추고 싶을 때는 for입니다. React 화면 그리기가 map인 이유도 '배열 → JSX 배열' 변환이기 때문이에요."
},
{
"courseSlug": "javascript",
"question": "지수는 콘솔에서 document.querySelector로 학습 페이지의 배경을 핑크로 바꾸고 제목 글자도 고쳤습니다. 그런데 F5를 누르자 전부 원래대로 돌아왔어요. 가장 알맞은 이유는 무엇일까요?",
"option1": "서버가 잘못된 변경을 감지하고 자동으로 되돌렸기 때문이다",
"option2": "콘솔에서 바꾼 내용은 일정 시간이 지나면 저절로 사라지기 때문이다",
"option3": "콘솔은 브라우저 속 모형(DOM)만 바꾸고, 새로고침은 서버의 원본을 다시 받아 모형을 새로 만들기 때문이다",
"option4": "querySelector는 요소를 찾기만 할 뿐 화면을 실제로 바꾸지는 못하기 때문이다",
"answerIndex": 2,
"explanation": "섹션 6에서 배웠듯 콘솔의 변경은 서버 원본이 아니라 내 브라우저가 들고 있는 DOM 모형에만 적용됩니다. 새로고침은 원본을 다시 받아 모형을 처음부터 다시 만드는 일이라 마음껏 실험해도 안전해요."
},
{
"courseSlug": "layout",
"question": "코스에서 소개한 8pt 그리드의 핵심 규칙은 무엇인가요?",
"option1": "모든 요소를 화면 가운데에 정렬한다",
"option2": "한 화면에 카드를 8개 이하로만 배치한다",
"option3": "모든 간격과 크기를 8의 배수로만 쓴다",
"option4": "글꼴 크기를 항상 8pt로 고정한다",
"answerIndex": 2,
"explanation": "8pt 그리드의 규칙은 딱 하나, 모든 간격·크기를 8의 배수(8, 16, 24, 32...)로만 쓰는 것입니다. 13, 18, 37 같은 어중간한 숫자가 사라지면 화면 전체가 같은 박자로 정돈돼 보입니다."
},
{
"courseSlug": "layout",
"question": "코스에서 설명한 '근접성'의 원리로 옳은 것은?",
"option1": "관련 있는 요소일수록 서로 다른 색으로 칠해 구분한다",
"option2": "관련 있는 것은 가깝게, 관련 없는 것은 멀게 배치한다",
"option3": "모든 요소 사이 간격을 16px로 똑같이 통일한다",
"option4": "그룹마다 반드시 선이나 박스를 그려 경계를 표시한다",
"answerIndex": 1,
"explanation": "근접성은 '붙어 있으면 한 팀, 떨어져 있으면 남남'이라는 원리입니다. 선이나 박스를 긋지 않아도 간격 차이만으로 그룹 관계가 보이며, 모든 간격이 똑같으면 오히려 어디서 끊어 읽을지 알 수 없게 됩니다."
},
{
"courseSlug": "layout",
"question": "그림과 여백이 많은 랜딩 페이지에서 가장 중요한 '시작하기' 버튼을 놓기 좋은 자리는 어디인가요?",
"option1": "화면 왼쪽 위, 로고 바로 옆",
"option2": "화면 정중앙, 제목 바로 아래",
"option3": "본문 첫 줄이 시작되는 왼쪽 끝",
"option4": "화면 오른쪽 아래, 시선이 끝나는 지점",
"answerIndex": 3,
"explanation": "그림과 여백이 많은 화면에서 시선은 Z 모양으로 움직이며, Z의 끝인 오른쪽 아래가 시선의 종착역입니다. 코스에서 랜딩 페이지의 시작하기 버튼이 대부분 오른쪽 아래에 있는 이유로 든 내용입니다."
},
{
"courseSlug": "layout",
"question": "화면이 좁아질 때 반응형 레이아웃에서 12칸 그리드가 '접히는' 방식으로 옳은 설명은?",
"option1": "컬럼 수는 12개 그대로 두고, 각 요소가 차지하는 칸 수를 늘린다",
"option2": "컬럼 수 자체를 12개에서 6개, 1개로 점점 줄여 나간다",
"option3": "데스크톱용과 모바일용 화면을 두 벌 만들어 바꿔 끼운다",
"option4": "요소 크기는 그대로 두고 화면을 좌우로 스크롤하게 만든다",
"answerIndex": 0,
"explanation": "칸(컬럼) 수는 12개 그대로이고, 카드가 차지하는 칸 수만 4칸에서 6칸, 12칸으로 바뀌면서 요소가 아래로 쌓입니다. 이렇게 접히는 기준이 되는 화면 폭을 브레이크포인트라고 부릅니다."
},
{
"courseSlug": "layout",
"question": "동아리 소개 카드에 제목, 설명, 버튼을 넣었는데 세 요소 사이 간격을 전부 16px로 똑같이 줬더니 어디까지가 한 묶음인지 안 보입니다. 코스에서 배운 대로 고치는 방법은?",
"option1": "모든 간격을 8px로 더 좁혀 세 요소를 한 덩어리로 만든다",
"option2": "제목과 설명 사이에 굵은 구분선을 먼저 그어 경계를 만든다",
"option3": "한 팀인 제목과 설명 사이는 좁히고, 버튼과의 간격은 확실히 넓힌다",
"option4": "세 요소를 모두 가운데 정렬해서 새로운 기준선을 만든다",
"answerIndex": 2,
"explanation": "근접성의 포인트는 간격의 '차이'입니다. 피그마 실습에서도 제목과 설명 간격은 8, 설명과 버튼 간격은 24로 두어 팀 안은 좁게, 팀 사이는 넓게 만들었습니다. 선을 긋기 전에 간격 차이로 먼저 그룹을 만드는 것이 코스의 핵심입니다."
},
{
"courseSlug": "linux-advanced",
"question": "터미널에 docker라고 입력했을 때, 셸이 실행할 프로그램을 찾는 방법으로 옳은 것은?",
"option1": "홈 디렉터리부터 하위 폴더 전체를 훑어 가장 최신 파일을 실행한다",
"option2": "시스템에 설치된 모든 프로그램 목록에서 이름을 조회해 실행한다",
"option3": "PATH에 적힌 폴더들을 왼쪽부터 순서대로 뒤져 처음 발견한 것을 실행한다",
"option4": "/usr/bin 폴더 하나만 확인하고 없으면 바로 오류를 낸다",
"answerIndex": 2,
"explanation": "섹션 1에서 PATH는 '명령어를 찾을 때 뒤져 볼 폴더 목록'이며, 셸은 왼쪽 폴더부터 순서대로 찾아 처음 발견한 것을 실행한다고 설명한다. 그래서 command not found는 프로그램이 PATH에 등록된 폴더 밖에 있다는 뜻이다."
},
{
"courseSlug": "linux-advanced",
"question": "리다이렉션 기호 >와 >>의 차이를 바르게 설명한 것은?",
"option1": ">는 파일 끝에 이어 붙이고, >>는 기존 내용을 덮어쓴다",
"option2": ">는 기존 내용을 덮어쓰고, >>는 파일 끝에 이어 붙인다",
"option3": ">는 화면 출력용이고, >>는 파일 저장 전용 기호다",
"option4": ">는 출력을 파일로 보내고, >>는 입력을 파일에서 읽어 온다",
"answerIndex": 1,
"explanation": "섹션 4에서 >는 덮어쓰기(기존 내용 삭제), >>는 이어 붙이기라고 강조한다. 로그를 모을 때 >를 잘못 쓰면 어제까지의 기록이 통째로 사라진다."
},
{
"courseSlug": "linux-advanced",
"question": "크론 예약 줄 \"0 4 * * * /home/ubuntu/backup.sh\"가 실행되는 시각은 언제인가?",
"option1": "4시간마다 한 번씩",
"option2": "매시 4분마다",
"option3": "매월 4일 0시에",
"option4": "매일 새벽 4시 0분에",
"answerIndex": 3,
"explanation": "섹션 3의 별 5개 문법은 왼쪽부터 '분·시·일·월·요일'이다. 분=0, 시=4, 나머지는 *(아무 때나)이므로 매일 새벽 4시 0분에 백업 스크립트가 실행된다."
},
{
"courseSlug": "linux-advanced",
"question": "sudo systemctl enable caddy 명령이 하는 일은 무엇인가?",
"option1": "서버가 부팅될 때 caddy가 자동으로 시작되도록 등록한다",
"option2": "caddy 서비스를 즉시 시작하고 현재 상태를 출력한다",
"option3": "caddy가 죽지 않도록 메모리를 우선 할당해 고정한다",
"option4": "caddy의 로그를 /var/log 폴더에 기록하도록 설정한다",
"answerIndex": 0,
"explanation": "섹션 5에서 enable은 '부팅 시 자동 시작 등록'이라고 설명한다. 이를 빼먹으면 정전이나 EC2 재시작 후 서비스가 살아나지 않아 '사이트가 안 열려요' 사태가 난다."
},
{
"courseSlug": "linux-advanced",
"question": "몇 달 동안 잘 돌던 서버가 어느 날 이유 없이 갑자기 죽었다. 코스에서 말한 이 사고의 단골 범인과 확인 명령을 고르면?",
"option1": "크론이 백업을 너무 자주 실행해서 — crontab -e로 주기를 줄인다",
"option2": "로그가 계속 쌓여 디스크가 가득 차서 — df -h로 사용률을 확인한다",
"option3": "PATH 환경변수가 초기화되어서 — echo $PATH로 값을 확인한다",
"option4": "Caddy가 재시작을 반복해서 — systemctl stop caddy를 실행한다",
"answerIndex": 1,
"explanation": "섹션 6의 '디스크 꽉 참 주의보'에서 로그를 방치하면 디스크가 가득 차 멀쩡한 서비스가 갑자기 죽으며, 이것이 '잘 되던 서버가 이유 없이 죽었다'의 단골 범인이라고 설명한다. 예방책은 df -h로 디스크를 주기적으로 확인하는 습관이다."
},
{
"courseSlug": "linux",
"question": "터미널에서 pwd 명령을 입력하면 어떤 일이 일어날까요?",
"option1": "현재 폴더 안에 있는 파일 목록을 보여준다",
"option2": "어디에 있든 내 홈 폴더로 순간이동한다",
"option3": "지금 내가 있는 위치(현재 작업 디렉터리)를 출력한다",
"option4": "부모 폴더로 한 칸 위로 이동한다",
"answerIndex": 2,
"explanation": "pwd는 Print Working Directory의 약자로, 코스 섹션 3 '길 찾기 명령'에서 배운 \"나 지금 어디지?\"에 답하는 명령입니다. 파일 목록은 ls, 이동은 cd가 담당해요."
},
{
"courseSlug": "linux",
"question": "윈도우에서 파일을 지우는 것과 비교했을 때, 리눅스 rm 명령의 특징으로 옳은 것은?",
"option1": "지운 파일이 휴지통으로 들어가 나중에 되살릴 수 있다",
"option2": "휴지통 없이 즉시, 영구히 삭제된다",
"option3": "sudo를 붙여 관리자 권한이 있어야만 실행된다",
"option4": "폴더도 아무 옵션 없이 안의 내용까지 함께 지워진다",
"answerIndex": 1,
"explanation": "코스 섹션 4의 경고처럼 rm에는 휴지통이 없어 즉시·영구 삭제됩니다. 폴더를 지우려면 -r(recursive) 옵션을 따로 붙여야 하고, 지우기 전 pwd와 ls로 두 번 확인하는 습관이 필요해요."
},
{
"courseSlug": "linux",
"question": "코스에서 '실무에서 제일 많이 치는 조합'으로 소개한 tail -f app.log | grep ERROR 를 실행하면 어떻게 될까요?",
"option1": "app.log의 앞에서 20줄 중 ERROR가 든 줄만 보여준다",
"option2": "app.log 전체를 한 번에 좌르륵 출력하고 바로 끝난다",
"option3": "ERROR라는 이름의 새 로그 파일을 만들어 저장한다",
"option4": "실시간으로 쌓이는 로그 중 ERROR가 포함된 줄만 골라 보여준다",
"answerIndex": 3,
"explanation": "tail -f는 파일에 새 줄이 쌓이는 걸 실시간 중계하고, grep은 원하는 단어가 든 줄만 골라냅니다. 섹션 5에서 이 둘을 파이프(|)로 이은 것을 \"실시간 CCTV에 형광펜 필터 달기\"라고 비유했어요."
},
{
"courseSlug": "linux",
"question": "ls -l 결과에 -rwxr-xr-- 라고 표시된 파일이 있습니다. 이 파일에 대한 그룹(group)의 권한은?",
"option1": "읽기와 실행은 되지만 쓰기는 안 된다",
"option2": "읽기·쓰기·실행이 전부 가능하다",
"option3": "읽기만 가능하고 쓰기·실행은 안 된다",
"option4": "실행만 가능하고 읽기·쓰기는 안 된다",
"answerIndex": 0,
"explanation": "권한은 첫 글자(파일/폴더) 뒤로 [주인][그룹][모두] 순서로 세 글자씩 세 묶음입니다. 가운데 묶음 r-x가 그룹 권한이므로 읽기(r)·실행(x)은 되고 쓰기(w)는 안 됩니다(섹션 6)."
},
{
"courseSlug": "linux",
"question": "\"서비스가 느려요!\"라는 신고를 받은 수습 개발자가 서버에서 어떤 프로그램이 CPU를 많이 쓰는지 실시간으로 확인하려 합니다. 코스에서 '작업관리자의 터미널판'이라 소개한 명령은?",
"option1": "cat — 파일 내용을 한 번에 전부 출력한다",
"option2": "ssh — 암호화된 통로로 원격 서버에 접속한다",
"option3": "top — 프로세스 목록을 실시간으로 모니터링한다",
"option4": "chmod — 파일에 실행(x) 권한을 부여한다",
"answerIndex": 2,
"explanation": "섹션 7에서 top을 윈도우 작업관리자의 터미널판으로 소개하며, 서버가 느려지면 \"누가 CPU를 다 먹고 있지?\" 하고 top부터 연다고 설명합니다. ps는 목록, top은 실시간 화면이에요."
},
{
"courseSlug": "mainboard-power",
"question": "이 코스에서 메인보드를 비유한 표현으로 가장 알맞은 것은?",
"option1": "도시 전체에 피를 돌리는 심장",
"option2": "부품들을 서로 연결하는 도시의 도로망",
"option3": "변두리 교통을 정리하는 교통관제센터",
"option4": "바깥세상과 물자를 주고받는 항구와 공항",
"answerIndex": 1,
"explanation": "섹션 1에서 메인보드는 CPU(시청)·RAM(창고) 같은 부품들을 잇는 '도시의 도로망'으로 소개됩니다. 심장은 파워, 교통관제센터는 칩셋, 항구·공항은 후면 I/O 패널의 비유예요."
},
{
"courseSlug": "mainboard-power",
"question": "후면 패널의 파란색 USB-A 포트에 대한 설명으로 옳은 것은?",
"option1": "USB 2.0 규격이라 키보드·마우스 전용이다",
"option2": "방향 없이 꽂을 수 있는 요즘 표준 포트다",
"option3": "USB 3.x 규격이라 검은색 포트보다 훨씬 빠르다",
"option4": "내장그래픽용 화면 출력에 쓰는 포트다",
"answerIndex": 2,
"explanation": "섹션 3에서 파란색은 USB 3.x, 검은색은 USB 2.0이며 파란 포트가 이론상 10배 이상 빠르다고 배웠어요. 그래서 외장 SSD는 꼭 파란 포트에 꽂아야 제 속도가 납니다."
},
{
"courseSlug": "mainboard-power",
"question": "파워(PSU)를 고를 때 '정격 500W'라는 표기가 뜻하는 것은?",
"option1": "500W를 계속, 안정적으로 낼 수 있다는 보증이다",
"option2": "순간적으로만 500W까지 낼 수 있다는 뜻이다",
"option3": "벽 콘센트에서 항상 500W를 끌어온다는 뜻이다",
"option4": "부품 소비 전력의 합계가 500W여야 한다는 뜻이다",
"answerIndex": 0,
"explanation": "섹션 5에서 '정격'은 그 출력을 지속적으로 안정하게 낼 수 있다는 보증이고, '최대 출력'은 순간만 가능한 말장난이라고 배웠어요. 싸구려 파워가 최대 출력을 크게 적는 눈속임을 쓰기 때문에 반드시 정격 기준으로 골라야 합니다."
},
{
"courseSlug": "mainboard-power",
"question": "전원을 켜면 BIOS/UEFI가 가장 먼저 수행하는 POST 단계에서 하는 일은?",
"option1": "Windows 부트로더를 불러와 OS를 시작한다",
"option2": "어느 저장장치에서 부팅할지 순서를 정한다",
"option3": "CPU 온도에 맞춰 팬 속도를 자동으로 조절한다",
"option4": "CPU·RAM 등 부품이 제대로 있는지 점호를 한다",
"answerIndex": 3,
"explanation": "섹션 4에서 POST는 아침 조회의 출석 체크처럼 부품을 점호하는 단계이고, 문제가 있으면 비프음이나 LED로 알려 준다고 배웠어요. 부팅 순서 결정과 OS 바통 터치는 그다음 단계입니다."
},
{
"courseSlug": "mainboard-power",
"question": "친구가 그래픽카드를 새로 장착했는데 모니터에 화면이 안 나온다고 합니다. 코스에서 '단골 실수 1위'로 꼽은, 가장 먼저 확인해야 할 것은?",
"option1": "케이스가 ATX 폼팩터를 지원하는지 확인한다",
"option2": "UEFI에 들어가 부팅 순서를 바꾸고 저장한다",
"option3": "모니터 케이블이 보드가 아닌 그래픽카드 쪽 HDMI/DP에 꽂혔는지 본다",
"option4": "파워의 80PLUS 등급이 Gold 이상인지 확인한다",
"answerIndex": 2,
"explanation": "섹션 3에서 그래픽카드를 꽂았다면 모니터는 보드의 HDMI가 아니라 그래픽카드 쪽 HDMI/DP에 연결해야 하며, 이것이 단골 실수 1위라고 배웠어요. 보드 포트는 내장그래픽용 출력이기 때문입니다."
},
{
"courseSlug": "memory-storage",
"question": "'Random Access Memory'라는 이름이 붙은 이유로 코스에서 설명한 것은 무엇인가?",
"option1": "데이터를 무작위 순서로 뒤섞어 저장해서 해킹에 강하기 때문",
"option2": "어느 주소(칸)에 있든 똑같은 속도로 바로 접근할 수 있기 때문",
"option3": "전원이 꺼질 때 데이터가 무작위로 사라지는 성질이 있기 때문",
"option4": "CPU가 남는 시간에 임의의 칸을 골라 검사하는 방식이기 때문",
"answerIndex": 1,
"explanation": "RAM은 번호(주소)가 붙은 사물함 벽과 같아서 1번부터 차례로 뒤질 필요 없이 어느 칸이든 같은 속도로 즉시 꺼낼 수 있고, 그래서 Random Access(임의 접근) Memory라고 부른다(섹션 1)."
},
{
"courseSlug": "memory-storage",
"question": "코스의 비유에서 RAM을 '책상', SSD를 '책장'에 비유한 핵심 이유는 무엇인가?",
"option1": "책상은 크기를 늘릴 수 없지만 책장은 계속 늘릴 수 있기 때문",
"option2": "책상은 여럿이 나눠 쓰고 책장은 한 사람만 쓰는 공간이기 때문",
"option3": "책상 위는 자주 정리해야 하지만 책장은 자동으로 정리되기 때문",
"option4": "책상은 빠르지만 전원이 꺼지면 치워지고, 책장은 느리지만 그대로 남기 때문",
"answerIndex": 3,
"explanation": "RAM은 손만 뻗으면 닿는 책상처럼 빠르지만 휘발성이라 전원이 꺼지면 전부 사라지고, SSD는 걸어가야 하는 책장처럼 느리지만 비휘발성이라 내용이 그대로 남는다(섹션 1)."
},
{
"courseSlug": "memory-storage",
"question": "같은 16GB 용량이라도 '16GB 1개'보다 '8GB 2개'를 짝지어 꽂는 쪽이 보통 더 나은 이유는?",
"option1": "듀얼채널이 활성화되어 CPU와 램 사이 전송 대역폭이 최대 2배가 되기 때문",
"option2": "램 2개가 서로 데이터를 백업해 줘서 내용이 사라질 위험이 줄기 때문",
"option3": "램 하나당 발열이 절반으로 줄어 클럭 속도가 자동으로 올라가기 때문",
"option4": "나중에 증설할 때 쓸 수 있는 빈 슬롯의 여유가 더 많아지기 때문",
"answerIndex": 0,
"explanation": "램을 같은 색 슬롯에 짝지어 꽂으면 CPU와 램 사이가 왕복 2차선 도로처럼 되는 듀얼채널이 활성화되어 대역폭이 최대 2배가 된다(섹션 3). 코스는 오히려 증설 여유는 줄어든다고 설명한다."
},
{
"courseSlug": "memory-storage",
"question": "컴퓨터가 몹시 느려졌는데 CPU 사용률은 낮고, 디스크 사용률은 100%, 램 사용률은 90%를 넘는다. 코스에 따르면 가장 유력한 원인은?",
"option1": "CPU 코어 수가 부족해서 작업들이 계산 순서를 기다리는 상태",
"option2": "SSD의 TBW 수명이 다해서 읽기 속도가 급격히 떨어진 상태",
"option3": "램 부족으로 스왑이 일어나 램과 SSD 창고 사이를 계속 왕복하는 상태",
"option4": "듀얼채널이 풀려서 램의 전송 대역폭이 절반으로 줄어든 상태",
"answerIndex": 2,
"explanation": "세 증상이 동시에 나타나면 범인은 십중팔구 램 부족(스왑)이다. 수백~수천 배 느린 SSD의 스왑 공간을 계속 왕복하느라 정작 일을 못 하고, CPU는 데이터가 도착하길 기다리며 놀게 된다(섹션 6)."
},
{
"courseSlug": "memory-storage",
"question": "16GB 노트북에서 IntelliJ, React 개발 서버, Spring Boot, Docker, 브라우저 탭 30개를 동시에 띄우자 창을 전환할 때마다 1~2초씩 멈칫한다. 코스의 실습대로 '스왑이 지금 일어나는 중인지'를 실시간으로 확인하려면 리소스 모니터(resmon)에서 무엇을 봐야 하는가?",
"option1": "[CPU] 탭의 코어별 사용률 그래프가 치솟는지",
"option2": "[메모리] 탭의 '하드 폴트/초' 그래프가 치솟는지",
"option3": "[디스크] 탭의 파일별 읽기 속도 목록이 비어 있는지",
"option4": "[네트워크] 탭의 프로세스별 전송량이 줄어드는지",
"answerIndex": 1,
"explanation": "하드 폴트는 '찾는 데이터가 램에 없어서 디스크(스왑)까지 다녀온 횟수'이므로, 이 그래프가 계속 치솟으면 섹션 6에서 배운 스왑 연쇄가 지금 일어나고 있다는 뜻이다(섹션 7 실습)."
},
{
"courseSlug": "mobile-design",
"question": "코스에서 제시한 '눌리는 모든 요소'의 터치 타깃 최소 크기는 얼마인가?",
"option1": "24×24px — 아이콘 표준 크기에 맞춰서",
"option2": "44×44px — 어른 엄지 접촉면(약 10mm)을 기준으로",
"option3": "16×16px — 본문 최소 글자 크기와 통일해서",
"option4": "60×60px — 태블릿 화면까지 고려한 여유 크기",
"answerIndex": 1,
"explanation": "섹션 1 '엄지의 법칙'에서 마우스 커서는 바늘 끝이지만 엄지는 도장이라며, 눌리는 요소는 최소 44×44px을 확보해야 한다고 설명한다. 어른 엄지 접촉면 약 10mm가 화면에서 대략 44px 이상에 해당하기 때문이다."
},
{
"courseSlug": "mobile-design",
"question": "모바일 우선(Mobile First) 방식의 CSS 작성 순서로 옳은 것은?",
"option1": "큰 화면 스타일을 기본값으로 두고 max-width 미디어 쿼리로 좁은 화면에서 덜어낸다",
"option2": "화면 크기별로 CSS 파일을 따로 만들어 기기마다 다른 파일을 불러온다",
"option3": "좁은 화면 스타일을 기본값으로 두고 min-width 미디어 쿼리로 넓은 화면에서 더한다",
"option4": "JS로 화면 폭을 감지해 데스크톱용과 모바일용 컴포넌트를 통째로 교체한다",
"answerIndex": 2,
"explanation": "섹션 2에서 모바일 우선은 좁은 화면용 CSS를 기본값으로 쓰고 화면이 넓어질 때 min-width로 스타일을 '더해 가는' 방식이라고 설명한다. max-width로 '빼며' 내려가는 데스크톱 우선과 정반대 순서다."
},
{
"courseSlug": "mobile-design",
"question": "index.html에 viewport 메타 태그가 없으면 모바일 브라우저는 어떻게 동작하는가?",
"option1": "PC용 페이지로 가정하고 980px짜리 가상 화면에 그린 뒤 축소해서 보여준다",
"option2": "페이지 렌더링을 중단하고 데스크톱 전용 화면으로 리다이렉트한다",
"option3": "기기의 실제 폭을 자동으로 감지해 처음부터 1:1 크기로 그려 준다",
"option4": "화면을 가로 모드로 강제 회전시켜 부족한 폭을 확보한다",
"answerIndex": 0,
"explanation": "섹션 3에서 viewport 태그가 없으면 모바일 브라우저가 '이건 PC용 페이지겠지' 하고 980px 가상 화면에 그린 뒤 축소해 보여줘서 글씨가 개미만 해진다고 설명한다. 그래서 width=device-width, initial-scale=1 한 줄이 필요하다."
},
{
"courseSlug": "mobile-design",
"question": "코스가 말하는 모바일 제스처 설계의 '정석'에 가장 가까운 것은?",
"option1": "다른 앱과 차별화되도록 우리 서비스만의 새로운 제스처를 발명한다",
"option2": "화면을 깔끔하게 만들기 위해 버튼을 없애고 스와이프로만 기능을 제공한다",
"option3": "제스처는 배우기 어려우므로 모바일 웹에서는 아예 사용하지 않는다",
"option4": "기존 관습을 따르되, 제스처는 보이는 버튼과 짝을 이루는 지름길로만 제공한다",
"answerIndex": 3,
"explanation": "섹션 4의 두 규칙이다 — 사용자의 근육 기억인 관습을 따를 것, 그리고 제스처는 눈에 보이지 않으니 반드시 보이는 버튼과 짝을 이뤄 '아는 사람의 지름길'로만 쓸 것. 스와이프로만 가능한 기능은 없는 거나 마찬가지라고 설명한다."
},
{
"courseSlug": "mobile-design",
"question": "수습 A가 개발자 도구 기기 툴바(375px)로 플랫폼을 점검하다가, 넓은 표 하나 때문에 페이지 전체가 좌우로 덜렁거리는 것을 발견했다(FE-06 티켓과 같은 증상). 코스에서 배운 정석 해결법은?",
"option1": "표의 글자 크기를 확 줄여 375px 폭 안에 표 전체가 들어가게 만든다",
"option2": "표를 이미지로 캡처해 넣어서 폭이 넘치는 문제 자체를 없앤다",
"option3": "overflow-x: auto를 준 컨테이너 안에 표를 가둬 그 안에서만 스크롤되게 한다",
"option4": "body에 width: 600px을 고정해 모든 기기에서 같은 폭으로 보이게 한다",
"answerIndex": 2,
"explanation": "섹션 5에서 표처럼 원래 넓은 콘텐츠는 페이지를 늘리는 대신 overflow-x: auto를 준 컨테이너 안에서만 스크롤되게 가두는 것이 정석이라고 설명한다. 범인 요소 하나가 페이지 전체를 덜렁거리게 만드는 '의도치 않은 가로 스크롤'의 표준 처방이다."
},
{
"courseSlug": "net-tools",
"question": "ping 명령이 알려 주는 두 가지 핵심 정보는 무엇인가?",
"option1": "상대 서버의 운영체제 종류와 열려 있는 포트 목록",
"option2": "상대 서버의 생존 여부와 왕복 응답 시간(ms)",
"option3": "내 PC의 IPv4 주소와 기본 게이트웨이 주소",
"option4": "목적지까지 거치는 라우터(홉) 목록과 구간별 속도",
"answerIndex": 1,
"explanation": "코스에서 ping은 서버 문 앞에서 '노크'하고 대답이 오기까지의 왕복 시간을 재는 명령으로 소개된다. 대답 여부로 생존을 확인하고, 시간=8ms 같은 숫자로 응답 속도를 측정한다."
},
{
"courseSlug": "net-tools",
"question": "코스는 nslookup을 '전화번호부에 직접 전화를 걸어 물어보는 것'에 비유한다. 여기서 전화번호부가 가리키는 것은?",
"option1": "우리 집의 정문 역할을 하는 공유기(기본 게이트웨이)",
"option2": "서버 현관에서 응대하는 안내데스크(Caddy)",
"option3": "도메인 이름을 IP 숫자로 바꿔 주는 DNS",
"option4": "PC에 IP 주소를 자동으로 나눠 주는 DHCP",
"answerIndex": 2,
"explanation": "컴퓨터는 이름이 아니라 IP 숫자로 서로를 찾기 때문에, 이름을 번호로 바꿔 주는 전화번호부가 필요하다. 코스에서 그 전화번호부가 바로 DNS이고, nslookup은 거기에 직접 질문하는 명령이다."
},
{
"courseSlug": "net-tools",
"question": "netstat -ano 출력에서 상태(State)가 LISTENING인 줄은 무엇을 의미하는가?",
"option1": "요청이 오면 받으려고 대기 중인 서버 프로그램이 있다",
"option2": "상대 서버와 지금 데이터를 주고받는 통화 중인 연결이다",
"option3": "연결이 끊겨서 재접속을 기다리고 있는 오류 상태다",
"option4": "방화벽이 그 포트로 들어오는 접속을 차단하고 있다",
"answerIndex": 0,
"explanation": "코스에서 LISTENING은 \"전화 오면 받을게요\" 하고 대기 중인 서버 프로그램으로 설명된다. 예시에서 :5173(Vite 개발 서버)과 :5432(PostgreSQL)가 이 상태였고, 지금 통화 중인 연결은 ESTABLISHED다."
},
{
"courseSlug": "net-tools",
"question": "tracert 실행 결과 중간 홉 몇 개가 '* * *'로 나왔지만 마지막 줄에서 목적지에 도착했다. 코스에 따른 올바른 해석은?",
"option1": "경로 중간이 끊긴 것이므로 통신사에 신고해야 한다",
"option2": "패킷 손실이 생긴 것이므로 회선이 불안정한 상태다",
"option3": "DNS 조회가 실패한 것이므로 nslookup으로 확인해야 한다",
"option4": "그 라우터가 보안상 대답을 생략했을 뿐 경로는 정상이다",
"answerIndex": 3,
"explanation": "코스는 보안상 대답을 생략하는 라우터가 많으니 중간의 '* * *'에 당황하지 말라고 강조한다. 진짜 문제는 어느 홉 이후로 전부 끊기고 목적지에 도착하지 못하는 경우다."
},
{
"courseSlug": "net-tools",
"question": "동아리방 PC에서 웹사이트가 안 열린다. ipconfig로 내 IP가 정상임을 확인했고 게이트웨이 ping도 성공, ping 8.8.8.8도 성공했지만 nslookup naver.com은 실패했다. 진단 순서도에 따른 원인은?",
"option1": "공유기 문제이므로 공유기를 재부팅해야 한다",
"option2": "집 밖 회선 문제이므로 통신사에 연락해야 한다",
"option3": "회선은 정상인데 DNS가 고장 난 상태다",
"option4": "네이버 서버가 아픈 것이므로 기다리면 된다",
"answerIndex": 2,
"explanation": "순서도의 핵심 분기점: IP 숫자(8.8.8.8)로는 통신이 되는데 이름 찾기(nslookup)가 실패하면 '회선 O, DNS X'로 원인을 쪼갤 수 있다. 코스에서 \"인터넷은 되는데 사이트만 안 열림\"의 단골 범인으로 소개된 경우다."
},
{
"courseSlug": "network",
"question": "랜선(UTP 케이블) 속 구리선 8가닥이 두 가닥씩 꼬여 있는 이유는 무엇일까요?",
"option1": "구리선 길이를 늘려서 신호가 더 멀리까지 가게 하려고",
"option2": "케이블을 더 튼튼하게 만들어 잘 끊어지지 않게 하려고",
"option3": "전자파 간섭이 두 선에 거의 똑같이 들어와 서로 상쇄되게 하려고",
"option4": "8가닥의 색 순서를 눈으로 구분하기 쉽게 하려고",
"answerIndex": 2,
"explanation": "두 선을 꼬아 놓으면 전자파 간섭이 두 선에 거의 똑같이 들어와 서로 상쇄됩니다. 섹션 1에서 '시끄러운 교실에서 같은 소음을 듣는 두 사람' 비유로 설명한 트위스티드 페어의 원리예요."
},
{
"courseSlug": "network",
"question": "코스에서 DNS를 '인터넷의 전화번호부'라고 불렀습니다. DNS가 하는 일로 알맞은 것은?",
"option1": "도메인 이름을 물어보면 그에 해당하는 IP 주소를 알려 준다",
"option2": "큰 데이터를 패킷으로 쪼개고 도착지에서 순서대로 조립한다",
"option3": "집 안에 새로 접속한 기기마다 사설 IP를 자동으로 나눠 준다",
"option4": "브라우저와 서버가 주고받는 대화를 암호화해 엿보지 못하게 한다",
"answerIndex": 0,
"explanation": "사람은 이름(도메인)을 외우고 컴퓨터는 번호(IP)로 통신하기 때문에, DNS가 '이름 → 번호'를 찾아 주는 전화번호부 역할을 합니다. 섹션 5의 핵심 개념이에요."
},
{
"courseSlug": "network",
"question": "192.168.0.5 같은 사설 IP만으로는 바깥 인터넷에서 우리 집 PC를 직접 찾아올 수 없습니다. 그 이유로 알맞은 것은?",
"option1": "사설 IP는 전송 속도가 느려서 외부 통신에는 쓸 수 없기 때문에",
"option2": "사설 IP는 숫자 범위가 0~255를 벗어나 규격에 맞지 않기 때문에",
"option3": "사설 IP는 기기를 켤 때마다 완전히 다른 주소로 바뀌기 때문에",
"option4": "사설 IP는 집 네트워크 안에서만 통하는 '호수'라서 옆 집에도 같은 주소가 있을 수 있기 때문에",
"answerIndex": 3,
"explanation": "섹션 2의 아파트 비유처럼 사설 IP는 '302호' 같은 호수여서 우리 아파트 안에서만 통하고, 옆 아파트에도 같은 302호가 있습니다. 바깥에서 찾아오려면 전 세계에서 유일한 공인 IP(도로명 주소)가 필요해요."
},
{
"courseSlug": "network",
"question": "데이터를 보낼 때 IP 주소만으로는 부족하고 포트 번호가 함께 필요한 이유는 무엇일까요?",
"option1": "포트 번호가 있어야 데이터 전송 속도가 훨씬 빨라지기 때문에",
"option2": "한 서버(건물) 안에 여러 프로그램(방)이 있어서 어느 프로그램으로 갈지 정해야 하기 때문에",
"option3": "IP 주소는 나라 안에서만 통하고 포트 번호가 국제 주소 역할을 하기 때문에",
"option4": "포트 번호로 데이터를 암호화해서 다른 사람이 엿보지 못하게 하기 때문에",
"answerIndex": 1,
"explanation": "섹션 3의 비유대로 IP는 건물 주소, 포트는 방 번호입니다. 한 서버에 웹(443), Gitea(3000), DB(5432)처럼 여러 서비스가 살기 때문에 '어느 건물의 몇 호'까지 합쳐져야 데이터가 정확한 프로그램에 도착해요."
},
{
"courseSlug": "network",
"question": "친구와 실시간 영상통화를 하는데 화면이 잠깐 뭉개졌다가, 끊긴 부분을 다시 받지 않고 곧바로 최신 화면으로 이어졌습니다. 이 서비스가 썼을 가능성이 높은 배송 방식과 그 이유는?",
"option1": "TCP — 상자마다 번호를 붙여 반드시 순서대로 조립해야 하므로",
"option2": "TCP — 분실된 패킷을 다시 보내 한 조각도 빠지지 않게 하므로",
"option3": "UDP — 지나간 화면을 재전송받는 것보다 최신 데이터를 빨리 받는 게 중요하므로",
"option4": "UDP — 보내기 전에 3-way 악수로 연결을 맺어 확실하게 전달하므로",
"answerIndex": 2,
"explanation": "섹션 6에서 게임·영상통화처럼 '좀 깨져도 빠른 게 중요할 때'는 UDP를 쓴다고 배웠어요. 0.1초 전 화면은 지금 다시 받아 봐야 이미 과거라서, 분실된 건 버리고 최신 것을 받는 편이 낫습니다."
},
{
"courseSlug": "ops-basics",
"question": "장애의 3대 신호 중 사용자에게 '서버 오류' 페이지가 보이는 500 에러가 떴을 때, 코스가 꼽은 흔한 범인 후보는 무엇인가?",
"option1": "DB 느린 쿼리나 트래픽 폭주",
"option2": "도메인이나 인증서 설정 문제",
"option3": "백엔드 예외(코드 버그)나 DB 연결 끊김",
"option4": "서버 다운이나 컨테이너 죽음",
"answerIndex": 2,
"explanation": "500 에러는 요청은 도착했는데 처리 중 예외가 터진 상태로, 범인은 대부분 백엔드 코드나 DB 연결이다. DB 느린 쿼리는 '느림', 서버 다운이나 도메인·인증서 문제는 '접속 불가'의 범인 후보다."
},
{
"courseSlug": "ops-basics",
"question": "코스에서 배운 '원인 좁히기'는 정전 때 동네 전체 → 두꺼비집 → 방 스위치 → 전구 순서로 확인하듯 바깥에서 안쪽으로 진행한다. 올바른 확인 순서는?",
"option1": "DB → 앱 로그 → 컨테이너 → 서버",
"option2": "서버 → 컨테이너 → 앱 로그 → DB",
"option3": "컨테이너 → 서버 → DB → 앱 로그",
"option4": "앱 로그 → DB → 서버 → 컨테이너",
"answerIndex": 1,
"explanation": "섹션 3의 핵심은 큰 범위에서 작은 범위로 좁히는 것이다. 서버 생존(ping·SSH) → 컨테이너(docker ps) → 앱 로그(docker logs) → DB 순서로 확인해야 헛수고가 없다."
},
{
"courseSlug": "ops-basics",
"question": "docker ps를 쳤더니 어떤 컨테이너의 STATUS가 'Exited (137)'로 나왔다. 코스 설명에 따르면 137 코드가 자주 의미하는 것은?",
"option1": "정상적으로 가동을 마치고 종료됐다는 뜻",
"option2": "죽었다 살아나기를 반복하는 중이라는 뜻",
"option3": "디스크 용량 부족으로 기록이 멈췄다는 뜻",
"option4": "메모리 부족(OOM)으로 강제 종료됐다는 뜻",
"answerIndex": 3,
"explanation": "코스의 docker ps STATUS 읽는 법에서 Exited (137)은 메모리 부족(OOM)으로 강제 종료됐을 때 자주 보이는 코드라고 설명한다. 죽었다 살아나기를 반복하는 상태는 'Restarting'으로 표시된다."
},
{
"courseSlug": "ops-basics",
"question": "'재시작의 정석'에 따르면 docker restart 명령을 치기 전에 가장 먼저 해야 하는 일은 무엇인가?",
"option1": "docker logs로 로그를 파일로 저장해 증거부터 확보한다",
"option2": "docker compose down으로 전체 컨테이너를 내린다",
"option3": "curl로 사이트가 200을 반환하는지 확인한다",
"option4": "최근 백업 파일로 DB를 즉시 복구한다",
"answerIndex": 0,
"explanation": "재시작은 병을 고치는 동시에 현장을 치워 버리는 행동이라, 재시작 전에 로그부터 저장하지 않으면 원인을 영영 모르게 된다. curl 확인은 재시작 후 마지막 단계이고, 전체를 내리는 명령은 코스가 '절대 하지 말 것'으로 경고한다."
},
{
"courseSlug": "ops-basics",
"question": "아침에 확인해 보니 학습 플랫폼 사이트 자체는 잘 열리는데, 로그인 버튼만 누르면 500 에러가 난다. 코스의 원인 좁히기 논리대로라면 가장 먼저 무엇을 해야 할까?",
"option1": "ping과 SSH로 서버가 살아 있는지부터 확인한다",
"option2": "도메인과 인증서 설정이 꼬였는지 확인한다",
"option3": "서버와 Caddy는 무죄로 보고 백엔드(Spring Boot) 로그부터 확인한다",
"option4": "제1용의자인 최근 배포 내역을 확인하고 이전 버전으로 롤백한다",
"answerIndex": 2,
"explanation": "사이트가 '열린다'는 사실 자체가 서버와 Caddy는 살아 있다는 알리바이가 되어 용의선상에서 빠진다. 시나리오 B처럼 범위가 이미 백엔드·DB로 좁혀졌으므로 백엔드 로그부터 보는 것이 순서다."
},
{
"courseSlug": "os",
"question": "코스에서 컴퓨터를 건물에 비유할 때, 운영체제(OS)는 무엇에 해당한다고 설명했나요?",
"option1": "건물에 들어와 사는 입주 손님",
"option2": "전기·수도 같은 건물 시설",
"option3": "앱과 하드웨어 사이의 총괄 매니저",
"option4": "건물을 처음 지을 때 쓰는 설계도",
"answerIndex": 2,
"explanation": "섹션 1에서 CPU·메모리·디스크는 건물 시설, 앱은 입주 손님, 그 사이에서 자원을 배분하고 질서를 지키는 총괄 매니저가 운영체제라고 비유했습니다."
},
{
"courseSlug": "os",
"question": "코스의 '레시피와 냄비' 비유에 따르면, 프로그램과 프로세스의 차이로 옳은 것은 무엇인가요?",
"option1": "프로그램은 실행 중인 상태이고, 프로세스는 디스크에 저장된 파일이다",
"option2": "프로그램은 디스크에 저장된 파일이고, 프로세스는 실행되어 CPU와 메모리를 쓰며 살아 움직이는 상태다",
"option3": "둘은 같은 말인데 크롬에서는 프로그램, 윈도우에서는 프로세스라고 부른다",
"option4": "프로그램은 여러 개 띄울 수 있지만, 프로세스는 컴퓨터에 항상 하나만 존재한다",
"answerIndex": 1,
"explanation": "섹션 3에서 프로그램은 디스크에 가만히 있는 레시피(파일), 프로세스는 그 레시피로 지금 요리 중인 냄비라고 설명했습니다. 크롬 하나로도 프로세스는 여러 개 생길 수 있어요."
},
{
"courseSlug": "os",
"question": "전원 버튼을 누른 뒤 로그인 화면이 나올 때까지, 코스에서 배운 부팅 4단계의 올바른 순서는 무엇인가요?",
"option1": "펌웨어(UEFI) → 부트로더 → 커널 적재 → 서비스·로그인 화면",
"option2": "부트로더 → 펌웨어(UEFI) → 커널 적재 → 서비스·로그인 화면",
"option3": "커널 적재 → 펌웨어(UEFI) → 부트로더 → 서비스·로그인 화면",
"option4": "펌웨어(UEFI) → 커널 적재 → 부트로더 → 서비스·로그인 화면",
"answerIndex": 0,
"explanation": "섹션 4의 부팅 릴레이: 펌웨어가 하드웨어 점호(POST)를 하고, 부트로더가 디스크에서 커널을 찾아 메모리에 올리고, 커널이 드라이버와 함께 시동을 건 뒤 서비스들이 켜지며 로그인 화면이 나옵니다."
},
{
"courseSlug": "os",
"question": "크롬이 갑자기 죽어도 카톡은 멀쩡하게 계속 돌아갑니다. 코스에서 배운 내용 중 이것을 가능하게 하는 것은 무엇인가요?",
"option1": "OS가 크롬에게만 CPU 시간을 몰아서 배분해 두었기 때문",
"option2": "카톡은 RAM이 아니라 디스크의 페이지 파일에서 직접 실행되기 때문",
"option3": "두 앱이 항상 서로 다른 CPU 코어에서만 실행되도록 정해져 있기 때문",
"option4": "OS가 프로세스마다 독립된 가상 주소 공간을 주어 서로의 메모리를 침범하지 못하게 격리하기 때문",
"answerIndex": 3,
"explanation": "섹션 5(가상 메모리)에서 OS는 각 프로세스에게 자기만의 가상 주소 공간을 주므로 한 앱이 다른 앱의 메모리를 읽거나 망가뜨릴 수 없다고 했습니다. 이 '격리' 덕분에 크롬이 죽어도 카톡은 멀쩡해요."
},
{
"courseSlug": "os",
"question": "한 수습 개발자가 '귀찮아서' 몇 달째 OS 업데이트를 미루고 있습니다. 코스의 비유에 따르면 이 PC는 어떤 집과 같은 상태인가요?",
"option1": "오래된 가전을 바꾸지 않아 전기 효율이 떨어진 집",
"option2": "창문 청소를 미뤄서 바깥 전망이 흐려진 집",
"option3": "도어락 비밀번호가 인터넷에 공개됐는데도 바꾸지 않은 집",
"option4": "우편함이 가득 차서 새로운 소식을 받지 못하는 집",
"answerIndex": 2,
"explanation": "섹션 6에서 업데이트의 절반 이상은 보안 패치이고, 취약점은 발견되는 순간 전 세계에 공개되므로 패치 안 한 컴퓨터는 '도어락 비밀번호가 인터넷에 올라왔는데 안 바꾼 집'과 같다고 비유했습니다."
},
{
"courseSlug": "peripherals",
"question": "노트북 스펙표의 램 항목에 '온보드'라고 적혀 있을 때, 이것이 뜻하는 것은?",
"option1": "램이 별도 슬롯에 꽂혀 있어 언제든 뺐다 꽂을 수 있다",
"option2": "램이 최신 규격이라 같은 용량이라도 속도가 더 빠르다",
"option3": "램 칩이 메인보드에 납땜되어 있어 나중에 용량을 늘릴 수 없다",
"option4": "램의 일부를 SSD처럼 저장 공간으로 나눠 쓸 수 있다",
"answerIndex": 2,
"explanation": "코스 2번 섹션(스펙표 읽기)에서 온보드 램은 메인보드에 납땜된 것이라 증설이 불가능하고, '산 날의 용량이 평생 용량'이 된다고 설명합니다. 그래서 처음부터 여유 있는 용량을 골라야 합니다."
},
{
"courseSlug": "peripherals",
"question": "코스가 USB의 대혼란을 정리하며 딱 하나만 기억하라고 강조한 핵심 원칙은?",
"option1": "USB-C 모양 케이블은 모두 USB4 속도를 낸다",
"option2": "커넥터 '모양'과 전송 '속도'는 완전히 별개의 개념이다",
"option3": "파란색 단자는 USB 2.0, 검은색 단자는 USB 3.x를 뜻한다",
"option4": "USB-A는 위아래 구분이 없어 어느 방향으로든 꽂힌다",
"answerIndex": 1,
"explanation": "6번 섹션(USB 규격 정리)의 핵심입니다. USB-C는 커넥터 모양 이름이고 USB 3.x·USB4는 속도 규격 이름이라, C 모양인데 속도는 2.0인 저가 케이블도 있습니다."
},
{
"courseSlug": "peripherals",
"question": "코스가 제시한 '개발용 모니터' 스펙의 우선순위로 옳은 것은?",
"option1": "주사율 > 해상도 > 패널",
"option2": "패널 > 주사율 > 해상도",
"option3": "주사율 > 패널 > 해상도",
"option4": "해상도 > 패널(IPS) > 주사율",
"answerIndex": 3,
"explanation": "3번 섹션에서 개발용 우선순위는 해상도 > 패널(IPS) > 주사율로, 게임용과 정반대라고 설명합니다. 코드는 결국 글자라서 글자가 많이·또렷하게 보이는 게 최고이기 때문입니다."
},
{
"courseSlug": "peripherals",
"question": "Docker 컨테이너 여러 개와 무거운 IDE를 동시에 돌리는 개발자에게 코스가 추천하는 CPU 접미사와 그 이유는?",
"option1": "H — 고성능·고발열 타입이라 빌드와 Docker 작업이 빠르다",
"option2": "U — 저전력 타입이라 컨테이너를 오래 돌리기에 유리하다",
"option3": "U와 H는 성능 차이가 없고 배터리 용량만 다르다",
"option4": "접미사는 출시 연도를 뜻하므로 성능과는 관련이 없다",
"answerIndex": 0,
"explanation": "2번 섹션의 CPU 접미사 해독법에 따르면 H는 High performance(고성능·고발열)로 빌드·Docker가 빠르고, U는 저전력·저발열이라 가벼운 코딩엔 충분하지만 무거운 빌드는 느립니다."
},
{
"courseSlug": "peripherals",
"question": "수습 A가 아침에 출근해 도킹 스테이션에 C 케이블 한 가닥으로 노트북을 연결했다. 노트북 충전은 되는데 독에 꽂힌 외부 모니터 화면만 안 나온다. 코스 내용상 가장 먼저 의심해야 할 원인은?",
"option1": "독의 전원 공급 와트(W)가 노트북 충전기보다 낮다",
"option2": "충전 전용 C 케이블이라 영상 신호(DP Alt Mode)를 전달하지 못한다",
"option3": "모니터 패널이 IPS가 아니라 VA여서 독의 신호와 호환되지 않는다",
"option4": "모니터가 4K여서 배율(스케일링) 설정을 마치기 전에는 화면이 켜지지 않는다",
"answerIndex": 1,
"explanation": "6번 섹션의 실무 사례 그대로입니다. '독에 모니터를 꽂았는데 화면이 안 나와요'의 범인은 십중팔구 충전 전용 C 케이블 — 겉모습은 같아도 영상 신호(DP Alt Mode)를 못 나르는 케이블이 있으니, 살 때 Gen 숫자와 영상 출력 지원 문구를 읽어야 합니다."
},
{
"courseSlug": "portfolio",
"question": "이 코스에서 말하는 '좋은 포트폴리오'의 정의로 가장 알맞은 것은?",
"option1": "완성작을 최대한 많이 모아 보여주는 전시회",
"option2": "사용한 기술 스택을 빠짐없이 나열한 목록",
"option3": "내가 문제를 어떻게 푸는 사람인지 보여주는 과정의 이야기",
"option4": "수상 경력과 자격증을 한곳에 정리한 증명서 모음",
"answerIndex": 2,
"explanation": "코스는 포트폴리오를 완성작 전시회가 아니라 '문제 → 고민 → 해결 → 배움'의 과정을 담은 이야기책으로 정의한다. 기능 목록은 검색하면 나오지만 과정의 이야기는 나만 쓸 수 있기 때문이다."
},
{
"courseSlug": "portfolio",
"question": "STAR 틀에서 '가장 길게 써야 하고, 읽는 사람이 제일 궁금해하는' 칸은 무엇인가?",
"option1": "S(상황) — 어떤 프로젝트에서 무슨 역할이었는지",
"option2": "A(행동) — 내가 구체적으로 무엇을 했는지",
"option3": "T(과제) — 내가 맡은 문제와 목표가 무엇이었는지",
"option4": "R(결과) — 그래서 무엇이 달라졌는지",
"answerIndex": 1,
"explanation": "코스는 A(행동)가 STAR의 주인공이라고 강조한다. 다들 S와 R만 쓰고 A를 한 줄로 끝내지만, 읽는 사람이 궁금한 건 '너는 뭘 했는데?'라는 A 부분이다."
},
{
"courseSlug": "portfolio",
"question": "'수습 8주 = 재료 창고' 표에 따르면, 3~6주차에 생기는 티켓(실제 이슈 처리 기록)은 포트폴리오에서 어떤 쓰임이 있는가?",
"option1": "\"실무 문제를 이렇게 풀었다\"를 보여주는 사례",
"option2": "\"기초를 이렇게 다졌다\"를 보여주는 증거",
"option3": "대표작 후보 1순위가 되는 종합 산출물",
"option4": "'배움(R)' 칸을 채워 줄 회고의 원석",
"answerIndex": 0,
"explanation": "재료 창고 표에서 3~6주차 티켓은 '실무 문제를 이렇게 풀었다' 사례로 쓰인다. 기초 증거는 1~2주차 과제집, 대표작 후보 1순위는 7~8주차 종합 프로젝트, 배움의 원석은 매주 회고·멘토 피드백이다."
},
{
"courseSlug": "portfolio",
"question": "개발자 편에서 저장소를 공개하기 전에 '꼭' 확인하라고 강조한 것은 무엇인가?",
"option1": "커밋 메시지가 한 단어로 너무 짧지 않은지",
"option2": "README 맨 위에 스크린샷이나 데모 GIF가 있는지",
"option3": "잔디(커밋 그래프)가 끊기지 않고 매일 이어지는지",
"option4": "비밀번호·API 키·.env 파일이 커밋에 섞여 있지 않은지",
"answerIndex": 3,
"explanation": "코스는 한 번 커밋된 비밀은 삭제해도 이력에 남는다며, 공개 전 비밀번호·API 키·.env 파일 확인을 '올리기 전에 꼭!' 경고로 강조한다. 회사 코드는 공개 저장소에 올리지 않는 것도 원칙이다."
},
{
"courseSlug": "portfolio",
"question": "수습생 민지가 대표작 README에 넣을 스크린샷을 찍었는데, 화면에 테스트용 글 제목 \"ㅁㄴㅇㄹ\"과 북마크바·탭 20개가 그대로 보인다. 코스의 스크린샷 체크리스트에 따르면 민지는 어떻게 해야 하는가?",
"option1": "전체 화면 구도는 그대로 두고 해상도만 높여 다시 찍는다",
"option2": "스크린샷 아래에 긴 글 설명을 붙여 부족한 부분을 보완한다",
"option3": "그럴듯한 더미 데이터로 바꾸고 브라우저 잡동사니를 잘라낸 뒤 핵심 위주로 다시 캡처한다",
"option4": "정지 화면 대신 코드 편집기 전체를 캡처해서 올린다",
"answerIndex": 2,
"explanation": "체크리스트는 \"ㅁㄴㅇㄹ\" 같은 테스트 데이터 대신 그럴듯한 데이터를 넣고, 북마크바·탭 같은 브라우저 잡동사니를 잘라내며, 전체 화면 1장보다 자랑할 핵심을 크게 담으라고 안내한다. 스크린샷은 '작업물의 증명사진'이기 때문이다."
},
{
"courseSlug": "react-intro",
"question": "이 코스가 첫 섹션에서 소개하는 React의 핵심 아이디어를 한 줄로 나타낸 것은?",
"option1": "화면(UI) = f(이벤트)",
"option2": "상태 = f(화면)",
"option3": "화면(UI) = f(상태)",
"option4": "서버 = f(요청)",
"answerIndex": 2,
"explanation": "섹션 1의 핵심 문장은 '화면(UI) = f(상태)'입니다. 화면을 직접 조작하지 않고 상태가 이러면 화면은 이렇게 생겨야 한다고 선언하면, 상태가 바뀔 때 React가 바뀐 부분만 다시 그려 줍니다."
},
{
"courseSlug": "react-intro",
"question": "JSX에서 <h1>제목</h1><p>내용</p>처럼 형제 태그 두 개를 동시에 반환하려고 하면 에러가 난다. 코스에서 알려 주는 올바른 방법은?",
"option1": "각 태그를 따옴표로 감싸 문자열로 반환한다",
"option2": "<>...</> (Fragment)로 두 태그를 하나로 감싼다",
"option3": "return 문을 태그마다 한 번씩 두 번 쓴다",
"option4": "두 태그 사이에 쉼표를 넣어 나란히 반환한다",
"answerIndex": 1,
"explanation": "섹션 3의 JSX 필수 규칙 4번 — 형제 태그는 하나로 감싸야 하며, <>...</> (Fragment)로 포장하면 됩니다. 'Adjacent JSX elements must be wrapped...' 에러가 바로 이 규칙 위반의 신호입니다."
},
{
"courseSlug": "react-intro",
"question": "좋아요 버튼에서 setCount(count + 1) 대신 count = count + 1처럼 값을 직접 바꾸면 화면이 갱신되지 않는다. 코스가 설명하는 이유는?",
"option1": "count가 부모에게서 받은 읽기 전용 props이기 때문",
"option2": "state에는 문자열만 저장할 수 있고 숫자는 쓸 수 없기 때문",
"option3": "브라우저가 폼의 기본 동작으로 새로고침을 막고 있기 때문",
"option4": "setCount를 호출해야 React가 '다시 그리자'는 신호를 받기 때문",
"answerIndex": 3,
"explanation": "섹션 4에서 useState가 값을 바꾸는 함수를 따로 주는 이유는 딱 하나 — setCount를 불러야 React가 '상태가 바뀌었으니 화면을 다시 그리자'는 신호를 받기 때문입니다. 직접 바꾸면 React가 알아채지 못합니다."
},
{
"courseSlug": "react-intro",
"question": "코스가 '초보 함정 1위'로 꼽는 실수 — onClick={handleSubmit} 대신 onClick={handleSubmit()}처럼 괄호를 붙이면 어떤 일이 생기나?",
"option1": "렌더링되는 순간 함수가 즉시 실행돼 버린다",
"option2": "클릭할 때마다 함수가 두 번씩 실행된다",
"option3": "함수가 등록되지 않아 클릭해도 아무 일이 없다",
"option4": "이벤트가 부모 컴포넌트로 넘어가 버린다",
"answerIndex": 0,
"explanation": "섹션 5의 초보 함정 1위 — 괄호를 붙이면 '실행 결과'를 건네는 것이라 렌더링되는 순간 즉시 실행됩니다. 이벤트에는 괄호 없이 함수 그 자체를 건네야 '그때 실행해 줘'가 됩니다."
},
{
"courseSlug": "react-intro",
"question": "코스 목록을 .map()으로 그리면서 key={index}(자리 번호)를 썼더니, 항목 순서를 바꾸자 입력값이 엉뚱한 항목에 뒤섞였다. 코스의 '출석부' 비유에 따르면 올바른 해결책은?",
"option1": "key를 아예 빼서 React가 자동으로 항목을 구분하게 둔다",
"option2": ".map() 대신 반복문으로 목록을 하나씩 그린다",
"option3": "DB가 준 고유한 id를 key로 넣어 '학번'으로 부르게 한다",
"option4": "순서를 바꿀 때마다 목록 전체를 새로 만들어 갈아 끼운다",
"answerIndex": 2,
"explanation": "섹션 6의 비유 — key는 React의 출석부이며, 자리 번호(index)로 부르면 자리만 바뀌어도 헷갈립니다. 학번처럼 변하지 않는 고유 id를 key로 주면 순서가 바뀌어도 React가 각 항목을 정확히 알아봅니다."
},
{
"courseSlug": "server-anatomy",
"question": "이 코스에서 말하는 '서버'의 정체로 가장 알맞은 것은?",
"option1": "데이터를 표(테이블) 형태로 안전하게 보관하는 저장 전용 장치",
"option2": "특정 포트를 열고 요청을 기다렸다가 응답하는 프로그램",
"option3": "서버실에 설치된 고성능 전용 컴퓨터 기계 그 자체",
"option4": "다른 컴퓨터에 먼저 요청을 보내는 쪽을 부르는 역할 이름",
"answerIndex": 1,
"explanation": "섹션 1의 핵심 — 서버는 기계가 아니라 '역할'이고, 포트를 열고 하루 종일 요청을 기다리는 프로그램이 그 역할을 맡습니다. 먼저 요청을 보내는 쪽은 클라이언트예요."
},
{
"courseSlug": "server-anatomy",
"question": "우리 회사(AWESOMEDEV) 학습 플랫폼의 3계층에서 각 역할을 맡은 프로그램을 옳게 짝지은 것은?",
"option1": "웹서버=Spring Boot, WAS=Caddy, DB=PostgreSQL",
"option2": "웹서버=PostgreSQL, WAS=Spring Boot, DB=Caddy",
"option3": "웹서버=Caddy, WAS=Spring Boot, DB=PostgreSQL",
"option4": "웹서버=Caddy, WAS=PostgreSQL, DB=Spring Boot",
"answerIndex": 2,
"explanation": "섹션 2~3에서 본 우리 스택 — 손님을 맞는 웹서버는 Caddy(HTTPS·정적 파일), 요리(비즈니스 로직)를 하는 WAS는 Spring Boot, 재료(데이터) 창고인 DB는 PostgreSQL입니다."
},
{
"courseSlug": "server-anatomy",
"question": "로그인 후 화면에 보이는 \"○○님, 진도 40%\" 문구에 대한 설명으로 옳은 것은?",
"option1": "요청이 올 때마다 새로 만들어지는 동적 응답이라 Spring Boot와 DB가 처리한다",
"option2": "미리 만들어 둔 정적 파일이라 Caddy가 파일을 그대로 건네준다",
"option3": "누가 요청해도 내용이 같아서 자판기처럼 바로 꺼내 줄 수 있다",
"option4": "React 빌드 결과물에 포함되어 있어 서버 없이 브라우저가 만들어 낸다",
"answerIndex": 0,
"explanation": "섹션 4의 구분 — 누가·언제 요청하냐에 따라 내용이 달라지는 것은 동적 응답이고, 주방(WAS)과 창고(DB)를 다녀와야 하므로 Spring Boot + DB가 처리합니다."
},
{
"courseSlug": "server-anatomy",
"question": "우리 반 30명이 동시에 이 페이지를 열었을 때, 코스에서 설명한 서버의 처리 방식으로 옳은 것은?",
"option1": "1번 요청 처리가 끝날 때까지 나머지 29명의 접속은 모두 끊어 버린다",
"option2": "요청이 올 때마다 DB로 가는 통로를 매번 새로 뚫어 속도를 높인다",
"option3": "대기열이 가득 차더라도 에러 없이 요청을 무한정 받아 준다",
"option4": "스레드 풀에 대기시켜 둔 스레드를 요청마다 한 명씩 붙여 겹쳐서 처리한다",
"answerIndex": 3,
"explanation": "섹션 5 — Spring Boot는 요청 처리 직원(스레드)을 스레드 풀에 미리 대기시켜 두고 요청마다 한 명씩 붙입니다. DB 통로는 커넥션 풀로 미리 뚫어 돌려쓰고, 대기열마저 차면 에러가 나요."
},
{
"courseSlug": "server-anatomy",
"question": "학습 플랫폼 사용자가 수만 명으로 늘어 서버가 힘들어하고, '한 대가 멈추면 서비스 전체가 멈추는' 위험까지 없애고 싶다. 코스 내용에 따른 알맞은 처방은?",
"option1": "EC2 인스턴스 타입을 더 좋은 것으로 바꾸는 스케일 업을 한다",
"option2": "앞에 로드 밸런서를 세우고 바쁜 WAS만 여러 대로 늘리는 스케일 아웃을 한다",
"option3": "WAS가 데이터를 메모리에 직접 보관하게 해서 DB까지 가는 왕복을 없앤다",
"option4": "정적 파일 서빙을 중단해서 웹서버(Caddy)의 부담부터 줄인다",
"answerIndex": 1,
"explanation": "섹션 6 — 스케일 업은 아무리 좋아도 '한 대'의 한계와 한 대가 죽으면 전부 멈추는 위험이 그대로입니다. 3계층으로 역할을 나눠 둔 덕분에 로드 밸런서를 세우고 바쁜 WAS만 부분 확장하는 스케일 아웃이 가능해요."
},
{
"courseSlug": "spring-intro",
"question": "스프링의 '의존성 주입(DI)'을 이 코스의 식당 주방 비유로 가장 잘 설명한 것은?",
"option1": "요리사가 요리할 때마다 직접 마트에 가서 재료를 사 오고 도구까지 스스로 준비하는 것",
"option2": "손님이 주방에 직접 들어가서 원하는 요리를 자기 손으로 만들어 먹는 것",
"option3": "요리사가 \"재료 주세요\"라고 선언만 하면 주방(컨테이너)이 필요한 재료를 알아서 가져다주는 것",
"option4": "주방장이 모든 요리를 혼자 도맡아 하고 나머지 요리사들은 주문만 받게 하는 것",
"answerIndex": 2,
"explanation": "섹션 1의 핵심 비유입니다. 스프링은 앱이 켜질 때 필요한 객체들을 미리 만들어 컨테이너(주방 창고)에 보관해 두고, \"이거 필요해요\"라고 선언한 곳에 알아서 넣어 줍니다 — 이것이 의존성 주입(DI)입니다."
},
{
"courseSlug": "spring-intro",
"question": "코스의 '어노테이션 5총사' 설명에서, 주방에서 실제 요리(비즈니스 로직)를 하는 요리사 역할을 맡는 어노테이션은 무엇인가?",
"option1": "@RestController — 요청을 받는 카운터 직원",
"option2": "@Service — 주방에서 실제 요리를 하는 요리사",
"option3": "@Repository — 창고(DB)에서 재료를 꺼내오는 담당",
"option4": "@Configuration — 주방 설비를 설치하고 빈을 등록하는 담당",
"answerIndex": 1,
"explanation": "섹션 2에서 @Service는 \"주방에서 실제 요리(비즈니스 로직)를 하는 요리사\"로 설명됩니다. @RestController는 주문을 받는 카운터, @Repository는 창고(DB) 담당이에요."
},
{
"courseSlug": "spring-intro",
"question": "코스에서 Controller에 비즈니스 로직을 쓰지 말라고 하는 이유로 든 것은 무엇인가?",
"option1": "각 층이 자기 일만 한다는 원칙이 깨져서, 나중에 규칙을 바꾸려 할 때 어디를 고쳐야 할지 찾기 어려워지기 때문",
"option2": "비즈니스 로직이 들어가는 순간 서버가 켜지지 않고 시작하자마자 에러가 나기 때문",
"option3": "스프링이 그 클래스를 더 이상 빈(Bean)으로 등록해 주지 않게 되기 때문",
"option4": "Controller에서는 Service를 생성자 주입으로 받을 수 없게 되기 때문",
"answerIndex": 0,
"explanation": "섹션 3의 핵심입니다. 코스는 \"당장은 돌아가지만\" 검증·로그 같은 주방의 일이 카운터에 쌓이고, 나중에 \"로그인 규칙만 바꾸고 싶은데\" 할 때 어디를 고쳐야 할지 아무도 모르게 된다고 설명합니다."
},
{
"courseSlug": "spring-intro",
"question": "application.yml에서 ${DB_URL:jdbc:postgresql://localhost:5432/mirim} 같은 ${환경변수:기본값} 문법이 뜻하는 것은?",
"option1": "기본값을 먼저 사용하고, 기본값이 비어 있을 때만 환경변수를 읽는다",
"option2": "환경변수의 값과 기본값을 이어 붙여서 하나의 최종 값으로 만든다",
"option3": "환경변수는 참고용일 뿐이고 실제로는 항상 기본값만 사용된다",
"option4": "환경변수가 있으면 그 값을 쓰고, 없으면 콜론 뒤의 기본값을 쓴다",
"answerIndex": 3,
"explanation": "섹션 4의 핵심 문법입니다. 환경변수가 있으면 그걸 쓰고 없으면 기본값을 쓰기 때문에, 같은 코드가 내 PC에서는 로컬 PostgreSQL로, 운영 서울 EC2에서는 환경변수로 덮어쓴 진짜 DB로 돌아갑니다."
},
{
"courseSlug": "spring-intro",
"question": "수습 개발자가 이메일과 역할(role)이 모두 일치하는 사용자를 찾으려고 JPA 메서드 findByEmailAndRole(String email, String role)을 만들었다. 코스에서 배운 이름 규칙대로라면 스프링이 대신 써 주는 SQL은?",
"option1": "SELECT * FROM users WHERE email = ? OR role = ?",
"option2": "SELECT * FROM users WHERE email = ? AND role = ?",
"option3": "SELECT * FROM users WHERE email = ? ORDER BY role DESC",
"option4": "SELECT COUNT(*) > 0 FROM users WHERE email = ? AND role = ?",
"answerIndex": 1,
"explanation": "섹션 5의 규칙 응용입니다. findBy 뒤의 필드명은 WHERE 조건이 되고, And는 두 조건을 함께 거는 접속사예요. COUNT(*) > 0 형태는 existsBy로 시작할 때 만들어지는 SQL입니다."
},
{
"courseSlug": "sql-intermediate",
"question": "GROUP BY로 행을 묶은 뒤, 제출 수가 20건 넘는 '팀(그룹)'만 남기고 싶다. 어떤 키워드 뒤에 COUNT(*) > 20 조건을 써야 할까?",
"option1": "WHERE — 행을 하나씩 검사하는 입장 검사이므로",
"option2": "ORDER BY — 조건에 맞는 팀을 앞으로 정렬하므로",
"option3": "HAVING — 팀이 다 만들어진 뒤 팀 단위로 거르므로",
"option4": "GROUP BY — 묶는 기준에 조건을 함께 적으므로",
"answerIndex": 2,
"explanation": "WHERE는 묶기 전 행 하나하나를 거르는 '입장 검사'라서 그 시점엔 셀 팀이 없고, 묶은 뒤 팀 단위로 거르는 문은 HAVING이다. 코스 2섹션(HAVING)의 실행 순서 WHERE → GROUP BY → HAVING → ORDER BY 개념이다."
},
{
"courseSlug": "sql-intermediate",
"question": "submission 테이블에서 아직 채점되지 않은(score가 NULL인) 제출을 조회하려면 어떤 조건을 써야 할까?",
"option1": "WHERE score = NULL — 등호로 NULL과 직접 비교한다",
"option2": "WHERE score IS NULL — IS로 NULL 여부를 검사한다",
"option3": "WHERE score = 0 — NULL은 0점과 같은 값이므로",
"option4": "WHERE COALESCE(score) — NULL을 자동으로 찾아준다",
"answerIndex": 1,
"explanation": "NULL은 '모름'이라서 = 로 비교하면 결과도 NULL이 되어 항상 0건이 나오고, NULL 여부는 IS NULL로 검사해야 한다. 코스 4섹션(NULL의 함정)의 함정 ①에 해당한다."
},
{
"courseSlug": "sql-intermediate",
"question": "제출이 5건 있고 score가 (90, 80, NULL, 70, NULL)일 때, AVG(score)의 결과는?",
"option1": "80 — NULL 두 건은 건너뛰고 240을 3으로 나눈다",
"option2": "48 — NULL을 0으로 쳐서 240을 5로 나눈다",
"option3": "NULL — NULL이 하나라도 끼면 집계 전체가 NULL이 된다",
"option4": "60 — NULL을 최솟값으로 바꾼 뒤 평균을 낸다",
"answerIndex": 0,
"explanation": "집계 함수는 NULL을 조용히 건너뛰므로 AVG는 채점된 3건만으로 240÷3=80을 계산한다. 코스 4섹션의 함정 ② — 미채점을 0점으로 칠지 말지는 DB가 아니라 내가 정해야 한다는 내용이다."
},
{
"courseSlug": "sql-intermediate",
"question": "\"검색이 빨라진다니 모든 컬럼에 인덱스를 걸자\"는 생각이 코스에서 '안 됩니다'라고 한 이유는?",
"option1": "인덱스는 테이블당 한 개만 만들 수 있기 때문에",
"option2": "인덱스를 걸면 SELECT 결과의 정렬 순서가 바뀌기 때문에",
"option3": "인덱스가 많으면 EXPLAIN이 실행 계획을 못 세우기 때문에",
"option4": "INSERT/UPDATE 때마다 인덱스도 고쳐야 해서 쓰기가 느려지기 때문에",
"answerIndex": 3,
"explanation": "인덱스는 디스크를 차지하고, 데이터를 넣거나 고칠 때마다 유지 비용이 들어 쓰기가 느려지는 읽기-쓰기 거래(trade-off)다. 그래서 코스 5섹션은 'WHERE나 JOIN에 자주 등장하는 컬럼에만' 거는 것을 원칙으로 든다."
},
{
"courseSlug": "sql-intermediate",
"question": "수십만 행의 submission 테이블에서 WHERE student_id = 7 조회가 느리다는 말을 듣고 EXPLAIN을 붙였더니 'Seq Scan on submission'이 나왔다. 코스가 알려준 다음 행동은?",
"option1": "WHERE를 HAVING으로 바꿔 팀 단위로 거르게 한다",
"option2": "student_id 컬럼에 CREATE INDEX를 걸까 검토한다",
"option3": "쿼리를 트랜잭션(BEGIN~COMMIT)으로 감싸 다시 실행한다",
"option4": "COALESCE로 student_id의 NULL을 0으로 바꿔 준다",
"answerIndex": 1,
"explanation": "데이터가 많은데 Seq Scan이면 책을 한 장씩 넘기는 중이라는 점검 신호이므로, 자주 검색하는 컬럼에 인덱스를 걸지 고민하는 것이 다음 단계다. 코스 6섹션의 'EXPLAIN 붙이기 → Seq Scan 찾기 → 인덱스 고민' 3단 콤보다."
},
{
"courseSlug": "sql",
"question": "이 코스에서는 데이터베이스를 엑셀에 비유합니다. 엑셀의 '시트 한 장'에 해당하는 것은 무엇인가요?",
"option1": "행(row) — 데이터 한 건",
"option2": "테이블(table)",
"option3": "열(column) — 속성 하나",
"option4": "데이터베이스(DB) 전체",
"answerIndex": 1,
"explanation": "섹션 1의 비유에서 엑셀 파일 하나가 데이터베이스, 시트 한 장이 테이블, 행이 데이터 한 건, 열이 속성입니다. 우리 플랫폼 DB에는 users 등 테이블(시트) 5개가 들어 있어요."
},
{
"courseSlug": "sql",
"question": "WHERE kind = 'MAIN'처럼 SQL에서 문자열 값을 조건에 쓸 때 올바른 표기 방법은 무엇인가요?",
"option1": "큰따옴표(\"MAIN\")로 감싼다",
"option2": "따옴표 없이 MAIN이라고 그대로 쓴다",
"option3": "작은따옴표('MAIN')로 감싼다",
"option4": "괄호((MAIN))로 감싼다",
"answerIndex": 2,
"explanation": "섹션 3의 '따옴표 주의'에서 배운 내용으로, 문자열은 작은따옴표로 감싸고 큰따옴표는 열·테이블 이름용이라 뜻이 달라집니다. 숫자는 week = 1처럼 따옴표 없이 씁니다."
},
{
"courseSlug": "sql",
"question": "submission 테이블에서 '최근 제출 5건'을 보려고 합니다. SELECT 문 뒤에 이어 붙일 내용으로 옳은 것은 무엇인가요?",
"option1": "ORDER BY submitted_at DESC LIMIT 5",
"option2": "ORDER BY submitted_at ASC LIMIT 5",
"option3": "LIMIT 5 ORDER BY submitted_at DESC",
"option4": "WHERE submitted_at DESC LIMIT 5",
"answerIndex": 0,
"explanation": "섹션 4에서 DESC가 내림차순(최신순), LIMIT이 위에서 N개 자르기이며, 조합 순서는 FROM → WHERE → ORDER BY → LIMIT입니다. 관리자 화면의 '최근 제출물' 목록이 바로 이 쿼리예요."
},
{
"courseSlug": "sql",
"question": "submission 테이블의 user_id처럼, 다른 테이블의 행을 번호표(id)로 가리키는 열을 부르는 이름은 무엇인가요?",
"option1": "기본키(primary key)",
"option2": "별명(alias)",
"option3": "와일드카드(wildcard)",
"option4": "외래키(foreign key)",
"answerIndex": 3,
"explanation": "섹션 6에서 이름은 users에 한 번만 두고 다른 테이블은 번호표(id)로 가리키게 하는데, 이 번호표 열을 '다른(외) 테이블의 열쇠(키)'라는 뜻의 외래키라고 부릅니다. JOIN은 이 번호표를 실제 이름으로 바꿔 보는 일이에요."
},
{
"courseSlug": "sql",
"question": "수습생 A가 로컬 DB에서 BEGIN;을 실행한 뒤 UPDATE submission SET status = 'DONE';을 쳤는데, WHERE를 빼먹어 모든 행이 DONE으로 바뀐 걸 발견했습니다. 아직 확정 전이라면 원래대로 되돌리는 명령은 무엇인가요?",
"option1": "COMMIT; — 지금까지의 변경을 저장한다",
"option2": "DELETE FROM submission; — 잘못 바뀐 행을 지운다",
"option3": "ROLLBACK; — BEGIN 이후의 변경을 전부 되돌린다",
"option4": "SELECT status FROM submission; — 상태를 다시 조회한다",
"answerIndex": 2,
"explanation": "섹션 5의 트랜잭션은 '게임 보스전 앞 세이브 포인트' 비유 그대로, BEGIN 이후의 변경은 가안 상태라 ROLLBACK 한 방에 전부 원상복구됩니다. 반대로 확정하고 싶을 때만 COMMIT을 씁니다."
},
{
"courseSlug": "tcp-udp",
"question": "TCP 3-way 핸드셰이크에서 세 마디가 오가는 올바른 순서는 무엇인가요?",
"option1": "ACK → SYN → SYN+ACK",
"option2": "SYN → ACK → SYN+ACK",
"option3": "SYN → SYN+ACK → ACK",
"option4": "SYN+ACK → SYN → ACK",
"answerIndex": 2,
"explanation": "섹션 2에서 배운 대로, 내 PC가 SYN으로 대화를 청하고 서버가 SYN+ACK으로 맞잡은 뒤 내 PC가 ACK으로 악수를 완성해야 연결이 수립됩니다."
},
{
"courseSlug": "tcp-udp",
"question": "코스에서 설명한 'UDP가 빠른 진짜 이유'로 가장 알맞은 것은 무엇인가요?",
"option1": "연결 맺기·확인 답장·재전송 같은 일을 생략하기 때문에",
"option2": "패킷을 TCP보다 훨씬 큰 크기로 쪼개서 보내기 때문에",
"option3": "전용 회선을 미리 예약해서 다른 데이터가 못 끼어들기 때문에",
"option4": "받는 쪽이 영수증(ACK)을 더 빠른 주기로 보내 주기 때문에",
"answerIndex": 0,
"explanation": "섹션 4의 핵심은 UDP의 속도가 '안 하는 일이 많아서' 나온다는 것입니다. 악수(3-way)도, ACK 확인도, 재전송도 하지 않는 대신 신뢰성을 포기한 대가로 속도를 얻습니다."
},
{
"courseSlug": "tcp-udp",
"question": "TCP로 상자 #1~#5를 보내다가 #3이 길에서 실종됐습니다. 이때 벌어지는 일로 옳은 것은 무엇인가요?",
"option1": "받는 쪽이 #3 자리를 비워 둔 채 데이터를 미완성으로 조립한다",
"option2": "보내는 쪽이 #1부터 #5까지 전부 처음부터 다시 보낸다",
"option3": "받는 쪽이 연결을 끊고 3-way 핸드셰이크부터 다시 시작한다",
"option4": "받는 쪽이 ACK로 알려 주면 보내는 쪽이 #3만 골라 재전송한다",
"answerIndex": 3,
"explanation": "섹션 3의 재전송·순서 보장 개념입니다. 받는 쪽이 '몇 번까지 잘 받았는지' 영수증(ACK)으로 알려 주므로, 실종된 #3만 다시 보내고 늦게 온 #3을 제자리에 끼워 넣어 원본과 100% 동일하게 복원합니다."
},
{
"courseSlug": "tcp-udp",
"question": "netstat 실습에서 원격 주소가 ':443'이고 상태가 ESTABLISHED인 줄이 뜻하는 것은 무엇인가요?",
"option1": "내 PC가 SSH로 EC2 서버에 원격 접속해 있다는 뜻",
"option2": "상대 서버의 HTTPS 방과 3-way 악수가 끝나 연결이 살아 있다는 뜻",
"option3": "UDP 방송 수신이 진행 중이라 상태가 표시되고 있다는 뜻",
"option4": "PostgreSQL 데이터베이스와 질의를 주고받는 중이라는 뜻",
"answerIndex": 1,
"explanation": "섹션 5~6에서 443번은 HTTPS의 방 번호이고, ESTABLISHED는 3-way 악수가 성공적으로 끝나 연결이 살아 있다는 표시라고 배웠습니다. 참고로 UDP는 연결 개념이 없어 이 명단에 상태가 뜨지 않습니다."
},
{
"courseSlug": "tcp-udp",
"question": "온라인 게임을 만들고 있습니다. 캐릭터의 실시간 위치는 UDP로 보내는데, '아이템 구매' 버튼까지 UDP로 보내자는 의견이 나왔다면 어떻게 판단해야 할까요?",
"option1": "게임 데이터끼리는 같은 프로토콜을 써야 하므로 전부 UDP로 통일한다",
"option2": "구매가 위치 정보보다 자주 발생하지 않으므로 UDP로 보내도 무방하다",
"option3": "결제는 유실되면 안 되는 데이터이므로 느려도 TCP로 보내야 한다",
"option4": "UDP로 보내되 헤더를 20바이트로 늘리면 유실을 막을 수 있다",
"answerIndex": 2,
"explanation": "섹션 7 토론(Q1)의 핵심 기준인 '이 데이터는 유실돼도 되는가?'를 적용한 문제입니다. 위치는 최신 정보가 곧 다시 오니 유실을 감수해도 되지만, 결제는 한 건이라도 유실되면 안 되므로 TCP를 써야 합니다."
},
{
"courseSlug": "testing",
"question": "단위 테스트의 3막 구조 given-when-then에서 'when' 단계가 하는 일은 무엇인가?",
"option1": "테스트에 필요한 객체와 데이터를 만들어 무대를 준비한다",
"option2": "assertThat으로 실제값과 기대값이 같은지 검증한다",
"option3": "검사하려는 동작을 딱 하나만 실행한다",
"option4": "테스트가 끝난 뒤 사용한 데이터를 깨끗하게 정리한다",
"answerIndex": 2,
"explanation": "코스의 연극 비유에서 when은 '사건 발생', 즉 주인공의 행동으로 테스트하려는 딱 그 동작 하나만 호출하는 단계다. 두세 가지를 한꺼번에 하면 실패했을 때 범인을 못 찾는다고 설명한다."
},
{
"courseSlug": "testing",
"question": "이 코스가 테스트 코드를 '미래의 나를 지키는 보험'에 비유한 핵심 이유는?",
"option1": "한 번 작성해 두면 수정 없이 영원히 코드를 지켜 주기 때문에",
"option2": "사고가 나기 전에 미리 들어 두고, 나중에 코드가 부서지면 빨간불로 즉시 알려 주기 때문에",
"option3": "테스트가 있으면 버그가 아예 발생하지 않도록 원천 차단해 주기 때문에",
"option4": "배포 전에 사용자가 대신 기능을 눌러 보고 검사해 주기 때문에",
"answerIndex": 1,
"explanation": "섹션 1에서 보험은 사고가 나기 전에 드는 것이고, 3개월 뒤의 내가 코드를 부수면 테스트가 빨간불로 즉시 알려 준다고 설명한다. 보험료(작성 시간)는 조금 내고 보험금(밤샘 디버깅 면제)은 크게 돌려받는다는 비유다."
},
{
"courseSlug": "testing",
"question": "코스가 입문 단계에서 꼭 챙기라고 특별히 강조한 좋은 단위 테스트의 두 가지 조건은?",
"option1": "반복 가능할 것, 자가 검증이 될 것",
"option2": "코드가 짧을 것, 메서드 이름을 한글로 쓸 것",
"option3": "커버리지가 높을 것, 실제 DB로 검증할 것",
"option4": "빠를 것, 테스트끼리 서로 독립적일 것",
"answerIndex": 3,
"explanation": "섹션 5에서 특히 강조한 두 조건은 빠르다(Fast)와 독립적이다(Independent)이다. 빨라야 고칠 때마다 돌리는 습관이 생기고, 독립적이어야 순서나 공유 데이터 때문에 터지는 '도미노 테스트'가 되지 않는다. 반복 가능·자가 검증은 '그 외' 조건으로만 언급된다."
},
{
"courseSlug": "testing",
"question": "ProgressServiceTest의 '이미 완료한 강의를 다시 완료해도 진도율은 그대로다' 테스트에 대한 설명으로 옳은 것은?",
"option1": "완료 버튼 연타로 진도율이 두 배로 오르던 실제 버그의 재발을 막으려고 남긴 테스트다",
"option2": "DB와 서버를 실제로 띄워 진도율 API를 호출해 보는 통합 테스트다",
"option3": "강의를 전부 완료했을 때 정확히 100%가 나오는지 확인하는 테스트다",
"option4": "같은 강의를 두 번 완료하면 진도율이 20%가 되는 것이 정상임을 증명하는 테스트다",
"answerIndex": 0,
"explanation": "섹션 4의 해부 ④에서 이 테스트는 실화 기반으로, 완료 버튼을 연타하면 진도율이 2배로 오르던 버그를 고친 뒤 재발하지 말라고 못 박아 둔 것이라고 설명한다. 테스트는 '버그의 묘비명이자 부활 방지 부적'이라는 표현이 나온다."
},
{
"courseSlug": "testing",
"question": "출석률(0~100%)을 계산하는 함수를 새로 만들었고 테스트 케이스를 3개만 고를 수 있다. 코스에서 배운 경계값 요령에 가장 충실한 선택은?",
"option1": "37%, 52%, 68%처럼 서로 다른 중간값 3개를 골라 검사한다",
"option2": "매번 무작위로 값 3개를 새로 뽑아 다양하게 검사한다",
"option3": "출석 0번(0%), 딱 1번 출석, 전부 출석(100%)의 가장자리 값을 검사한다",
"option4": "가장 자주 나올 평균적인 값 하나를 골라 3번 반복해 검사한다",
"answerIndex": 2,
"explanation": "섹션 6에서 버그는 평범한 가운데 값이 아니라 범위가 시작되고 끝나는 가장자리에서 태어난다고 했다. 실전 요령으로 '텅 빈 경우 / 딱 1개인 경우 / 꽉 찬(최대) 경우' 세 칸을 먼저 챙기라고 안내한다."
},
{
"courseSlug": "tool-capture",
"question": "Win+Shift+S로 화면을 캡처하면 결과물은 기본적으로 어디로 가나요?",
"option1": "내 PC의 '사진' 폴더에 파일로 자동 저장된다",
"option2": "클립보드에 복사되어 Ctrl+V로 바로 붙여넣을 수 있다",
"option3": "그림판이 자동으로 열리면서 이미지가 삽입된다",
"option4": "Gitea 과제 저장소에 자동으로 업로드된다",
"answerIndex": 1,
"explanation": "Win+Shift+S 캡처는 파일로 자동 저장되지 않고 클립보드로 복사됩니다. 그래서 '찍기 → Ctrl+V로 붙이기'까지 3초면 끝난다는 게 섹션 2의 핵심입니다."
},
{
"courseSlug": "tool-capture",
"question": "화면보다 세로로 긴 웹 페이지 전체를 PNG 한 장으로 캡처하려면 코스에서 알려준 방법은 무엇인가요?",
"option1": "PrtScn을 스크롤하면서 여러 번 눌러 이어 붙인다",
"option2": "Win+Shift+S의 '전체' 모드로 모니터를 통째로 찍는다",
"option3": "F12 → Ctrl+Shift+P → 'screenshot' 입력 후 'Capture full size screenshot'을 선택한다",
"option4": "Win+G 게임 바로 페이지를 스크롤하며 녹화한다",
"answerIndex": 2,
"explanation": "섹션 3의 치트시트대로 브라우저 개발자 도구(F12)의 명령 팔레트에서 'Capture full size screenshot'을 실행하면 페이지 전체가 한 장으로 저장됩니다. 화면에 보이는 부분만 찍는 다른 방법과 달리 긴 페이지를 통째로 담을 수 있어요."
},
{
"courseSlug": "tool-capture",
"question": "3~10초짜리 짧은 버그 재현을 공유할 때 코스가 MP4 대신 GIF를 추천하는 이유는 무엇인가요?",
"option1": "GIF가 MP4보다 화질이 항상 더 좋기 때문",
"option2": "GIF에는 소리를 함께 담을 수 있기 때문",
"option3": "GIF는 프레임 수 제한이 없어 긴 영상에 유리하기 때문",
"option4": "채팅이나 Gitea 이슈에서 클릭 없이 자동 재생되기 때문",
"answerIndex": 3,
"explanation": "섹션 4에서 개발자들이 GIF를 좋아하는 이유는 받는 사람이 플레이어를 열 필요 없이 스크롤하다가 바로 볼 수 있다는 점이라고 설명합니다. 소리가 필요하거나 30초를 넘는 재현은 MP4를 쓰는 게 코스의 기준입니다."
},
{
"courseSlug": "tool-capture",
"question": "캡처에 찍힌 API 토큰이나 비밀번호를 가릴 때 코스가 권장하는 방법은 무엇인가요?",
"option1": "그림판에서 완전 불투명한 단색 박스로 덮는다",
"option2": "모자이크 처리를 해서 알아볼 수 없게 만든다",
"option3": "흐림(블러) 효과를 진하게 여러 번 겹쳐 적용한다",
"option4": "이미지를 JPG로 저장해 글자가 뭉개지게 한다",
"answerIndex": 0,
"explanation": "섹션 6에서 모자이크나 블러는 도구로 복원된 사례가 있으므로, 완전 불투명한 단색 박스로 확실히 덮으라고 강조합니다. 가장 안전한 방법은 애초에 민감한 창을 닫고 다시 찍는 것이라고도 덧붙입니다."
},
{
"courseSlug": "tool-capture",
"question": "수습생 A가 마우스를 올려야만 보이는 드롭다운 메뉴를 캡처하려고 Win+Shift+S를 눌렀더니 메뉴가 닫혀 버렸습니다. 코스의 치트시트가 알려주는 해결법은 무엇인가요?",
"option1": "Win+Shift+S의 '창' 모드로 바꿔서 다시 시도한다",
"option2": "F12 개발자 도구에서 전체 페이지 스크린샷을 내려받는다",
"option3": "PrtScn으로 화면 전체를 찍은 뒤 필요한 부분만 나중에 잘라낸다",
"option4": "Win+G 게임 바로 화면을 녹화한 뒤 정지 화면을 캡처한다",
"answerIndex": 2,
"explanation": "섹션 3의 치트시트에 따르면 Win+Shift+S는 누르는 순간 열려 있던 메뉴가 닫히므로, 메뉴가 열린 상태에서 PrtScn으로 전체 화면을 클립보드에 담고 나중에 잘라내는 것이 요령입니다."
},
{
"courseSlug": "tool-dbeaver",
"question": "코스에서 설명하는 DBeaver의 정체로 가장 알맞은 것은?",
"option1": "PostgreSQL을 대체하는 새로운 종류의 데이터베이스",
"option2": "DB에 접속해 화면으로 보여 주는 GUI 클라이언트",
"option3": "Docker 컨테이너를 관리하는 서버 모니터링 도구",
"option4": "SQL 없이 데이터를 저장하는 스프레드시트 프로그램",
"answerIndex": 1,
"explanation": "코스 1섹션에서 DBeaver는 DB 그 자체가 아니라, 컨테이너 안에서 돌고 있는 PostgreSQL에 접속해 보여 주기만 하는 GUI 클라이언트(창문)라고 설명합니다."
},
{
"courseSlug": "tool-dbeaver",
"question": "우리 로컬 개발 DB에 연결할 때 입력하는 접속 정보로 옳은 것은?",
"option1": "Host: localhost, Port: 5432, Database: mirim, Username: mirim",
"option2": "Host: mirim-postgres, Port: 8080, Database: public, Username: admin",
"option3": "Host: 127.0.0.1, Port: 3306, Database: mirim, Username: postgres",
"option4": "Host: localhost, Port: 5432, Database: public, Username: mirim123",
"answerIndex": 0,
"explanation": "3섹션의 접속 정보에 따르면 내 PC에서 도는 DB이므로 Host는 localhost, Port는 PostgreSQL 기본값 5432, Database와 Username은 둘 다 mirim입니다."
},
{
"courseSlug": "tool-dbeaver",
"question": "SQL 편집기에서 커서가 있는 문장 하나만 실행하는 단축키는?",
"option1": "Alt+X",
"option2": "Ctrl+]",
"option3": "Ctrl+Enter",
"option4": "Win+Shift+S",
"answerIndex": 2,
"explanation": "6섹션의 단축키 정리에서 커서가 있는 문장 하나 실행은 Ctrl+Enter, 편집기 전체 실행은 Alt+X입니다. Ctrl+]는 SQL 편집기를 여는 단축키예요."
},
{
"courseSlug": "tool-dbeaver",
"question": "Data 탭에서 셀을 더블클릭해 값을 고쳤을 때, 그 변경이 진짜 DB에 반영되는 시점은?",
"option1": "셀에서 엔터를 누르는 순간 바로 반영된다",
"option2": "테이블 탭을 닫으면 자동으로 반영된다",
"option3": "DBeaver를 재시작해야 반영된다",
"option4": "아래쪽 Save(저장) 버튼을 눌러야 반영된다",
"answerIndex": 3,
"explanation": "5섹션에 따르면 셀 더블클릭으로 값을 수정해도 엔터만으로는 저장되지 않고, 아래쪽 Save(저장)를 눌러야 그때서야 진짜 DB에 반영됩니다."
},
{
"courseSlug": "tool-dbeaver",
"question": "수습 개발자 지연이가 운영 서버(EC2) 데이터를 확인할 일이 생겨, 자기 노트북 DBeaver에 운영 DB 접속 정보를 넣으려 한다. 코스의 철칙에 따르면 올바른 행동은?",
"option1": "조회(SELECT)만 하고 수정하지 않는다는 조건으로 연결한다",
"option2": "연결하지 말고 먼저 멘토에게 이야기해서 방법을 상의한다",
"option3": "Test Connection까지만 눌러 보고 Finish는 누르지 않는다",
"option4": "확인이 끝난 뒤 저장된 연결을 바로 삭제하는 조건으로 연결한다",
"answerIndex": 1,
"explanation": "7섹션의 철칙은 개인 PC의 DBeaver로는 로컬 개발 DB에만 연결하고 운영 DB 접속 정보는 넣지 않는 것입니다. 실수 한 줄로 실제 사용자 사고가 나고 접속 정보가 유출 통로가 될 수 있어, 필요하면 반드시 멘토에게 먼저 이야기해야 합니다."
},
{
"courseSlug": "tool-devtools",
"question": "화면에서 지금 보고 있는 특정 버튼의 코드가 궁금할 때, 그 요소로 바로 이동하는 가장 빠른 방법은 무엇인가요?",
"option1": "F12를 눌러 Elements 탭에서 트리를 하나씩 펼쳐 찾는다",
"option2": "Ctrl + Shift + M을 눌러 기기 프리셋을 고른다",
"option3": "그 요소를 우클릭한 뒤 \"검사\"를 클릭한다",
"option4": "Console 탭에 document.title을 입력한다",
"answerIndex": 2,
"explanation": "코스의 '여는 법 3가지' 중 우클릭 → \"검사\"는 클릭한 그 요소로 바로 점프하는 지름길로 소개됩니다. F12는 도구를 열 뿐 특정 요소로 직행하지는 않아요."
},
{
"courseSlug": "tool-devtools",
"question": "Elements 탭에서 뉴스 사이트 헤드라인을 \"우리 반 급식 최고\"로 바꾼 뒤 새로고침(F5)을 하면 어떻게 되나요?",
"option1": "서버 파일도 함께 바뀌어 다른 사람에게도 바뀐 화면이 보인다",
"option2": "수정 내용이 전부 사라지고 원래 화면으로 돌아온다",
"option3": "브라우저에 저장되어 내 컴퓨터에서는 계속 바뀐 채로 보인다",
"option4": "개발자도구를 닫기 전까지는 수정한 내용이 그대로 유지된다",
"answerIndex": 1,
"explanation": "Elements에서의 수정은 '내 브라우저의 복사본'에만 적용되고 서버의 진짜 파일은 전혀 바뀌지 않아요. 그래서 새로고침 한 번이면 전부 원상복구됩니다."
},
{
"courseSlug": "tool-devtools",
"question": "Network 탭에서 어떤 API 요청의 Status가 401로 표시되었습니다. 코스의 '빠른 판독법'에 따르면 이 상황의 의미는 무엇인가요?",
"option1": "서버 내부에서 오류가 발생했다는 뜻이다",
"option2": "요청이 성공적으로 처리되었다는 뜻이다",
"option3": "요청한 주소가 존재하지 않는다는 뜻이다",
"option4": "로그인이 안 된 상태로 요청을 보냈다는 뜻이다",
"answerIndex": 3,
"explanation": "코스에서 401은 \"로그인 안 됨\"을 뜻하는 단골 상태 코드로 소개됩니다. 4xx는 내(요청) 잘못, 5xx는 서버 잘못, 404는 \"그런 주소 없음\"이에요."
},
{
"courseSlug": "tool-devtools",
"question": "Lighthouse 검사 결과에서 점수 아래에 나오는 'Opportunities' 항목이 알려 주는 것은 무엇인가요?",
"option1": "어떤 부분을 어떻게 고치면 좋아지는지에 대한 개선 제안",
"option2": "페이지에서 발생한 자바스크립트 에러의 전체 목록",
"option3": "서버와 주고받은 모든 요청과 응답의 기록",
"option4": "다른 사이트와 비교한 우리 페이지의 점수 순위",
"answerIndex": 0,
"explanation": "Opportunities에는 \"이미지가 너무 커요, 이만큼 줄이면 몇 초 빨라져요\" 같은 구체적인 개선 방법이 적혀 있어요. 그래서 코스는 Lighthouse를 브라우저에 내장된 무료 컨설턴트에 비유합니다."
},
{
"courseSlug": "tool-devtools",
"question": "수습 개발자가 만든 게시글 목록 페이지에 목록이 안 나옵니다. Network 탭에서 해당 요청을 확인하니 Status는 200이고 Response에는 게시글 JSON이 제대로 들어 있었어요. 코스의 판별법에 따르면 어디를 먼저 의심해야 하나요?",
"option1": "Spring Boot 서버 쪽 코드",
"option2": "데이터베이스 연결 설정",
"option3": "React 화면 쪽 코드",
"option4": "네트워크 회선 상태",
"answerIndex": 2,
"explanation": "코스의 판별법대로 Response에 데이터가 멀쩡히 있는데 화면에 안 나오면 React(화면) 쪽 문제예요. Status가 4xx/5xx일 때가 요청이나 서버 쪽 문제입니다."
},
{
"courseSlug": "tool-docker",
"question": "Docker Desktop 왼쪽 메뉴의 세 탭을 코스의 비유로 짝지은 것 중 옳은 것은?",
"option1": "Containers=설계도 창고, Images=돌아가는 기계, Volumes=데이터 금고",
"option2": "Containers=데이터 금고, Images=돌아가는 기계, Volumes=설계도 창고",
"option3": "Containers=돌아가는 기계, Images=설계도 창고, Volumes=데이터 금고",
"option4": "Containers=돌아가는 기계, Images=데이터 금고, Volumes=설계도 창고",
"answerIndex": 2,
"explanation": "섹션 2에서 이미지는 설계도(붕어빵 틀), 컨테이너는 그 틀로 찍어낸 지금 돌아가는 기계, 볼륨은 지워지면 안 되는 데이터를 보관하는 금고에 비유했습니다."
},
{
"courseSlug": "tool-docker",
"question": "Windows에 Docker Desktop을 설치할 때 WSL2를 함께 켜는 이유로 코스가 설명한 것은?",
"option1": "Windows 보안 업데이트를 컨테이너에도 자동으로 적용하기 위해서",
"option2": "컨테이너 기술이 리눅스 기능을 쓰므로, Windows 안에 작은 리눅스 방을 만들어 그 안에서 엔진을 돌리기 위해서",
"option3": "Docker Desktop의 GUI 화면을 그리는 그래픽 가속이 WSL2에서만 지원되기 때문에",
"option4": "여러 PC의 컨테이너를 하나의 네트워크로 묶어 주는 기능이 WSL2에 들어 있어서",
"answerIndex": 1,
"explanation": "섹션 1의 핵심 — Docker는 리눅스에서 태어난 기술이라, Windows에서는 WSL2라는 '리눅스 방'을 만들고 그 안에서 진짜 엔진을 돌립니다."
},
{
"courseSlug": "tool-docker",
"question": "docker ps와 docker ps -a의 차이, 그리고 Docker Desktop Containers 탭의 기본 동작에 대한 설명으로 옳은 것은?",
"option1": "docker ps는 멈춘 컨테이너까지 보여 주고, Containers 탭은 실행 중인 것만 보여 준다",
"option2": "둘은 같은 결과를 내며, Containers 탭은 이미지 목록까지 한 화면에 같이 보여 준다",
"option3": "docker ps -a는 볼륨 목록까지 함께 보여 주고, Containers 탭은 docker ps와 똑같다",
"option4": "docker ps는 지금 도는 것만, docker ps -a는 멈춘 것까지 보여 주며 Containers 탭은 -a 쪽에 가깝다",
"answerIndex": 3,
"explanation": "섹션 4에서 docker ps는 실행 중인 컨테이너만, -a는 멈춘 것까지 전부 보여 주고, Desktop의 Containers 탭은 멈춘 컨테이너도 회색으로 표시하는 -a 쪽이라고 설명합니다."
},
{
"courseSlug": "tool-docker",
"question": "docker system prune에 --volumes 옵션을 붙일 때 특히 조심해야 하는 이유는?",
"option1": "안 쓰는 볼륨까지 지워지는데, 볼륨에는 DB 데이터처럼 잃으면 안 되는 것이 들어 있을 수 있어서",
"option2": "실행 중인 컨테이너까지 강제로 중지시킨 뒤 목록에서 전부 삭제해 버려서",
"option3": "받아 둔 모든 이미지가 삭제되어 다시 다운로드하는 데 시간이 오래 걸려서",
"option4": "WSL2 설정 파일(.wslconfig)까지 초기화되어 메모리 상한선이 사라져서",
"answerIndex": 0,
"explanation": "섹션 6의 경고 — prune 자체는 안전한 편이지만 --volumes를 붙이면 안 쓰는 볼륨(DB 데이터가 들어 있을 수 있는 금고)까지 지우므로 확인 문구를 꼭 읽어야 합니다."
},
{
"courseSlug": "tool-docker",
"question": "아침에 백엔드(Spring Boot)를 실행했더니 DB 연결 에러가 났다. 코스의 아침 루틴대로라면 가장 먼저 해야 할 일은?",
"option1": "백엔드 코드의 DB 접속 설정 파일을 열어 오타부터 찾아본다",
"option2": "docker system prune으로 도커를 한 번 정리한 뒤 백엔드를 다시 실행한다",
"option3": "docker compose ps(또는 Containers 탭)로 DB 컨테이너가 Up 상태인지부터 확인한다",
"option4": "PC를 재부팅해서 WSL2 메모리를 비운 다음 백엔드를 다시 시도한다",
"answerIndex": 2,
"explanation": "섹션 5에서 DB 연결 에러가 나면 '코드 문제인가?' 고민하기 전에 docker compose up -d / ps 루틴으로 DB가 살아 있는지부터 확인하는 것이 순서라고 강조합니다."
},
{
"courseSlug": "tool-gitea",
"question": "이 코스에서 설명하는 Gitea는 어떤 것인가요?",
"option1": "GitHub가 만든 유료 클라우드 서비스",
"option2": "GitHub 같은 서비스를 우리 회사 서버(AWS EC2 위 Docker 컨테이너)에 직접 설치해 쓰는 것",
"option3": "코드를 자동으로 리뷰해 주는 인공지능 도구",
"option4": "커밋 메시지를 대신 작성해 주는 편집기 확장 프로그램",
"answerIndex": 1,
"explanation": "섹션 1 '우리 Git 서버 투어'의 핵심입니다. 남의 건물(GitHub)에 세 들지 않고 우리 건물에 작업실을 차린 것이라, 회사 코드가 바깥으로 나가지 않습니다."
},
{
"courseSlug": "tool-gitea",
"question": "코스에서 배운 이슈(Issue)의 상태로 맞는 것은 무엇인가요?",
"option1": "Open, In Progress, Done의 세 단계",
"option2": "Draft, Ready, Merged의 세 단계",
"option3": "Open(진행 중)과 Closed(끝)의 딱 두 가지",
"option4": "New, Assigned, Resolved, Verified의 네 단계",
"answerIndex": 2,
"explanation": "섹션 3 '이슈로 할 일 관리'에서 이슈의 상태는 Open(진행 중)과 Closed(끝) 딱 두 가지라고 설명했습니다. 병원 접수증처럼 번호가 붙고 처리가 끝나면 닫힙니다."
},
{
"courseSlug": "tool-gitea",
"question": "코드 한 줄만 살짝 고쳐서 커밋했을 때, diff 화면에는 어떻게 표시되나요?",
"option1": "노란색으로 강조된 한 줄로 표시된다",
"option2": "회색 문맥 줄로만 표시되어 눈에 띄지 않는다",
"option3": "초록(+) 한 줄만 새로 표시된다",
"option4": "빨강(-) 한 줄과 초록(+) 한 줄의 짝으로 표시된다",
"answerIndex": 3,
"explanation": "섹션 5 'diff 읽는 법'에서 배운 내용입니다. diff에서 수정은 '삭제+추가'로 취급되어, 한 줄만 바뀌어도 지워진 빨강 줄과 새로 생긴 초록 줄이 짝으로 나타납니다."
},
{
"courseSlug": "tool-gitea",
"question": "PR 리뷰어가 바뀐 코드의 특정 줄에 정확히 코멘트를 달고 싶을 때, 올바른 방법은 무엇인가요?",
"option1": "Conversation 탭의 댓글 본문에 줄 번호를 직접 적어서 설명한다",
"option2": "Files Changed 탭에서 줄 번호에 마우스를 올려 나타나는 + 버튼을 클릭한다",
"option3": "Commits 탭에서 해당 커밋의 메시지를 수정해 의견을 남긴다",
"option4": "새 이슈를 만들어 줄 번호를 라벨(Label)로 붙여 전달한다",
"answerIndex": 1,
"explanation": "섹션 4 'Pull Request와 리뷰 화면'에서 리뷰어의 주무대는 Files Changed 탭이고, 줄 번호에 마우스를 올리면 나오는 + 버튼으로 그 줄에 정확히 코멘트를 달 수 있다고 배웠습니다. 교과서 여백에 포스트잇을 붙이는 것과 같은 방식입니다."
},
{
"courseSlug": "tool-gitea",
"question": "수습 개발자 민지는 어제까지 잘 되던 로그인 기능이 오늘 갑자기 안 되는 것을 발견했습니다. 이 코스에서 배운 대로라면 가장 먼저 확인해야 할 곳은 어디인가요?",
"option1": "저장소의 가장 최근 커밋을 열어 diff에서 바뀐 줄을 확인한다",
"option2": "위키(Wiki)에 트러블슈팅 페이지를 새로 만들어 기록한다",
"option3": "Releases 탭에서 최신 버전 태그의 체인지로그를 다시 작성한다",
"option4": "프로필의 잔디밭(활동 히트맵)에서 어제의 활동량을 살펴본다",
"answerIndex": 0,
"explanation": "섹션 5에서 '어제까지 되던 게 왜 안 되지?' 할 때는 마지막 커밋의 diff부터 확인하는 습관을 강조했습니다. 범인은 대부분 가장 최근에 바뀐 줄에 있기 때문입니다."
},
{
"courseSlug": "tool-intellij",
"question": "IntelliJ에서 Shift 키를 빠르게 두 번 누르면 실행되는 기능은 무엇인가?",
"option1": "코드 정렬(Reformat) — 흐트러진 코드를 자동으로 정리한다",
"option2": "프로젝트 전체 텍스트 검색 — 특정 문자열이 있는 파일을 찾는다",
"option3": "뭐든지 검색(Search Everywhere) — 클래스·파일·설정·액션을 한 창에서 찾는다",
"option4": "이름 바꾸기(Rename) — 변수나 메서드 이름을 사용처까지 전부 바꾼다",
"answerIndex": 2,
"explanation": "코스 1섹션의 필수 단축키 표에서 Shift Shift는 '뭐든지 검색(Search Everywhere)', 즉 만능 검색창이다. 코드 정렬은 Ctrl+Alt+L, 전체 텍스트 검색은 Ctrl+Shift+F, 이름 바꾸기는 Shift+F6이다."
},
{
"courseSlug": "tool-intellij",
"question": "라이브 템플릿에서 sout을 입력하고 Tab을 누르면 만들어지는 코드는 무엇인가?",
"option1": "System.out.println(); — 디버깅용 출력문 한 줄",
"option2": "public static void main(String[] args) { } — main 메서드",
"option3": "for (int i = 0; i < ; i++) { } — 기본 for 반복문",
"option4": "for (String item : items) { } — 컬렉션을 도는 향상된 for문",
"answerIndex": 0,
"explanation": "2섹션 라이브 템플릿 표에서 sout은 System.out.println();을 소환하는 주문이다. main 메서드는 psvm, 기본 for문은 fori, 향상된 for문은 iter가 만들어 준다."
},
{
"courseSlug": "tool-intellij",
"question": "IntelliJ의 로컬 히스토리(Local History)에 대한 설명으로 옳은 것은?",
"option1": "Git 커밋과 자동으로 동기화되어 팀 전체에 공유된다",
"option2": "PC를 바꿔도 계정에 연결되어 영구히 보관된다",
"option3": "git commit 명령을 실행해야만 스냅샷이 기록된다",
"option4": "파일을 저장할 때마다 IDE가 자동으로 스냅샷을 남기며, 보관 기간은 며칠 수준이다",
"answerIndex": 3,
"explanation": "3섹션에서 로컬 히스토리는 Git 커밋과 별개로 IDE가 저장 시마다 몰래 남기는 '비밀 일기장'이라고 설명한다. 다만 내 PC에만 며칠만 남는 임시 보험이므로 진짜 기록은 Git 커밋 + Gitea 푸시다."
},
{
"courseSlug": "tool-intellij",
"question": "브레이크포인트(빨간 점)를 찍었는데 프로그램이 그 줄에서 멈추지 않는다. 코스에서 '십중팔구'라고 말한 가장 흔한 원인은?",
"option1": "Active profiles에 local을 넣지 않아 설정 파일이 잘못 적용되어서",
"option2": "Debug(벌레 아이콘)가 아니라 Run(▶)으로 실행해서",
"option3": "환경변수 칸에 DB_PASSWORD를 주입하지 않아서",
"option4": "브레이크포인트에 조건을 걸지 않아 무시되어서",
"answerIndex": 1,
"explanation": "5섹션 경고에 따르면 빨간 점이 작동하려면 반드시 Debug(벌레 아이콘)로 실행해야 하며, 안 멈추는 경우는 십중팔구 Run(▶)으로 실행한 경우다. Run과 Debug는 형제지만 다르다."
},
{
"courseSlug": "tool-intellij",
"question": "반복문이 1,000번 도는데 i가 743일 때만 버그가 생긴다. 코스에서 소개한 방법 중 이 순간만 콕 집어 멈추는 가장 효율적인 방법은?",
"option1": "sout으로 매번 i 값을 출력해 콘솔에서 눈으로 743을 찾는다",
"option2": "브레이크포인트에서 F8(Step Over)을 743번 눌러 한 줄씩 전진한다",
"option3": "빨간 점을 우클릭해 i == 743 조건을 적어 조건이 참일 때만 멈추게 한다",
"option4": "i를 Add to Watches에 등록하면 743번째 반복에서 자동으로 멈춘다",
"answerIndex": 2,
"explanation": "4섹션 팁의 조건부 브레이크포인트 개념이다. 빨간 점을 우클릭해 조건(예: i == 743)을 적으면 그 조건이 참일 때만 멈춘다. Add to Watches는 값을 감시만 할 뿐 멈추게 하지는 않는다."
},
{
"courseSlug": "tool-notion",
"question": "노션에서 '접었다 펼치는 목록'으로 셀프 퀴즈를 만들 때 좋은 토글 블록을 만드는 입력법은 무엇인가요?",
"option1": "/표 를 입력한다",
"option2": "> 를 입력하고 스페이스를 누른다",
"option3": "``` 를 입력한다",
"option4": "# 을 입력하고 스페이스를 누른다",
"answerIndex": 1,
"explanation": "섹션 2의 기본 블록 4가지 표에서 토글 블록은 '> + 스페이스'로 만든다고 소개했어요. 제목만 보고 답을 떠올린 뒤 펼쳐서 확인하는 셀프 퀴즈에 딱 맞는 블록입니다."
},
{
"courseSlug": "tool-notion",
"question": "코스에서 노션 데이터베이스가 일반 표보다 강력한 이유로 꼽은 세 가지는 무엇인가요?",
"option1": "필터, 정렬, 보기(표·칸반·캘린더 전환)",
"option2": "수식 계산, 차트 생성, 자동 백업",
"option3": "댓글 달기, 버전 기록, 권한 관리",
"option4": "파일 첨부, 알림 설정, 외부 연동",
"answerIndex": 0,
"explanation": "섹션 5에서 데이터베이스가 표보다 강한 이유로 필터('상태 = 진행 중'만 보기), 정렬(마감일 순 줄 세우기), 보기(같은 데이터를 칸반·캘린더로 전환) 세 가지를 들었어요."
},
{
"courseSlug": "tool-notion",
"question": "코스에서 명령어를 스크린샷 대신 코드 블록으로 저장하라고 강조하는 가장 큰 이유는 무엇인가요?",
"option1": "스크린샷보다 저장 용량을 훨씬 적게 차지하기 때문에",
"option2": "노션이 이미지 업로드 개수를 제한하기 때문에",
"option3": "복사 버튼으로 바로 붙여넣고 검색도 되는 '살아 있는 기록'이기 때문에",
"option4": "코드 블록은 다른 사람이 수정할 수 없게 잠기기 때문에",
"answerIndex": 2,
"explanation": "섹션 4에서 스크린샷 속 명령어는 복사도 검색도 안 되는 '죽은 기록'이고, 코드 블록은 복사 버튼 클릭 한 번으로 터미널에 붙여넣을 수 있으며 언어 지정 시 색까지 입혀지는 '살아 있는 기록'이라고 설명했어요."
},
{
"courseSlug": "tool-notion",
"question": "추천 페이지 구조에서 'TIL 일지'와 '트러블슈팅 모음'을 섞지 말고 따로 두라고 한 이유는 무엇인가요?",
"option1": "한 페이지에 블록이 많아지면 노션이 느려지기 때문에",
"option2": "트러블슈팅은 멘토에게만 공유해야 하기 때문에",
"option3": "일지는 데이터베이스로 만들 수 없기 때문에",
"option4": "일지는 날짜순, 해결법은 주제순으로 찾는 방법이 서로 다르기 때문에",
"answerIndex": 3,
"explanation": "섹션 3의 페이지 구조에서 '일지는 날짜순, 해결법은 주제순 — 찾는 방법이 다르니까요'라고 설명했어요. 기록은 나중에 꺼내 쓰는 방식에 맞춰 정리해야 합니다."
},
{
"courseSlug": "tool-notion",
"question": "수습생 지우가 'port is already allocated' 에러로 막혔던 Docker 포트 충돌 문제를 해결하고 트러블슈팅 페이지를 쓰려고 해요. '3개월 뒤의 나는 남이다'라는 코스의 규칙에 가장 맞는 제목은 무엇인가요?",
"option1": "오늘의 삽질 대탈출기",
"option2": "2026-07-16 문제 해결 기록",
"option3": "Docker 포트 충돌(port is already allocated) 해결",
"option4": "드디어 빨간 에러를 잡았다!",
"answerIndex": 2,
"explanation": "섹션 6의 '검색되는 기록' 규칙에 따르면 에러 메시지 원본과 핵심 단어를 제목에 넣어야 나중의 내가 검색으로 바로 찾을 수 있어요. 나머지 제목들은 3개월 뒤에 무슨 내용인지 검색할 단서가 없습니다."
},
{
"courseSlug": "tool-postman",
"question": "이 코스에서 설명하는 Postman의 핵심 역할은 무엇인가?",
"option1": "프론트 화면을 자동으로 만들어 주는 UI 생성 도구다",
"option2": "백엔드 코드의 문법 오류를 찾아 고쳐 주는 편집기다",
"option3": "프론트 화면 없이 백엔드 API 엔드포인트를 직접 호출해 보는 도구다",
"option4": "데이터베이스 테이블을 시각적으로 관리해 주는 도구다",
"answerIndex": 2,
"explanation": "섹션 1에서 Postman은 프론트라는 중간 단계를 건너뛰고 백엔드의 문(엔드포인트)을 직접 두드리는 도구라고 설명한다. 이렇게 하면 버그가 프론트 탓인지 백엔드 탓인지 빠르게 가려낼 수 있다."
},
{
"courseSlug": "tool-postman",
"question": "로그인 API(POST /api/auth/login)를 호출할 때 이메일과 비밀번호 JSON을 담아 보내는 올바른 방법은?",
"option1": "Body 탭에서 raw를 선택하고 형식을 JSON으로 바꾼 뒤 입력한다",
"option2": "Params 탭에 email과 password를 쿼리 값으로 추가한다",
"option3": "Headers 탭에 email과 password 값을 직접 적어 넣는다",
"option4": "주소창 끝에 이메일과 비밀번호를 이어 붙여서 보낸다",
"answerIndex": 0,
"explanation": "섹션 4의 실습 순서대로 POST 요청은 Body 탭 → raw 선택 → 오른쪽 드롭다운을 JSON으로 바꾼 뒤 데이터를 입력한다. POST는 서버에 데이터를 실어 보내는 요청이고 그 짐칸이 Body다."
},
{
"courseSlug": "tool-postman",
"question": "수습(INTERN) 계정으로 로그인한 상태에서 관리자 전용 API를 호출했다. 코스 내용에 따르면 정상적으로 받게 되는 응답은?",
"option1": "400 Bad Request — 요청 형식이 잘못되었기 때문",
"option2": "401 Unauthorized — 서버가 내가 누구인지 모르기 때문",
"option3": "404 Not Found — 그런 주소가 존재하지 않기 때문",
"option4": "403 Forbidden — 누구인지는 알지만 권한이 없기 때문",
"answerIndex": 3,
"explanation": "섹션 7에서 401은 '너 누군지 몰라'(로그인 안 됨), 403은 '너 누군지 아는데 이건 안 돼'(권한 부족)라고 구분한다. 수습 계정으로 관리자 API를 부르면 403이 오는 게 정상이다."
},
{
"courseSlug": "tool-postman",
"question": "요청 주소를 {{baseUrl}}/api/checklist처럼 변수로 써 두면 얻는 이점으로 코스가 설명한 것은?",
"option1": "요청 처리 속도가 빨라져서 응답 Time이 줄어든다",
"option2": "오른쪽 위 드롭다운에서 환경만 바꾸면 컬렉션 전체가 다른 서버를 향한다",
"option3": "쿠키가 자동으로 보관되어 로그인 상태가 계속 유지된다",
"option4": "주소가 암호화되어 운영 서버로 더 안전하게 전송된다",
"answerIndex": 1,
"explanation": "섹션 6의 환경(Environment) 개념으로, baseUrl 같은 변수를 중괄호 두 겹 문법으로 빼 두면 local과 prod를 스위치 하나로 전환할 수 있다. 주소를 매번 고치다 생기는 실수를 막는 방식이다."
},
{
"courseSlug": "tool-postman",
"question": "브라우저 화면에서 체크리스트가 이상하게 보여서 Postman으로 GET /api/checklist를 직접 호출했더니 설계서와 똑같은 올바른 JSON이 돌아왔다. 코스의 식당 비유에 따르면 다음으로 해야 할 판단은?",
"option1": "백엔드 코드에 버그가 있으므로 컨트롤러부터 수정한다",
"option2": "DB 데이터가 잘못되었으므로 테이블을 직접 고친다",
"option3": "백엔드는 정상이므로 프론트(React) 쪽 코드를 의심해 본다",
"option4": "네트워크 장애가 원인이므로 서버를 재시작해 본다",
"answerIndex": 2,
"explanation": "식당 비유에서 주방(백엔드)에 직접 주문해 제대로 된 음식이 나오면 문제는 홀(프론트)에 있다. 백엔드 응답이 명세와 같다면 용의자에서 백엔드를 지우고 프론트를 살펴보는 것이 코스가 가르치는 수사 순서다."
},
{
"courseSlug": "tool-shortcuts",
"question": "회사에서 자리를 비울 때 반드시 눌러야 하는 '보안 기본기' 단축키는 무엇인가요?",
"option1": "Win + Z — 스냅 레이아웃 열기",
"option2": "Win + L — 화면 잠금",
"option3": "Win + Tab — 작업 보기 열기",
"option4": "Win + D — 바탕화면 보기",
"answerIndex": 1,
"explanation": "코스 2섹션(창 관리)에서 Win+L은 화면 잠금이며, 잠그지 않고 자리를 뜨는 건 현관문을 열어 두고 외출하는 것과 같다고 강조합니다."
},
{
"courseSlug": "tool-shortcuts",
"question": "브라우저에서 실수로 중요한 문서 탭을 닫아 버렸을 때, 코스가 '실수 복구의 은인'이라고 소개한 단축키는?",
"option1": "Ctrl + T — 새 탭 열기",
"option2": "Ctrl + W — 현재 탭 닫기",
"option3": "Ctrl + Shift + T — 방금 닫은 탭 되살리기",
"option4": "Ctrl + 9 — 마지막 탭으로 이동",
"answerIndex": 2,
"explanation": "4섹션(탐색기·브라우저)에서 Ctrl+Shift+T는 닫은 탭을 되살리는 단축키로, 여러 번 누르면 닫은 순서의 역순으로 계속 되살아난다고 설명합니다."
},
{
"courseSlug": "tool-shortcuts",
"question": "텍스트 편집의 '조합 공식'에 따르면, Ctrl + Shift + End를 눌렀을 때 일어나는 일은 무엇인가요?",
"option1": "커서 위치부터 문서 끝까지 전부 선택된다",
"option2": "커서가 있는 줄의 끝까지만 선택된다",
"option3": "문서 전체가 한 번에 선택된다",
"option4": "커서가 문서 맨 아래로 이동만 하고 선택은 되지 않는다",
"answerIndex": 0,
"explanation": "3섹션의 공식대로 Ctrl은 '문서 단위로 크게 이동', Shift는 '이동하면서 선택'이라 둘을 곱하면 커서부터 문서 끝까지 통째로 선택됩니다."
},
{
"courseSlug": "tool-shortcuts",
"question": "코스에서 Win + V(클립보드 히스토리)를 쓸 때 특히 주의하라고 한 것은 무엇인가요?",
"option1": "히스토리를 켜면 복사 속도가 느려지므로 필요할 때만 켠다",
"option2": "고정(pin)한 항목은 재부팅하면 모두 사라지므로 다시 등록한다",
"option3": "목록에는 텍스트만 저장되고 이미지 복사는 남지 않는다",
"option4": "복사한 비밀번호나 토큰도 목록에 남으므로 바로 삭제한다",
"answerIndex": 3,
"explanation": "5섹션의 주의 박스에서, 민감한 값을 복사하면 히스토리 목록에 그대로 남아 남이 볼 수 있으니 바로 삭제하고 비밀번호는 관리자의 자동 입력으로 다루라고 안내합니다."
},
{
"courseSlug": "tool-shortcuts",
"question": "수습 개발자 지민이는 코딩 중에 메신저 알림이 눈에 띌 때마다 집중이 끊깁니다. 이 코스의 권장 해결법은 무엇인가요?",
"option1": "알림이 올 때마다 Win + D로 바탕화면을 보며 흐름을 끊고 쉰다",
"option2": "메신저 창을 Win + ↓로 최소화해 두고 필요할 때만 다시 연다",
"option3": "Win + Ctrl + D로 가상 데스크톱을 만들어 코딩 책상과 메신저 책상을 분리한다",
"option4": "Alt + Tab으로 재빨리 전환해 알림을 그때그때 확인하고 돌아온다",
"answerIndex": 2,
"explanation": "2섹션의 '책상을 여러 개 쓰는' 비유처럼, 가상 데스크톱으로 코딩(1번)과 메신저(3번)를 분리하면 알림에 홀려 딴 길로 새는 걸 물리적으로 막을 수 있다고 설명합니다."
},
{
"courseSlug": "tool-terminal",
"question": "코스의 '검은 창 삼형제' 정리에 따르면, 윈도우에서 평소에 기본으로 쓰기 좋은 셸과 리눅스 명령을 그대로 따라 하고 싶을 때 쓰는 셸의 조합으로 맞는 것은?",
"option1": "평소엔 cmd, 리눅스 명령은 PowerShell",
"option2": "평소엔 PowerShell, 리눅스 명령은 Git Bash",
"option3": "평소엔 Git Bash, 리눅스 명령은 cmd",
"option4": "평소엔 cmd, 리눅스 명령은 Git Bash",
"answerIndex": 1,
"explanation": "섹션 1의 결론이 '평소엔 PowerShell, 리눅스 명령이 필요하면 Git Bash'입니다. cmd는 아주 오래된 배치 파일을 돌릴 때 정도로, 요즘은 거의 쓰지 않는다고 정리했어요."
},
{
"courseSlug": "tool-terminal",
"question": "코스에서 '터미널'과 '셸(shell)'의 관계를 설명한 내용으로 옳은 것은?",
"option1": "터미널은 명령을 해석하는 프로그램이고, 셸은 그 결과를 그려 주는 화면이다",
"option2": "터미널과 셸은 같은 것을 부르는 두 가지 이름일 뿐 구분할 필요가 없다",
"option3": "터미널은 글자가 표시되는 창이고, 셸은 그 안에서 명령을 해석해 주는 통역 프로그램이다",
"option4": "터미널은 윈도우 전용 용어이고, 셸은 리눅스 전용 용어라서 서로 섞어 쓸 수 없다",
"answerIndex": 2,
"explanation": "섹션 1에서 터미널은 글자가 표시되는 창(카페), 셸은 그 안에서 명령을 해석하는 통역 프로그램(바리스타)이라고 비유했습니다. 그래서 한 Windows Terminal 창에 PowerShell 탭과 Git Bash 탭을 동시에 열 수 있어요."
},
{
"courseSlug": "tool-terminal",
"question": "블로그에서 복사한 rm -rf 폴더 명령이 PowerShell에서 에러가 나는 이유로, 코스의 설명과 일치하는 것은?",
"option1": "PowerShell에는 rm 명령 자체가 없어서 New-Item으로 지워야 하기 때문이다",
"option2": "관리자 권한 터미널이 아니어서 액세스가 거부되었기 때문이다",
"option3": "rm은 Git Bash 전용 명령이라 PowerShell 탭에서는 아예 입력이 막히기 때문이다",
"option4": "PowerShell의 rm은 Remove-Item의 별명(alias)이라 -rf 옵션이 없고, rm -r -fo처럼 써야 하기 때문이다",
"answerIndex": 3,
"explanation": "섹션 3에서 PowerShell의 ls·cd·cat·rm은 진짜 리눅스 명령이 아니라 별명(alias)이라고 했어요. 간단한 사용은 통하지만 -rf 같은 옵션부터는 달라서, PowerShell식으로는 rm -r -fo(Recurse + Force)를 써야 합니다."
},
{
"courseSlug": "tool-terminal",
"question": "코스에서 배운 파이프(|) 기호를 기준으로, tasklist | findstr node 명령의 의미로 옳은 것은?",
"option1": "tasklist의 전체 출력 중에서 node가 들어간 줄만 걸러서 보여 준다",
"option2": "tasklist와 findstr node를 동시에 병렬로 실행해서 속도를 높인다",
"option3": "node 프로세스를 찾아낸 뒤 그 프로세스를 자동으로 강제 종료한다",
"option4": "tasklist의 결과를 node라는 이름의 파일로 저장해 두고 나중에 연다",
"answerIndex": 0,
"explanation": "섹션 4에서 파이프(|)는 '앞 명령의 출력을 뒤 명령에게 넘겨주는 배관'이라고 설명했어요. 전체 프로세스 목록을 뽑아서(tasklist) 그중 node가 들어간 줄만 걸러 주는(findstr) 것이지, 종료나 저장을 하지는 않습니다."
},
{
"courseSlug": "tool-terminal",
"question": "개발 서버를 분명히 껐는데 npm run dev를 다시 켜니 '포트가 이미 사용 중입니다(5173)' 에러가 납니다. 코스에서 배운 3단계 해결법대로라면 가장 먼저 해야 할 일은?",
"option1": "taskkill /f /im node.exe 로 node 프로세스를 전부 즉시 종료한다",
"option2": "netstat -ano | findstr :5173 으로 그 포트를 쓰고 있는 프로세스의 PID를 찾는다",
"option3": "관리자 권한 터미널을 열어 방화벽에서 5173 포트 규칙을 바꾼다",
"option4": "ipconfig 로 내 IP 주소와 게이트웨이 정보부터 확인한다",
"answerIndex": 1,
"explanation": "섹션 4의 실전 3단계는 1) netstat -ano | findstr :5173 으로 범인 PID 찾기, 2) tasklist로 어떤 프로그램인지 확인, 3) taskkill /f /pid 로 종료 순서예요. 무엇이 포트를 잡고 있는지 확인하기 전에 무작정 전부 죽이는 건 순서가 아닙니다."
},
{
"courseSlug": "tool-vscode",
"question": "코스에서 \"이 중에 딱 하나만 고르라면\"이라고 강조한, VS Code의 모든 기능을 검색해서 실행할 수 있는 단축키는 무엇인가요?",
"option1": "Ctrl+P",
"option2": "Ctrl+Shift+F",
"option3": "Ctrl+Shift+P",
"option4": "Ctrl+Shift+K",
"answerIndex": 2,
"explanation": "Ctrl+Shift+P는 명령 팔레트를 여는 단축키로, 다른 단축키를 까먹어도 팔레트에 기능 이름만 치면 실행할 수 있다고 코스 섹션 1에서 강조합니다."
},
{
"courseSlug": "tool-vscode",
"question": "추천 확장 4종 중 Prettier가 하는 일로 코스에서 설명한 것은 무엇인가요?",
"option1": "코드 한 줄마다 누가 언제 왜 고쳤는지 표시해 준다",
"option2": "저장할 때마다 들쭉날쭉한 코드를 자동으로 정렬해 준다",
"option3": "rafce를 치고 Tab을 누르면 컴포넌트 뼈대를 완성해 준다",
"option4": "메뉴 전체를 한국어로 바꿔 진입장벽을 낮춰 준다",
"answerIndex": 1,
"explanation": "Prettier는 format on save 설정을 켜면 Ctrl+S를 누를 때마다 코드를 자동 정렬해 주는 확장입니다. 나머지 보기는 각각 GitLens, ES7+ React Snippets, Korean Language Pack의 설명이에요."
},
{
"courseSlug": "tool-vscode",
"question": "섹션 6 '검색의 기술'에서 설명한 Ctrl+P와 Ctrl+Shift+F의 용도 구분으로 옳은 것은 무엇인가요?",
"option1": "Ctrl+P는 파일 이름으로 찾고, Ctrl+Shift+F는 파일 내용으로 프로젝트 전체를 검색한다",
"option2": "Ctrl+P는 현재 파일 안을 검색하고, Ctrl+Shift+F는 파일 이름으로 찾는다",
"option3": "Ctrl+P는 정규식 검색 전용이고, Ctrl+Shift+F는 특정 확장자만 검색한다",
"option4": "Ctrl+P는 최근 연 파일을 전환하고, Ctrl+Shift+F는 명령 팔레트를 연다",
"answerIndex": 0,
"explanation": "코스는 Ctrl+P를 '도서관에서 책 제목으로 찾기'(파일 이름), Ctrl+Shift+F를 '책 속 문장으로 찾기'(내용 전체 검색)에 비유하며 두 검색의 용도를 구분합니다."
},
{
"courseSlug": "tool-vscode",
"question": "VS Code 소스 제어(Git) 패널에서 파일 옆의 + 버튼을 누르는 것은 어떤 git 명령과 같다고 코스에서 설명하나요?",
"option1": "git push — 원격 저장소로 올리기",
"option2": "git commit — 변경 내용을 기록하기",
"option3": "git status — 작업 상태 확인하기",
"option4": "git add — 변경 파일을 스테이징하기",
"answerIndex": 3,
"explanation": "섹션 4에서 파일 옆 + 버튼은 스테이징, 즉 git add와 같다고 설명합니다. 커밋은 위 입력창의 체크 버튼, push+pull은 '변경 내용 동기화' 버튼이에요."
},
{
"courseSlug": "tool-vscode",
"question": "수습생 지우는 집 PC에서 확장 설치와 단축키·설정을 공들여 맞춰 두었는데, 내일부터는 학교 PC에서도 똑같은 환경으로 작업하고 싶습니다. 코스에서 배운 내용대로라면 어떻게 해야 할까요?",
"option1": "확장 목록을 종이에 적어 두고 학교 PC에서 하나씩 다시 설치한다",
"option2": "설정 파일을 USB에 복사해서 학교 PC의 폴더에 붙여넣는다",
"option3": "설정 동기화를 켜고 GitHub 계정으로 로그인해 두면 학교 PC에서도 로그인 한 번으로 복원된다",
"option4": "Git 패널에서 설정을 커밋해 Gitea에 올린 뒤 학교 PC에서 내려받는다",
"answerIndex": 2,
"explanation": "섹션 5의 설정 동기화(Settings Sync)는 설정·단축키·확장 목록·스니펫을 계정에 백업해 주는 기능으로, 코스에서 '게임의 클라우드 세이브'에 비유합니다. 어떤 PC든 로그인 한 번이면 내 환경이 복원돼요."
},
{
"courseSlug": "troubleshooting",
"question": "코스에서 작업 관리자를 여는 방법 세 가지 중 '가장 빠른 지름길'로 소개한 것은?",
"option1": "Ctrl + Alt + Delete를 누른 뒤 작업 관리자를 선택한다",
"option2": "Ctrl + Shift + Esc를 누른다",
"option3": "작업 표시줄을 우클릭한 뒤 작업 관리자를 선택한다",
"option4": "Windows 키 + R을 누른 뒤 taskmgr을 입력한다",
"answerIndex": 1,
"explanation": "섹션 2에서 작업 관리자를 여는 세 가지 방법 중 Ctrl+Shift+Esc를 '가장 빠른 지름길'로 소개했습니다. 나머지 두 방법보다 단계가 적어 한 번에 열립니다."
},
{
"courseSlug": "troubleshooting",
"question": "백업의 3-2-1 원칙에서 숫자 '1'이 뜻하는 것은 무엇인가?",
"option1": "백업은 하루에 1번만 하면 충분하다는 뜻이다",
"option2": "원본 파일은 반드시 1개만 유지해야 한다는 뜻이다",
"option3": "복사본 중 1개는 다른 장소에 보관해야 한다는 뜻이다",
"option4": "저장 매체는 1가지 종류로 통일해야 한다는 뜻이다",
"answerIndex": 2,
"explanation": "섹션 4의 3-2-1 원칙은 복사본 3개, 서로 다른 매체 2가지, 그중 1개는 다른 장소 보관입니다. 노트북과 외장하드를 같은 가방에 넣으면 가방을 잃는 순간 둘 다 사라지기 때문입니다."
},
{
"courseSlug": "troubleshooting",
"question": "블루스크린(BSOD)이 떴을 때 코스에서 폰 카메라로 찍어서라도 꼭 챙기라고 한 '단서 두 개'는?",
"option1": "중지 코드와 실패한 .sys 파일명",
"option2": "윈도우 버전과 마지막 업데이트 날짜",
"option3": "CPU 온도와 램(메모리) 사용량",
"option4": "에러 발생 시각과 실행 중이던 프로그램 목록",
"answerIndex": 0,
"explanation": "섹션 3에서 단서 ①은 중지 코드(사망 원인명), 단서 ②는 .sys 파일명(용의자 실명)이라고 했습니다. 이 두 줄을 그대로 검색하는 것이 문제 해결의 출발점입니다."
},
{
"courseSlug": "troubleshooting",
"question": "\"껐다 켜 보셨어요?\"라는 재부팅이 자주 통하는 이유로 코스가 설명한 원리는 무엇인가?",
"option1": "디스크에 쌓인 임시 파일이 자동으로 삭제되기 때문이다",
"option2": "CPU가 식으면서 스로틀링이 풀리기 때문이다",
"option3": "윈도우가 재부팅 중에 손상된 파일을 복구해 주기 때문이다",
"option4": "전원이 꺼지면 램의 내용이 사라져 꼬인 상태(state)가 초기화되기 때문이다",
"answerIndex": 3,
"explanation": "섹션 6의 핵심 단어는 상태(state)입니다. 램은 전원이 꺼지면 내용이 전부 사라지는 메모리라서, 재부팅하면 쌓인 찌꺼기와 꼬임이 통째로 리셋됩니다. 단, 증상만 지울 뿐 원인은 못 고칩니다."
},
{
"courseSlug": "troubleshooting",
"question": "수습 과제 중 콘솔에 \"Objects are not valid as a React child\" 에러가 떴고, 메시지 뒤에 내 프로젝트 폴더 경로도 붙어 있다. 코스의 검색 요령대로라면 가장 좋은 방법은?",
"option1": "\"리액트 하다가 화면에 에러남\"처럼 상황을 내 말로 요약해서 검색한다",
"option2": "에러 문장을 따옴표로 감싸 그대로 검색하되, 내 폴더 경로 같은 부분은 빼고 react 키워드를 더한다",
"option3": "내 폴더 경로까지 포함한 전체 메시지를 한 글자도 빼지 않고 통째로 검색한다",
"option4": "에러 메시지 대신 화면을 스크린샷으로 찍어 이미지 검색을 한다",
"answerIndex": 1,
"explanation": "섹션 7의 요령은 에러 메시지를 번역하지 말고 그대로 붙여넣고, 핵심 문구를 따옴표로 감싸고, 상황 키워드를 1~2개 더하는 것입니다. 단, 파일 경로처럼 '나만의 부분'은 빼야 같은 에러를 겪은 사람의 글을 찾을 수 있습니다."
},
{
"courseSlug": "typography",
"question": "코스에서 설명하는 세리프(Serif)와 산세리프(Sans-serif)를 구분하는 기준은 무엇인가?",
"option1": "글자 기울기가 있는지 없는지",
"option2": "획 끝에 장식(삐침)이 있는지 없는지",
"option3": "글자 폭이 모두 같은지 다른지",
"option4": "한글을 지원하는지 안 하는지",
"answerIndex": 1,
"explanation": "세리프는 획 끝에 장식(삐침)이 있는 폰트, 산세리프는 획 끝이 깔끔하게 잘린 폰트입니다. 섹션 1에서 다룬 폰트의 가장 큰 두 갈래 분류 기준이에요."
},
{
"courseSlug": "typography",
"question": "한글 폰트를 만들기 어려운 이유로 코스가 제시한 완성형 한글의 글자 수는 몇 자인가?",
"option1": "약 100자",
"option2": "2,350자",
"option3": "11,172자",
"option4": "24,000자",
"answerIndex": 2,
"explanation": "한글은 초성×중성×종성 조합으로 완성형 11,172자를 전부 그려야 합니다. 알파벳이 100자 남짓인 것과 비교해 만드는 비용이 커서 좋은 무료 한글 폰트가 귀하다는 것이 섹션 2의 핵심이에요."
},
{
"courseSlug": "typography",
"question": "문장에서 무언가를 강조할 때 코스가 제시한 우선순위를 순서대로 바르게 나열한 것은?",
"option1": "색 변경 → 굵기 올리기 → 크기 키우기",
"option2": "크기 키우기 → 색 변경 → 굵기 올리기",
"option3": "색 변경 → 크기 키우기 → 굵기 올리기",
"option4": "굵기 올리기 → 크기 키우기 → 색 변경",
"answerIndex": 3,
"explanation": "섹션 5의 강조 우선순위는 1순위 굵기, 2순위 크기, 3순위 색입니다. 굵기는 색 조화를 깨지 않으면서 확실하게 눈에 띄고, 색은 남용하면 뭐가 중요한지 모르는 화면이 되기 때문이에요."
},
{
"courseSlug": "typography",
"question": "웹 서비스 UI 본문에 거의 다 산세리프를 쓰는 이유로 코스가 설명한 것은?",
"option1": "화면 픽셀에서는 가는 삐침이 뭉개져 오히려 지저분해 보이기 때문",
"option2": "세리프 폰트는 대부분 유료 라이선스라 비용이 많이 들기 때문",
"option3": "산세리프는 어떤 폰트든 파일 용량이 세리프보다 작기 때문",
"option4": "세리프 폰트는 굵기 단계를 여러 개 제공하지 않기 때문",
"answerIndex": 0,
"explanation": "픽셀로 그리는 화면에서는 세리프의 가는 삐침이 뭉개지기 쉬워 산세리프가 훨씬 또렷합니다. 세리프는 종이에 인쇄된 긴 글에서 시선을 자연스럽게 이어 주는 데 유리하다는 것이 섹션 1의 설명이에요."
},
{
"courseSlug": "typography",
"question": "수습인 내가 '무료 다운로드'라고 적힌 예쁜 폰트를 발견해 회사 학습 플랫폼에 추가하고 싶다. 코스 기준으로 가장 올바른 행동은?",
"option1": "무료로 배포되는 폰트이므로 바로 프로젝트에 추가한다",
"option2": "출처와 폰트 이름을 화면 하단에 표기하고 사용한다",
"option3": "라이선스 원문에서 상업 이용·웹 임베딩 허용을 확인하고, 애매하면 멘토와 상의한다",
"option4": "회사 PC에 이미 설치된 폰트인지 확인되면 그대로 사용한다",
"answerIndex": 2,
"explanation": "섹션 7에서 '무료 다운로드 가능'과 '무료 사용 가능'은 다른 말이라고 강조합니다. 개인 사용만 무료인 폰트를 회사 서비스에 쓰면 라이선스 위반이므로, 라이선스 원문을 확인하고 근거를 가져와 멘토와 상의하는 것이 기준이에요."
},
{
"courseSlug": "uiux",
"question": "코스의 케첩병 비유에서 '반짝반짝 고급스럽지만 탁탁 쳐도 케첩이 안 나오는 유리병'은 어떤 제품을 보여주는 예인가?",
"option1": "UI는 나쁘지만 UX는 좋은 제품",
"option2": "UI와 UX가 모두 좋은 제품",
"option3": "UI는 좋지만 UX는 나쁜 제품",
"option4": "UI와 UX가 모두 나쁜 제품",
"answerIndex": 2,
"explanation": "유리병은 식탁 위에서 예쁘지만(UI 승) 케첩이 안 나와 바닥을 쳐야 하므로 겪는 경험은 나쁩니다(UX 패). 섹션 1의 'UI는 보이는 것, UX는 겪는 것' 개념입니다."
},
{
"courseSlug": "uiux",
"question": "사용자의 눈이 화면을 F패턴으로 스캔한다는 사실에서 코스가 내리는 결론은 무엇인가?",
"option1": "중요한 것일수록 위쪽·왼쪽에 크게 둬야 한다",
"option2": "중요한 것일수록 아래쪽·오른쪽에 작게 둬야 한다",
"option3": "모든 내용을 같은 크기로 배치해 공평하게 읽히게 해야 한다",
"option4": "내용을 화면 가운데에만 모아 눈길을 고정해야 한다",
"answerIndex": 0,
"explanation": "F패턴에서 눈은 맨 윗줄을 끝까지 읽고 점점 짧게 훑다가 왼쪽 가장자리만 내려가며 스캔합니다. 그래서 섹션 2는 중요한 것일수록 '위쪽·왼쪽·크게' 두라고 결론짓습니다."
},
{
"courseSlug": "uiux",
"question": "과제 제출 버튼 코드에서 submitting이 true인 동안 버튼을 disabled로 잠그는 가장 중요한 이유는?",
"option1": "서버 응답 속도를 더 빠르게 만들기 위해",
"option2": "연타로 과제가 두 번 제출되는 사고를 막기 위해",
"option3": "버튼 색을 파랑에서 회색으로 자연스럽게 바꾸기 위해",
"option4": "제출 중에 다른 페이지로 이동하지 못하게 막기 위해",
"answerIndex": 1,
"explanation": "섹션 4의 제출 버튼 해부에 따르면 disabled 잠금은 연타로 인한 중복 제출을 막는 '실수 방지'이고, '제출 중...' 글자 변경은 '피드백'입니다. 버튼 하나에 UX 두 가지가 들어 있습니다."
},
{
"courseSlug": "uiux",
"question": "코스에서 '실패' 표시를 빨간색 하나에만 의존하면 안 되고 글자나 아이콘을 함께 줘야 한다고 하는 이유는?",
"option1": "빨간색은 행동(눌러도 됨)을 나타내는 전용 색이라서",
"option2": "빨간색은 어떤 배경에서도 명도 대비가 항상 낮아서",
"option3": "화면 밝기를 낮추면 빨간색이 아예 보이지 않게 되어서",
"option4": "색약인 사용자는 빨강과 초록을 구분하기 어려울 수 있어서",
"answerIndex": 3,
"explanation": "섹션 5의 접근성 개념입니다. 색약 사용자를 위해 색 하나에만 의존하지 말고 '실패'라는 글자나 아이콘을 함께 줘야 하며, 신호등이 색과 위치로 두 번 알려 주는 것과 같은 원리입니다."
},
{
"courseSlug": "uiux",
"question": "수습생 A가 로그인 화면 비평에 \"왠지 답답해요\"라고 썼다. 이 코스의 화면 비평 규칙에 맞게 고친 문장은?",
"option1": "\"누가 이렇게 만들었는지 모르겠지만 전체적으로 별로예요\"",
"option2": "\"그냥 첫인상이 마음에 안 들어서 다시 만들면 좋겠어요\"",
"option3": "\"여백이 부족해서 라벨과 입력칸의 그룹핑이 안 보여요(근접성)\"",
"option4": "\"색 조합이 제 취향이 아니라서 더 화려하게 바꾸고 싶어요\"",
"answerIndex": 2,
"explanation": "섹션 8의 핵심 규칙은 '느낌이 아니라 용어로' 말하고 근거(어느 섹션의 어떤 원칙인지)를 붙이는 것입니다. 답답함의 원인을 섹션 6의 여백·근접성 개념으로 설명한 문장만 근거 있는 비평입니다."
},
{
"courseSlug": "user-research",
"question": "인터뷰에서 \"이 기능 편리하죠?\" 같은 질문이 나쁜 질문인 가장 큰 이유는 무엇인가요?",
"option1": "질문이 너무 길어서 응답자가 지루해지기 때문",
"option2": "과거가 아니라 현재의 습관을 물어보기 때문",
"option3": "듣고 싶은 답을 질문에 심어 '예의상 네'라는 답만 얻게 되기 때문",
"option4": "응답자가 다음 질문에 답하기를 거부하게 되기 때문",
"answerIndex": 2,
"explanation": "코스 섹션 2의 '유도 질문'에 해당합니다. 내가 듣고 싶은 답을 질문에 심으면 상대는 면전에서 거절하기 어려워 \"네...\"라고 답하게 되고, 이는 데이터가 아니라 '예의'를 수집한 것이라고 설명합니다."
},
{
"courseSlug": "user-research",
"question": "이 코스에서 말하는 '페르소나'의 올바른 정의는 무엇인가요?",
"option1": "아직 만나 보지 못한 이상적인 사용자를 상상해서 만든 가상 인물",
"option2": "리서치에서 만난 여러 실제 사용자의 공통점을 한 명의 대표 인물로 뭉친 카드",
"option3": "플랫폼을 가장 오래 사용한 실제 사용자 한 명의 상세 프로필",
"option4": "설문 응답자 전체의 평균 나이와 취향을 정리한 통계표",
"answerIndex": 1,
"explanation": "섹션 4에서 페르소나는 리서치 데이터의 공통점을 한 명의 '대표 인물' 카드로 뭉친 것이라고 정의합니다. 상상으로 지어내면 소설이 되고, 리서치 데이터로 만들면 나침반이 된다고 설명하죠."
},
{
"courseSlug": "user-research",
"question": "인터뷰만으로는 부족해서 '관찰'이 꼭 필요한 이유로 코스가 제시하는 것은 무엇인가요?",
"option1": "사람은 거짓말을 하려는 게 아니라 자기 행동을 정확히 기억하지 못하기 때문",
"option2": "인터뷰 답변은 대부분 의도적으로 꾸며낸 거짓말이기 때문",
"option3": "관찰이 인터뷰보다 시간이 덜 들고 준비가 간단하기 때문",
"option4": "사용자는 말로 설명하는 것보다 글로 쓰는 것을 더 잘하기 때문",
"answerIndex": 0,
"explanation": "섹션 3 '관찰의 힘'의 핵심입니다. 사람은 자기가 '그랬으면 하는 모습'으로 자신을 기억하기 때문에 말(인터뷰)과 행동(관찰)이 어긋나며, 그래서 리서치는 묻기와 지켜보기 두 발로 서야 한다고 설명합니다."
},
{
"courseSlug": "user-research",
"question": "설문과 인터뷰·관찰의 역할 분담에 대한 설명으로 코스 내용과 일치하는 것은 무엇인가요?",
"option1": "설문은 '왜'를 재고, 인터뷰는 '무엇'과 '얼마나'를 잰다",
"option2": "설문과 인터뷰 모두 '왜'를 알아내는 데 가장 뛰어난 도구다",
"option3": "인터뷰는 숫자를 모으는 도구이고, 설문은 이야기를 모으는 도구다",
"option4": "설문은 '무엇'과 '얼마나'를 재는 도구이고, '왜'는 인터뷰와 관찰이 잘한다",
"answerIndex": 3,
"explanation": "섹션 6 '설문의 함정'의 정리 문장 그대로입니다. 설문은 what과 how many를 재는 도구이고 why는 인터뷰와 관찰이 잘하므로, 설문에서 이상한 숫자를 발견하면 그것이 인터뷰 주제가 된다고 설명합니다."
},
{
"courseSlug": "user-research",
"question": "동료 수습생에게 \"학습 센터에서 네트워크 코스를 찾아 DNS 섹션으로 이동해 보세요\"라는 과제를 주고 5분 사용성 테스트를 진행 중입니다. 참가자가 메뉴를 헤매다 \"이거 맞아요?\"라고 물었을 때, 코스에서 배운 진행자의 가장 알맞은 대응은 무엇인가요?",
"option1": "\"위 메뉴에서 학습 센터를 누르면 돼요\"라고 방법을 바로 알려준다",
"option2": "\"평소라면 어떻게 하실 것 같아요?\"라고 되묻고 계속 지켜본다",
"option3": "참가자가 헤매지 않도록 과제를 더 쉬운 것으로 바꿔서 다시 시작한다",
"option4": "테스트를 그 자리에서 멈추고 왜 헤맸는지 인터뷰로 전환한다",
"answerIndex": 1,
"explanation": "섹션 5의 '마법의 주문'입니다. 실제 사용자 옆에는 도와줄 사람이 없으므로 도와주는 순간 테스트는 끝나며, 답을 알려주지 않으면서 상대를 존중하는 되묻기가 진행자의 필살기라고 설명합니다."
},
{
"courseSlug": "vpn-proxy",
"question": "이 코스에서 프록시(Proxy)를 한마디로 비유한 표현은 무엇인가?",
"option1": "내용물을 아무도 못 읽게 잠그는 밀봉된 강철 파이프",
"option2": "나 대신 요청과 응답을 전달해 주는 대리인(연예인의 매니저)",
"option3": "자주 쓰는 데이터를 오래 보관해 주는 창고 관리인",
"option4": "가장 빠른 경로를 골라 안내해 주는 내비게이션",
"answerIndex": 1,
"explanation": "코스 3섹션에서 프록시는 영어로 '대리인'이라는 뜻이며, 모든 연락이 매니저를 거치는 연예인 비유로 설명된다. 밀봉된 강철 파이프는 프록시가 아니라 VPN 터널의 비유다."
},
{
"courseSlug": "vpn-proxy",
"question": "VPN을 켜면 '내 위치가 바뀐 것처럼' 보이는 이유로 코스가 설명한 것은?",
"option1": "터널이 데이터 전송 경로의 속도를 바꿔 놓기 때문",
"option2": "브라우저가 위치 정보 제공을 자동으로 꺼 버리기 때문",
"option3": "목적지 서버가 터널의 출구인 VPN 서버의 IP만 보기 때문",
"option4": "DNS 서버가 내 주소를 주기적으로 새로 발급해 주기 때문",
"answerIndex": 2,
"explanation": "1섹션의 '출구 변경' 개념이다. 목적지 입장에서는 VPN 서버가 보낸 것처럼 보이고, 내 IP는 터널 입구 뒤에 숨어 있기 때문이다."
},
{
"courseSlug": "vpn-proxy",
"question": "정방향(Forward) 프록시와 리버스(Reverse) 프록시의 차이를 가장 잘 설명한 것은?",
"option1": "정방향은 요청을 보내는 쪽(클라이언트)을, 리버스는 요청을 받는 쪽(서버)을 대신한다",
"option2": "정방향은 통신을 암호화해 주지만, 리버스는 암호화를 전혀 하지 않는다",
"option3": "정방향은 응답만 전달하고, 리버스는 요청만 전달하는 구조다",
"option4": "정방향은 캐시 기능이 있지만, 리버스는 캐시를 사용할 수 없다",
"answerIndex": 0,
"explanation": "4섹션의 한 줄 정리 그대로다. 같은 '대리인'이지만 누구 편에 서 있느냐가 달라서, 정방향은 클라이언트가 숨겨지고 리버스는 서버 내부가 숨겨진다."
},
{
"courseSlug": "vpn-proxy",
"question": "공용 와이파이에서 HTTPS를 쓰더라도 여전히 새어 나갈 수 있는 정보로 코스가 꼽은 것은?",
"option1": "로그인 화면에서 입력한 비밀번호의 실제 내용",
"option2": "웹 페이지 본문 안에 들어 있는 개인 정보",
"option3": "결제 과정에서 오가는 신용카드 번호",
"option4": "어느 사이트에 접속하는지 알려 주는 도메인·DNS 질문 내용",
"answerIndex": 3,
"explanation": "5섹션에서 HTTPS 덕분에 '내용'은 암호화되지만, 어느 사이트에 가는지 같은 '행적'(도메인, DNS 질문)은 여전히 보일 수 있다고 설명한다. VPN을 켜면 행선지까지 터널 안에 숨는다."
},
{
"courseSlug": "vpn-proxy",
"question": "수습사원 A가 학습 플랫폼에서 F12로 Network 탭을 열어 응답 헤더의 'Server: Caddy'를 확인했고, Spring Boot 백엔드의 IP나 포트는 어디에서도 찾지 못했다. 이 관찰이 보여 주는 것은?",
"option1": "백엔드 서버가 꺼져 있어서 Caddy가 임시로 대신 응답한 것이다",
"option2": "브라우저가 캐시된 페이지를 보여 줘서 서버 정보가 생략된 것이다",
"option3": "리버스 프록시인 Caddy가 백엔드 등 서버 내부를 바깥에서 숨기고 있는 것이다",
"option4": "HTTPS 암호화 때문에 헤더 정보가 일부만 표시된 것이다",
"answerIndex": 2,
"explanation": "7섹션 실습 A의 핵심이다. 브라우저는 끝까지 Caddy하고만 대화하고 백엔드와 DB는 무대 뒤에 있으므로, 백엔드 주소가 안 보이는 것이 리버스 프록시가 서버 내부를 숨긴다는 증거다."
},
{
"courseSlug": "wifi-security",
"question": "코스에서 와이파이 전파를 '벽 없는 복도에서 말하기'에 비유한 이유로 가장 알맞은 것은?",
"option1": "전파는 벽을 전혀 통과하지 못해 복도에서만 쓸 수 있기 때문에",
"option2": "전파는 유선보다 속도가 느려서 데이터가 복도를 걷듯 천천히 가기 때문에",
"option3": "전파는 범위 안의 누구나 물리적으로 들을 수 있어서 암호화가 필수이기 때문에",
"option4": "전파는 공유기 한 대당 한 명만 연결할 수 있어 순서를 기다려야 하기 때문에",
"answerIndex": 2,
"explanation": "섹션 1의 핵심 비유로, 랜선은 꽂은 사람만 신호를 받지만 전파는 범위 안의 모두에게 퍼진다. 그래서 무선에서는 내용을 암호문으로 바꾸는 암호화(WPA)가 태생적으로 필수라는 결론으로 이어진다."
},
{
"courseSlug": "wifi-security",
"question": "문자로 받은 링크의 주소가 'edu.awesomedevapp.com.evil.ru'일 때, 이 도메인의 진짜 주인은 누구인가?",
"option1": "맨 앞의 edu가 주인이므로 교육기관 공식 사이트다",
"option2": "맨 뒤의 evil.ru가 진짜 주인이므로 가짜 사이트다",
"option3": "가운데의 awesomedevapp.com이 주인이므로 회사 공식 사이트다",
"option4": "도메인만으로는 주인을 알 수 없으므로 접속해서 확인해야 한다",
"answerIndex": 1,
"explanation": "섹션 4의 피싱 체크리스트 2번 — 도메인은 뒤에서부터 읽어야 하며, 마지막 두 덩어리가 진짜 주인이다. 앞부분은 공격자가 얼마든지 그럴듯하게 붙일 수 있다."
},
{
"courseSlug": "wifi-security",
"question": "WPA3가 WPA2보다 비밀번호 추측 공격에 강한 이유는 무엇인가?",
"option1": "한 번 틀릴 때마다 공유기와 다시 대면해야 해서 무한 대입이 불가능하기 때문에",
"option2": "비밀번호 길이를 최소 20자 이상으로 강제해서 추측 자체가 어렵기 때문에",
"option3": "틀린 비밀번호를 입력한 기기를 공유기가 영구적으로 차단하기 때문에",
"option4": "비밀번호를 아예 쓰지 않고 QR 코드로만 접속을 허용하기 때문에",
"answerIndex": 0,
"explanation": "섹션 2의 SAE 설명 — WPA2는 악수 과정을 녹음해 가서 집에서 무한 대입할 수 있지만, WPA3는 한 번 틀릴 때마다 공유기와 다시 대면해야 하므로 무한 대입 공격이 통하지 않는다."
},
{
"courseSlug": "wifi-security",
"question": "브라우저 주소창의 자물쇠(HTTPS) 아이콘이 보장해 주는 것으로 옳은 것은?",
"option1": "이 사이트는 피싱이 아닌 믿을 수 있는 착한 사이트라는 보증",
"option2": "이 사이트가 정부 기관의 안전 심사를 통과했다는 인증",
"option3": "이 사이트에 입력한 비밀번호는 절대 유출되지 않는다는 약속",
"option4": "브라우저와 서버 사이의 대화가 암호화되고 있다는 사실",
"answerIndex": 3,
"explanation": "섹션 3·4의 핵심 — 자물쇠는 '대화가 암호화됐다'는 뜻일 뿐 '상대가 착하다'는 보증이 아니며, 피싱 사이트도 자물쇠를 달 수 있다. 그래서 암호화 확인과 도메인 확인을 둘 다 해야 안전하다."
},
{
"courseSlug": "wifi-security",
"question": "수습사원 A가 카페에서 급히 사내 Gitea에 접속해야 한다. 'OO카페 공식 와이파이'라는 이름의 신호가 가장 센 와이파이가 잡혔을 때, 코스 내용에 따른 가장 안전한 행동은?",
"option1": "이름에 '공식'이 들어 있으므로 진짜 공유기라 믿고 바로 로그인한다",
"option2": "그 와이파이 대신 내 폰의 LTE/5G 테더링을 쓰거나 VPN을 켠 뒤 접속한다",
"option3": "신호가 가장 세다는 것은 카페 안에 있는 진짜 공유기라는 증거이므로 연결한다",
"option4": "주소창에 자물쇠만 떠 있으면 어떤 와이파이든 회사 시스템 접속도 안전하다",
"answerIndex": 1,
"explanation": "섹션 3의 중간자 공격 — SSID는 누구나 마음대로 지을 수 있고 공격자는 오히려 신호가 센 가짜 AP를 세우므로, 이름과 신호 세기는 아무 증명이 아니다. 공용 와이파이에서 회사 시스템 접속은 미루고, 급하면 테더링이나 VPN(회사 수칙 A7)을 쓰는 것이 3중 방어 습관이다."
},
{
"courseSlug": "wireframe",
"question": "코스에서 말하는 와이어프레임이 답해야 하는 질문으로 가장 알맞은 것은?",
"option1": "\"얼마나 예쁜가\" — 색과 폰트가 잘 어울리는지",
"option2": "\"얼마나 빠른가\" — 화면이 얼마나 빨리 뜨는지",
"option3": "\"무엇이 어디에 있는가\" — 위치와 크기가 맞는지",
"option4": "\"누가 쓰는가\" — 사용자가 어떤 사람인지",
"answerIndex": 2,
"explanation": "섹션 1의 한 줄 정의처럼 와이어프레임은 '무엇이 어디에 있는가'에만 답하는 뼈대 그림입니다. '얼마나 예쁜가'는 다음 단계인 디자인 시안의 질문이에요."
},
{
"courseSlug": "wireframe",
"question": "와이어프레임이 3단계로 진화하는 올바른 순서는?",
"option1": "회색 박스 → 손그림 → 디자인 시안",
"option2": "손그림 → 회색 박스 → 디자인 시안",
"option3": "디자인 시안 → 회색 박스 → 손그림",
"option4": "손그림 → 디자인 시안 → 회색 박스",
"answerIndex": 1,
"explanation": "섹션 3에서 배운 순서는 손그림(Lo-Fi) → 회색 박스(Mid-Fi) → 디자인 시안(Hi-Fi)입니다. 흐릿한 사진의 초점이 점점 맞아 가듯 단계마다 해상도를 올려요."
},
{
"courseSlug": "wireframe",
"question": "코스에서 와이어프레임을 '일부러 대충' 그리라고 하는 가장 큰 이유는?",
"option1": "버리는 비용을 낮춰 여러 아이디어를 싸고 빠르게 비교하기 위해",
"option2": "그림 실력이 없는 사람도 부담 없이 참여하게 하기 위해",
"option3": "개발자가 코드를 더 빨리 짤 수 있도록 시간을 아끼기 위해",
"option4": "디자인 도구 사용법을 몰라도 회의를 진행하게 하기 위해",
"answerIndex": 0,
"explanation": "섹션 2의 핵심은 '빨리 버리기'입니다. 손그림 1장은 10분이라 버려도 안 아깝지만, 공들인 시안은 매몰 비용의 함정 때문에 갈아엎자는 말을 꺼내기 어려워요."
},
{
"courseSlug": "wireframe",
"question": "플로우를 그릴 때 '해피 패스의 함정'을 피하려면 무엇까지 그려야 한다고 했나요?",
"option1": "모든 화면의 색상과 폰트 조합까지",
"option2": "화면마다 사용할 사진과 아이콘까지",
"option3": "각 화면을 만들 개발 일정표까지",
"option4": "에러·빈 화면·로딩 같은 예외 화면까지",
"answerIndex": 3,
"explanation": "섹션 5에서 모든 게 잘 풀리는 해피 패스만 그리지 말라고 경고합니다. 실제 사용자는 오타를 내고 검색 결과 0개를 만나므로, 에러·빈 화면·로딩까지 그려야 진짜 설계예요."
},
{
"courseSlug": "wireframe",
"question": "7주차 종합 프로젝트에서 아이디어 회의가 끝나자마자 팀원 A가 React 컴포넌트부터 만들기 시작했습니다. 코스의 가르침에 따르면 팀이 밟아야 할 올바른 순서는?",
"option1": "피그마 시안 → 손그림 → 플로우 → React 코드",
"option2": "플로우 → 피그마 회색 박스 → 손그림 → React 코드",
"option3": "손그림 → 플로우 → 피그마 회색 박스 → React 코드",
"option4": "피그마 회색 박스 → React 코드 → 손그림 → 플로우",
"answerIndex": 2,
"explanation": "섹션 8의 순서대로 손그림으로 후보를 쏟아내고, 플로우로 구멍을 찾고, 피그마 회색 박스로 배치를 확정한 다음에야 React로 옮깁니다. '그리기는 분 단위, 코딩은 일 단위'니까 싼 것부터예요."
},
{
"courseSlug": "app-landscape",
"question": "네이티브 앱을 만들 때 안드로이드와 iOS의 대표 언어를 옳게 짝지은 것은?",
"option1": "안드로이드 = Kotlin, iOS = Swift",
"option2": "안드로이드 = Swift, iOS = Kotlin",
"option3": "안드로이드 = Dart, iOS = JavaScript",
"option4": "안드로이드 = HTML, iOS = Java",
"answerIndex": 0,
"explanation": "3번 섹션 — 네이티브는 안드로이드가 Kotlin, iOS가 Swift가 대표 언어다."
},
{
"courseSlug": "app-landscape",
"question": "본문이 든, React Native가 웹 React 개발자에게 특히 익숙한 이유는?",
"option1": "언어가 Dart로 완전히 바뀌기 때문",
"option2": "useState·props·JSX 같은 사고방식은 그대로이고 주로 태그 이름(<div>→<View>)만 바뀌기 때문",
"option3": "브라우저 안에서 그대로 실행되기 때문",
"option4": "앱스토어 등록이 전혀 필요 없기 때문",
"answerIndex": 1,
"explanation": "4번 섹션 — 컴포넌트·props·state·JSX는 그대로 쓰이고 <div>→<View>, <p>→<Text>처럼 태그 이름 위주로만 달라진다."
},
{
"courseSlug": "app-landscape",
"question": "PWA(Progressive Web App)에 대한 설명으로 옳은 것은?",
"option1": "Kotlin으로 작성하는 네이티브 안드로이드 앱이다",
"option2": "코드 한 벌로 안드로이드·iOS의 진짜 네이티브 위젯을 그린다",
"option3": "manifest.json과 service worker로 설치·오프라인이 되지만 앱스토어에는 정식 등록되지 않는다",
"option4": "맥(Xcode)에서만 빌드할 수 있다",
"answerIndex": 2,
"explanation": "5번 섹션 — PWA는 manifest.json과 service worker로 설치·오프라인을 지원하되 앱스토어 정식 등록은 되지 않는다."
},
{
"courseSlug": "app-landscape",
"question": "본문의 선택 기준표에서 '안드로이드·iOS 둘 다 필요하고 인력·시간은 빠듯하며 팀이 React/JS에 능숙'할 때 유력한 길은?",
"option1": "네이티브",
"option2": "크로스플랫폼(React Native)",
"option3": "iOS 전용 Swift 개발",
"option4": "순수 정적 HTML 사이트",
"answerIndex": 1,
"explanation": "6번 섹션 처방전 — 두 플랫폼 + 빠듯한 자원 + React 능숙이면 크로스플랫폼(React Native)이 유력하다."
},
{
"courseSlug": "app-landscape",
"question": "우리 회사 관점에서 앱으로 확장할 때 본문이 강조한 핵심 사실은?",
"option1": "앱으로 가려면 Spring 백엔드를 처음부터 다시 만들어야 한다",
"option2": "어느 길을 가든 백엔드(Spring API)는 그대로 재사용되고, 앱은 같은 서버에 요청하는 또 하나의 화면이다",
"option3": "앱은 HTTP가 아니라 완전히 다른 통신 방식을 쓴다",
"option4": "네이티브로만 우리 서버에 접속할 수 있다",
"answerIndex": 1,
"explanation": "7번 섹션 — 앱도 같은 Spring API에 HTTP 요청을 보내는 또 하나의 화면일 뿐이라 백엔드는 그대로 재사용된다."
},
{
"courseSlug": "android-basics",
"question": "안드로이드에서 'Activity'는 무엇을 가리키나요?",
"option1": "앱의 배경에서 조용히 도는 작업(예: 음악 재생)",
"option2": "화면 한 장(로그인 화면, 목록 화면 등)",
"option3": "앱끼리 데이터를 주고받는 공유 통로",
"option4": "배터리 부족 같은 시스템 알림을 받는 부품",
"answerIndex": 1,
"explanation": "본문 2섹션에서 Activity는 '화면 한 장'으로 정의했고, 배경 작업은 Service, 데이터 공유는 ContentProvider, 알림 수신은 BroadcastReceiver다."
},
{
"courseSlug": "android-basics",
"question": "한 화면에서 다른 화면으로 이동하며 데이터까지 넘길 때 쓰는 것은?",
"option1": "Gradle",
"option2": "Logcat",
"option3": "Intent",
"option4": "AndroidManifest",
"answerIndex": 2,
"explanation": "2섹션에서 Intent를 '어디로 갈지 + 무엇을 들고 갈지 담은 쪽지'로 설명했고 startActivity로 화면을 전환한다."
},
{
"courseSlug": "android-basics",
"question": "실행 중인 앱에서 폰을 가로로 회전하면 액티비티에 기본적으로 무슨 일이 일어나나요?",
"option1": "아무 일도 없고 변수 값이 그대로 유지된다",
"option2": "onPause만 한 번 호출되고 끝난다",
"option3": "onDestroy 후 onCreate로 액티비티가 통째로 다시 만들어진다",
"option4": "앱이 자동으로 강제 종료된다",
"answerIndex": 2,
"explanation": "3섹션 경고대로 회전 시 액티비티가 재생성되므로 변수에만 담아 둔 값은 사라진다."
},
{
"courseSlug": "android-basics",
"question": "Jetpack Compose가 우리 React와 가장 닮은 점은?",
"option1": "XML 파일에 화면 구조를 미리 적어 둔다",
"option2": "상태가 바뀌면 화면이 자동으로 다시 그려지는 선언형이다",
"option3": "findViewById로 요소를 찾아 직접 손으로 바꾼다",
"option4": "자바스크립트로만 작성해야 한다",
"answerIndex": 1,
"explanation": "4섹션에서 Compose는 '화면 = f(상태)' 선언형이라 상태 변경 시 재구성되어 React의 재렌더와 발상이 같다고 설명했다."
},
{
"courseSlug": "android-basics",
"question": "카메라 같은 '위험 권한'은 안드로이드 6.0(API 23) 이후 어떻게 얻나요?",
"option1": "AndroidManifest에 선언만 하면 설치 시 자동으로 허용된다",
"option2": "앱 실행 중에 사용자에게 팝업으로 허락을 요청해야 한다",
"option3": "구글 심사팀이 검토해 대신 켜 준다",
"option4": "위험 권한은 코드로는 요청할 수 없다",
"answerIndex": 1,
"explanation": "6섹션대로 INTERNET 같은 일반 권한은 설치 시 자동 허용되지만 카메라·위치 등 위험 권한은 실행 중 런타임 요청이 필요하다."
},
{
"courseSlug": "kotlin-intro",
"question": "Kotlin에서 한 번 값을 담으면 다시 대입할 수 없어, JS의 const와 대응되는 변수 키워드는?",
"option1": "val",
"option2": "var",
"option3": "let",
"option4": "def",
"answerIndex": 0,
"explanation": "val은 value(값 고정)로 재대입이 불가능해 JS의 const와 짝지어진다. var가 재대입 가능한 let 쪽이다."
},
{
"courseSlug": "kotlin-intro",
"question": "null일 수 있는 값 maybe에 대해 maybe?.length를 실행했는데 maybe가 null이면 결과는?",
"option1": "앱이 NPE로 크래시된다",
"option2": "그냥 null이 반환된다(크래시 없음)",
"option3": "무조건 0이 반환된다",
"option4": "컴파일 자체가 안 된다",
"answerIndex": 1,
"explanation": "?.(안전 호출)은 앞이 null이면 크래시 없이 통째로 null을 반환한다. 크래시가 나는 건 !!다."
},
{
"courseSlug": "kotlin-intro",
"question": "maybe ?: \"손님\" 처럼 쓰이는 ?:(엘비스) 연산자의 역할은?",
"option1": "왼쪽이 null이면 오른쪽 기본값으로 대체한다",
"option2": "무조건 즉시 크래시를 낸다",
"option3": "두 숫자를 더한다",
"option4": "타입을 String으로 강제 변환한다",
"answerIndex": 0,
"explanation": "엘비스 연산자 ?:는 왼쪽 값이 null일 때 오른쪽 기본값으로 대체해 준다."
},
{
"courseSlug": "kotlin-intro",
"question": "일반 클래스 앞에 data를 붙여 data class로 만들 때, 본문 기준 '공짜로 따라오는 것'이 아닌 것은?",
"option1": "equals(값 비교)",
"option2": "toString(보기 좋은 출력)",
"option3": "copy(하나만 바꿔 복제)",
"option4": "서버 API 자동 호출",
"answerIndex": 3,
"explanation": "data class는 equals·toString·copy를 자동 생성해 주지만 네트워크 호출 같은 기능은 제공하지 않는다."
},
{
"courseSlug": "kotlin-intro",
"question": "본문에서 Kotlin의 when이 JS의 switch보다 나은 점으로 든 것은?",
"option1": "각 갈래마다 break를 반드시 붙여야 한다",
"option2": "break가 필요 없고, 값을 돌려주는 식(expression)으로도 쓸 수 있다",
"option3": "숫자만 비교할 수 있다",
"option4": "else 갈래를 쓸 수 없다",
"answerIndex": 1,
"explanation": "when은 break 없이 맞는 갈래 하나만 실행하고, 결과를 바로 변수에 담는 식으로도 쓸 수 있다."
},
{
"courseSlug": "ios-basics",
"question": "iOS를 '담장 친 정원(walled garden)'이라 부르는 이유로 본문 설명에 가장 맞는 것은?",
"option1": "애플이 기기·OS·앱 스토어·칩까지 한 회사가 직접 만들어 통제하기 때문",
"option2": "앱을 무료로만 배포할 수 있기 때문",
"option3": "안드로이드보다 기기 종류가 훨씬 많기 때문",
"option4": "개발에 윈도우 PC만 쓸 수 있기 때문",
"answerIndex": 0,
"explanation": "애플은 기기·OS·스토어·칩을 수직 통합해 규칙을 통제하므로 '담장 친 정원'이라 부른다."
},
{
"courseSlug": "ios-basics",
"question": "React의 useState와 가장 비슷한 사고방식을 가진 iOS 기술은?",
"option1": "UIKit에서 라벨을 직접 찾아 글자를 바꾸는 명령형 코드",
"option2": "SwiftUI의 @State — 상태만 바꾸면 화면이 자동으로 다시 그려짐",
"option3": "Info.plist의 권한 이유 문구",
"option4": "Xcode의 시뮬레이터",
"answerIndex": 1,
"explanation": "SwiftUI의 @State는 상태를 바꾸면 body가 재렌더되어 '화면=상태의 함수'인 useState와 판박이다."
},
{
"courseSlug": "ios-basics",
"question": "본문은 iOS의 '뷰 계층(view hierarchy)'을 무엇과 같은 뼈대라고 설명했는가?",
"option1": "데이터베이스 테이블",
"option2": "브라우저의 DOM 트리이자 React의 컴포넌트 트리",
"option3": "네트워크 패킷의 흐름",
"option4": "파일 시스템의 접근 권한",
"answerIndex": 1,
"explanation": "화면 위 모든 뷰가 부모-자식 트리로 쌓이는 구조는 DOM 트리·컴포넌트 트리와 같은 뼈대라고 설명했다."
},
{
"courseSlug": "ios-basics",
"question": "iOS 개발 환경에 대한 본문 설명과 일치하는 것은?",
"option1": "Xcode는 윈도우·맥·리눅스 모두에서 실행된다",
"option2": "Xcode는 macOS에서만 실행되어 개발용 맥이 사실상 필수다",
"option3": "시뮬레이터로 카메라 하드웨어까지 완벽히 테스트된다",
"option4": "App Store 정식 출시는 완전 무료다",
"answerIndex": 1,
"explanation": "Xcode가 macOS 전용이라 개발용 맥이 사실상 필수이며, 윈도우만으로는 공식 빌드가 안 된다고 했다."
},
{
"courseSlug": "ios-basics",
"question": "iOS에서 카메라 권한을 쓰는데 Info.plist에 이유 문구(NSCameraUsageDescription)를 적지 않으면?",
"option1": "시스템이 자동으로 권한을 허용한다",
"option2": "심사에서 경고만 받고 정상 동작한다",
"option3": "앱이 그 자리에서 죽는다(크래시)",
"option4": "안드로이드에서만 문제가 된다",
"answerIndex": 2,
"explanation": "iOS는 이유 문구가 없으면 해당 자원을 쓰는 순간 앱이 그대로 크래시한다고 본문이 강조했다."
},
{
"courseSlug": "swift-intro",
"question": "Swift에서 한 번 정하면 다시 값을 넣을 수 없는(상수) 키워드는 무엇인가요?",
"option1": "let",
"option2": "var",
"option3": "const",
"option4": "val",
"answerIndex": 0,
"explanation": "let은 상수라 재할당이 불가하고 var가 바뀔 수 있는 변수입니다(const·val은 Swift 키워드가 아님)."
},
{
"courseSlug": "swift-intro",
"question": "옵셔널 타입 String? 이 뜻하는 것으로 가장 정확한 것은?",
"option1": "언제나 문자열이 들어 있다",
"option2": "String 이거나 nil 일 수 있다",
"option3": "문자열들의 배열이다",
"option4": "자동으로 숫자로 바뀐다",
"answerIndex": 1,
"explanation": "타입 뒤 물음표(?)는 '값이 있거나 nil일 수 있음'을 타입에 표시한 옵셔널입니다."
},
{
"courseSlug": "swift-intro",
"question": "옵셔널이 nil일 때 대신 쓸 기본값을 지정하는, JS에도 있는 그 연산자는?",
"option1": "?. (옵셔널 체이닝)",
"option2": "! (강제 언래핑)",
"option3": "?? (nil 병합)",
"option4": "-> (반환 타입)",
"answerIndex": 2,
"explanation": "??는 nil 병합 연산자로 값이 없으면 오른쪽 기본값을 씁니다. !는 위험한 강제 언래핑, ?.는 안전한 접근입니다."
},
{
"courseSlug": "swift-intro",
"question": "struct(값 타입)에서 var s2 = s1 로 복사한 뒤 s2.x를 99로 바꾸면 s1.x는 어떻게 되나요?",
"option1": "함께 99로 바뀐다",
"option2": "그대로 1이다(복사되어 서로 남남)",
"option3": "컴파일 에러가 난다",
"option4": "nil이 된다",
"answerIndex": 1,
"explanation": "struct는 대입할 때 복사본이 생겨 s1과 s2가 독립적이므로 s1.x는 원래 값 그대로입니다(공유되는 class와 반대)."
},
{
"courseSlug": "swift-intro",
"question": "Swift의 protocol은 TypeScript나 Java의 무엇과 같은 역할을 하나요?",
"option1": "class",
"option2": "struct",
"option3": "interface",
"option4": "enum",
"answerIndex": 2,
"explanation": "프로토콜은 '갖춰야 할 프로퍼티·기능'을 정하는 계약으로, interface와 같은 자리에 대응합니다."
},
{
"courseSlug": "react-native",
"question": "React Native가 웹뷰(WebView) 방식과 근본적으로 다른 점은 무엇인가요?",
"option1": "자바스크립트 코드가 iOS·안드로이드의 진짜 네이티브 UI 위젯으로 렌더링된다",
"option2": "웹사이트를 앱 아이콘으로 감싸 앱 속 브라우저 안에서 보여 준다",
"option3": "HTML 파일을 그대로 폰 화면에 띄운다",
"option4": "앱 안에 작은 크롬 브라우저를 넣어 웹페이지를 연다",
"answerIndex": 0,
"explanation": "RN은 웹을 포장하는 WebView가 아니라, JS로 쓴 <Text>가 iOS의 UILabel, 안드로이드의 TextView 같은 진짜 네이티브 위젯으로 그려진다(섹션 1)."
},
{
"courseSlug": "react-native",
"question": "웹의 <div>에 대응하는 React Native 컴포넌트는 무엇인가요?",
"option1": "<Text>",
"option2": "<View>",
"option3": "<Image>",
"option4": "<Box>",
"answerIndex": 1,
"explanation": "대응표(섹션 3)에서 레이아웃 상자인 <div>는 RN의 <View>에 대응한다. <Text>는 <span>/<p> 글자에, <Image>는 <img>에 대응한다."
},
{
"courseSlug": "react-native",
"question": "React Native에서 화면에 글자를 표시할 때 반드시 지켜야 하는 규칙은?",
"option1": "모든 글자는 반드시 <Text> 컴포넌트 안에 넣어야 한다",
"option2": "모든 글자는 <View> 안에 맨몸으로 직접 써야 한다",
"option3": "글자는 className 속성으로만 표시한다",
"option4": "글자는 웹처럼 <p> 태그로 감싸야 한다",
"answerIndex": 0,
"explanation": "RN에서는 글자를 그리는 부품과 레이아웃 상자가 다르기 때문에 모든 글자는 <Text> 안에 있어야 하며, <View>에 맨몸으로 넣으면 에러가 난다(섹션 3)."
},
{
"courseSlug": "react-native",
"question": "React Native의 StyleSheet가 웹 CSS와 다른 점으로 옳은 것은?",
"option1": "CSS처럼 부모의 스타일이 자식에게 그대로 상속(캐스케이드)된다",
"option2": "크기 값에 반드시 px 단위를 붙여야 한다",
"option3": "flexDirection의 기본값이 웹(row)과 달리 column이다",
"option4": "속성 이름을 background-color처럼 하이픈으로 쓴다",
"answerIndex": 2,
"explanation": "RN은 flexDirection 기본값이 column이다. 반대로 속성은 camelCase(backgroundColor), 숫자엔 단위 없음, 캐스케이드 없음이라 나머지 보기는 틀리다(섹션 4)."
},
{
"courseSlug": "react-native",
"question": "Expo Go 앱의 역할로 맞는 것은?",
"option1": "앱을 애플·구글 스토어에 자동으로 심사·출시해 준다",
"option2": "자바 코드를 자바스크립트로 번역해 준다",
"option3": "Spring Boot 서버를 대신 실행해 준다",
"option4": "터미널에 뜬 QR코드를 스캔하면 방금 만든 앱을 내 진짜 폰에서 바로 실행해 준다",
"answerIndex": 3,
"explanation": "Expo Go는 QR코드를 스캔해 개발 중인 앱을 실제 폰에서 즉시 실행해 주는 앱이다. 스토어 출시나 코드 번역, 서버 실행과는 무관하다(섹션 5)."
},
{
"courseSlug": "flutter",
"question": "Flutter가 React Native와 구별되는 가장 결정적인 차이는 무엇인가?",
"option1": "OS가 제공하는 순정 네이티브 부품을 빌려다 화면을 배치한다",
"option2": "자체 렌더링 엔진이 버튼 모양까지 픽셀 단위로 직접 그린다",
"option3": "자바스크립트로 UI를 작성한다",
"option4": "서버 없이도 데이터를 저장할 수 있다",
"answerIndex": 1,
"explanation": "본문 섹션 1·2의 핵심 — RN은 OS 부품을 빌리지만 Flutter는 자체 엔진(Impeller/Skia)이 화면을 직접 그린다."
},
{
"courseSlug": "flutter",
"question": "Dart의 널 안전성(null safety)에 대한 설명으로 옳은 것은?",
"option1": "모든 변수가 기본적으로 null이 될 수 있다",
"option2": "타입에 ?를 붙인 값만 null이 될 수 있다",
"option3": "final로 선언한 값만 null이 될 수 있다",
"option4": "Dart에는 null이라는 개념이 아예 없다",
"answerIndex": 1,
"explanation": "섹션 3에서 설명하듯 ?를 붙인 타입만 null 허용, 나머지는 컴파일러가 null이 올 수 없음을 보증한다."
},
{
"courseSlug": "flutter",
"question": "Flutter에서 '모든 게 위젯'이라는 말이 뜻하는 것으로 가장 알맞은 것은?",
"option1": "버튼·글자뿐 아니라 여백·정렬 같은 레이아웃까지 전부 위젯이다",
"option2": "위젯은 오직 버튼만 가리키는 용어다",
"option3": "위젯은 HTML 태그를 부르는 다른 이름일 뿐이다",
"option4": "위젯은 서버에서만 만들 수 있다",
"answerIndex": 0,
"explanation": "섹션 4의 핵심 — Flutter는 버튼·글자는 물론 SizedBox 같은 여백·레이아웃까지 모두 위젯으로 다룬다."
},
{
"courseSlug": "flutter",
"question": "StatefulWidget에서 count 값을 바꿨는데 화면이 다시 그려지게 하려면?",
"option1": "count 값을 직접 바꾸기만 하면 자동으로 갱신된다",
"option2": "변경을 setState()로 감싸야 build()가 다시 불린다",
"option3": "앱을 껐다 켜야 반영된다",
"option4": "StatelessWidget으로 바꿔야 한다",
"answerIndex": 1,
"explanation": "섹션 5 — React의 setCount처럼, 상태 변경을 setState()로 감싸야 Flutter가 build()를 다시 호출한다."
},
{
"courseSlug": "flutter",
"question": "우리 상황에서 앱을 React Native 대신 Flutter로 만든다면 백엔드는 어떻게 되나?",
"option1": "Dart로 서버를 새로 작성해야 한다",
"option2": "기존 Spring API를 그대로 쓰고, 화면을 그리는 도구만 바뀐다",
"option3": "서버도 Flutter로 다시 만들어야 한다",
"option4": "서버가 아예 필요 없어진다",
"answerIndex": 1,
"explanation": "섹션 7 — 앱 도구 선택은 '화면을 무엇으로 그릴까'의 문제일 뿐, 데이터는 여전히 우리 Spring API에 요청한다."
},
{
"courseSlug": "app-navigation",
"question": "앱 내비게이션에서 '지금 화면에 보이는 것'은 무엇으로 결정될까요?",
"option1": "스택(카드 더미)에 쌓인 것 중 맨 위 한 장",
"option2": "브라우저 주소창(URL)에 적힌 경로",
"option3": "드로어에 숨겨진 첫 번째 메뉴 항목",
"option4": "데이터베이스에 저장된 마지막 로그",
"answerIndex": 0,
"explanation": "앱엔 주소창이 없고, 화면을 push로 쌓는 스택의 맨 위 카드가 곧 지금 화면이라고 본문에서 설명했다."
},
{
"courseSlug": "app-navigation",
"question": "'바깥은 탭, 각 탭 안은 스택'인 앱에서 검색 탭으로 상세에 들어갔다가 홈 탭에 갔다 다시 검색 탭으로 오면?",
"option1": "항상 앱이 종료된다",
"option2": "아까 보던 상세 화면이 그대로 유지된다",
"option3": "검색 탭이 홈 화면으로 바뀐다",
"option4": "모든 탭의 스택이 초기화된다",
"answerIndex": 1,
"explanation": "각 탭이 자기 스택을 따로 기억하므로, 탭을 오가도 이전에 보던 상세 화면이 보존된다고 본문에서 설명했다."
},
{
"courseSlug": "app-navigation",
"question": "iOS에서 이전 화면으로 뒤로 가는 대표적인 방법은?",
"option1": "화면 왼쪽 가장자리에서 오른쪽으로 쓸어넘기거나 좌상단 '뒤로'를 누른다",
"option2": "화면 아래 하드웨어 뒤로가기 버튼을 누른다",
"option3": "볼륨 버튼을 두 번 누른다",
"option4": "앱을 강제 종료했다가 다시 켠다",
"answerIndex": 0,
"explanation": "iOS는 하드웨어 뒤로가기 버튼이 없어 swipe-back 제스처나 좌상단 뒤로 버튼을 쓴다고 본문에서 설명했다."
},
{
"courseSlug": "app-navigation",
"question": "화면 A에서 B로 데이터를 넘길 때 본문이 권장한 방식은?",
"option1": "큰 데이터 객체를 통째로 params에 실어 넘긴다",
"option2": "id 같은 작은 열쇠만 넘기고 상세 데이터는 그 화면이 다시 조회한다",
"option3": "전역 변수에 넣고 아무 값도 넘기지 않는다",
"option4": "비밀번호까지 URL에 담아 넘긴다",
"answerIndex": 1,
"explanation": "params엔 id 같은 작은 값만 담고 큰 데이터는 도착 화면이 id로 재조회해야 뒤로가기·딥링크 진입에도 깨지지 않는다고 본문에서 강조했다."
},
{
"courseSlug": "app-navigation",
"question": "React Native에서 사실상 표준으로 쓰이는 내비게이션 라이브러리는?",
"option1": "React Navigation",
"option2": "react-router-dom",
"option3": "go_router",
"option4": "Redux",
"answerIndex": 0,
"explanation": "본문에 따르면 RN은 React Navigation이 표준이며, react-router-dom은 웹, go_router는 Flutter 쪽이다."
},
{
"courseSlug": "app-state-data",
"question": "다크모드 on/off 설정처럼 '앱을 껐다 켜도 이 기기에 남아야 하지만, 다른 기기와 공유할 필요는 없는' 값은 데이터의 어느 층에 두어야 할까요?",
"option1": "화면 상태 (useState)",
"option2": "기기 로컬 저장 (AsyncStorage)",
"option3": "서버 (Spring + PostgreSQL)",
"option4": "어느 층에도 저장하지 않는다",
"answerIndex": 1,
"explanation": "앱 재시작에도 남아야 하지만(→화면 상태 아님) 다른 기기와 공유할 필요는 없으므로(→서버 아님) 가운데 층인 기기 로컬 저장이 맞다."
},
{
"courseSlug": "app-state-data",
"question": "검색창에 입력 중인 글자나 지금 열린 탭처럼 '화면을 나가면 사라져도 되는' 값은 앱에서 무엇으로 관리하나요?",
"option1": "AsyncStorage",
"option2": "SQLite",
"option3": "useState",
"option4": "iOS Keychain",
"answerIndex": 2,
"explanation": "화면 상태는 웹 React와 100% 동일하게 useState로 관리하며, 앱이라고 특별한 도구가 필요하지 않다."
},
{
"courseSlug": "app-state-data",
"question": "로그인 토큰을 AsyncStorage에 그대로 저장하면 안 되는 이유와 올바른 대안은?",
"option1": "용량이 작아서 — 대신 SQLite에 저장한다",
"option2": "암호화되지 않은 평문이라 유출 위험 — iOS Keychain / Android Keystore 같은 보안 저장소에 저장한다",
"option3": "속도가 느려서 — 대신 서버에만 저장한다",
"option4": "문제없다 — 토큰은 어디에 저장해도 안전하다",
"answerIndex": 1,
"explanation": "AsyncStorage와 SQLite는 기본적으로 평문이라, 토큰 같은 민감정보는 OS 보안 저장소(Keychain/Keystore)에 넣어야 한다."
},
{
"courseSlug": "app-state-data",
"question": "우리 웹 프론트는 쿠키(withCredentials)로 로그인을 유지합니다. 앱(React Native)에서 서버 API를 호출할 때 로그인을 유지하는 흔한 방식은?",
"option1": "쿠키가 자동으로 붙으므로 아무것도 하지 않아도 된다",
"option2": "토큰을 Authorization 헤더에 직접 실어 보낸다",
"option3": "매 요청마다 비밀번호를 body에 담아 보낸다",
"option4": "서버가 접속 IP로 사용자를 알아본다",
"answerIndex": 1,
"explanation": "앱은 브라우저가 아니라 쿠키 자동첨부가 없으므로, 보안 저장소에 둔 토큰을 요청마다 Authorization 헤더에 직접 넣는다."
},
{
"courseSlug": "app-state-data",
"question": "오프라인에서 '좋아요'를 눌렀을 때, 서버 응답을 기다리지 않고 화면부터 먼저 바꾼 뒤 요청은 대기 큐에 쌓아 재연결 시 보내는 방식을 무엇이라 하나요?",
"option1": "비관적 UI",
"option2": "낙관적 UI (optimistic update)",
"option3": "강제 새로고침",
"option4": "서버 사이드 렌더링",
"answerIndex": 1,
"explanation": "응답을 기다리지 않고 '어차피 성공하겠지' 하고 화면부터 바꾸는 것이 낙관적 UI이며, 실패하면 되돌리고 요청은 큐에 쌓아 재연결 시 동기화한다."
},
{
"courseSlug": "pwa",
"question": "PWA를 '설치되는 앱'으로 만들어 주는 세 가지 핵심 재료가 아닌 것은?",
"option1": "HTTPS(안전한 연결)",
"option2": "웹 앱 매니페스트",
"option3": "서비스워커",
"option4": "앱스토어 심사 통과",
"answerIndex": 3,
"explanation": "본문에서 재료는 HTTPS·매니페스트·서비스워커 셋이며, PWA는 스토어 심사 없이 배포하는 게 장점이다."
},
{
"courseSlug": "pwa",
"question": "매니페스트의 display를 \"standalone\"으로 설정하면 어떤 일이 일어나는가?",
"option1": "주소창·탭 없이 전체화면으로 앱처럼 열린다",
"option2": "오프라인에서 무조건 동작한다",
"option3": "푸시 알림이 자동으로 켜진다",
"option4": "앱스토어에 자동 등록된다",
"answerIndex": 0,
"explanation": "섹션 3에서 display: standalone은 주소창을 숨기고 전체화면으로 열어 겉보기엔 네이티브 앱처럼 보이게 한다고 설명했다."
},
{
"courseSlug": "pwa",
"question": "서비스워커 덕분에 인터넷이 끊겨도 화면이 뜰 수 있는 이유는?",
"option1": "서버가 항상 켜져 있어서",
"option2": "요청을 가로채 캐시에 있으면 캐시로 응답해서",
"option3": "매니페스트가 데이터를 저장해서",
"option4": "브라우저가 HTML을 통째로 외워서",
"answerIndex": 1,
"explanation": "섹션 4에서 서비스워커는 요청을 가로채 캐시에 있으면 캐시(hit)로 응답하므로, 네트워크가 없어도 화면을 그려 낸다."
},
{
"courseSlug": "pwa",
"question": "웹 푸시 알림에 대한 설명으로 옳은 것은?",
"option1": "사용자 허락 없이도 서버가 보낼 수 있다",
"option2": "사용자가 권한을 거절하면 알림을 보낼 방법이 없다",
"option3": "서비스워커 없이 앱이 꺼진 상태에서 알림을 띄운다",
"option4": "매니페스트만 있으면 곧바로 발송된다",
"answerIndex": 1,
"explanation": "섹션 5에서 requestPermission은 '물어보는' 것이라, 사용자가 거절하면 알림을 보낼 방법이 아예 없다고 강조했다."
},
{
"courseSlug": "pwa",
"question": "iOS(아이폰)에서 PWA 웹 푸시에 대한 설명으로 옳은 것은?",
"option1": "사파리 탭으로 열어 두기만 해도 푸시가 온다",
"option2": "iOS는 웹 푸시를 전혀 지원하지 않는다",
"option3": "iOS 16.4부터, 홈 화면에 설치된 PWA에서만 푸시가 동작한다",
"option4": "웹 기능은 iOS가 안드로이드보다 더 많이 열려 있다",
"answerIndex": 2,
"explanation": "섹션 6에서 iOS는 16.4(2023)부터 웹 푸시를 지원하되 홈 화면에 설치된 PWA에서만 작동한다고 정확히 다뤘다."
},
{
"courseSlug": "app-security",
"question": "이 강좌가 말하는, 앱 보안이 웹 보안과 근본적으로 다른 한 가지 이유는?",
"option1": "앱은 접속할 때마다 서버가 화면 코드를 새로 내려 준다",
"option2": "앱 파일(APK/IPA)이 사용자·공격자의 기기에 설치돼 남아 뜯어볼 수 있다",
"option3": "앱은 HTTPS를 사용할 수 없다",
"option4": "앱은 아무 권한도 필요로 하지 않는다",
"answerIndex": 1,
"explanation": "코드가 기기에 설치돼 남아 디컴파일·변조가 가능하므로 '클라이언트를 믿지 마라'가 제1원칙이 된다."
},
{
"courseSlug": "app-security",
"question": "앱이 카메라·위치 권한을 다룰 때 지켜야 할, 방화벽 코스의 '필요한 포트만 연다'와 같은 원칙은?",
"option1": "최대 권한 — 미리 다 받아 둔다",
"option2": "권한은 설치 때 한 번에 몰아서 받는다",
"option3": "최소 권한 — 기능이 실제로 필요로 하는 것만 요청한다",
"option4": "권한은 서버가 대신 받아 준다",
"answerIndex": 2,
"explanation": "AWS 보안그룹의 '필요한 포트만 열기'와 같은 최소 권한이 사용자 신뢰와 스토어 심사에서 유리하다."
},
{
"courseSlug": "app-security",
"question": "앱에서 로그인 토큰을 저장하는 안전한 방법은?",
"option1": "SharedPreferences/UserDefaults에 평문으로 저장한다",
"option2": "앱 코드에 상수로 하드코딩한다",
"option3": "iOS Keychain / 안드로이드 Keystore 같은 OS 금고에 저장한다",
"option4": "디버그 로그 파일에 남겨 둔다",
"answerIndex": 2,
"explanation": "하드웨어로 보호되는 Keychain/Keystore에 맡겨야 하며, 평문 저장이나 하드코딩은 그대로 읽혀 금지된다."
},
{
"courseSlug": "app-security",
"question": "일반 HTTPS를 넘어, 가짜 CA를 이용한 중간자(MITM) 공격까지 막으려고 '우리 서버의 바로 그 인증서'만 믿도록 앱에 지문을 새기는 기법은?",
"option1": "인증서 고정(Certificate Pinning)",
"option2": "평문 전송(cleartext)",
"option3": "포트포워딩",
"option4": "캐싱",
"answerIndex": 0,
"explanation": "인증서 고정은 정해진 인증서만 신뢰해 MITM까지 막지만, 서버 인증서 갱신 시 앱도 함께 업데이트해야 한다."
},
{
"courseSlug": "app-security",
"question": "\"관리자 메뉴를 앱 화면에서 숨겼으니 안전하다\"는 생각이 위험한 이유로 이 강좌가 강조한 원칙은?",
"option1": "앱은 절대 뚫리지 않는다",
"option2": "화면 숨김은 UX일 뿐이고 진짜 권한 검사는 서버가 다시 해야 한다",
"option3": "스토어 심사가 모든 위협을 막아 준다",
"option4": "권한을 많이 받을수록 안전하다",
"answerIndex": 1,
"explanation": "설치된 앱은 뜯어볼 수 있어 숨긴 화면도 드러나므로, 진짜 검사는 서버가 담당해야 한다(App.jsx 주석과 동일)."
},
{
"courseSlug": "app-store-deploy",
"question": "배포 전 준비물 중, 앱이 사용자 데이터를 조금이라도 수집한다면 스토어에 반드시 등록해야 하는 것은?",
"option1": "공개 URL 형태의 개인정보 처리방침",
"option2": "512×512 앱 아이콘 한 장이면 충분",
"option3": "유료 개발자 등급 승급",
"option4": "별도의 서버 TLS 인증서",
"answerIndex": 0,
"explanation": "로그인·광고ID·로그 등 데이터를 조금이라도 모으면 공개 URL로 올린 개인정보 처리방침을 스토어에 등록해야 한다."
},
{
"courseSlug": "app-store-deploy",
"question": "안드로이드 keystore(서명 도장) 파일과 비밀번호를 잃어버리면 어떤 일이 생기나?",
"option1": "앱 아이콘 색이 초기화된다",
"option2": "같은 앱을 더 이상 업데이트할 수 없다",
"option3": "심사가 자동으로 빨라진다",
"option4": "앱이 무료로 전환된다",
"answerIndex": 1,
"explanation": "업데이트는 '같은 도장'으로 서명해야 기존 앱을 덮어쓸 수 있어, keystore를 잃으면 업데이트가 불가능해진다(그래서 Play App Signing으로 대비)."
},
{
"courseSlug": "app-store-deploy",
"question": "2021년 8월부터 Google Play에 올리는 '새 앱'이 사용해야 하는 업로드 형식은?",
"option1": ".apk 한 덩어리",
"option2": "IPA 패키지",
"option3": "AAB(Android App Bundle)",
"option4": "실행 가능한 exe",
"answerIndex": 2,
"explanation": "새 앱은 AAB로 올리고, 구글이 각 기기에 맞는 최적 APK로 재조립해 배달하므로 다운로드 용량이 줄어든다."
},
{
"courseSlug": "app-store-deploy",
"question": "App Store 심사가 Google Play보다 대체로 더 엄격하고 오래 걸리는 핵심 이유는?",
"option1": "안드로이드보다 개발자 비용이 싸서",
"option2": "리뷰어가 직접 심사하고, 앱 설치가 App Store로만 이뤄지는 닫힌 생태계라서",
"option3": "서명 과정을 생략하기 때문에",
"option4": "스크린샷을 요구하지 않기 때문에",
"answerIndex": 1,
"explanation": "애플은 사람이 직접 앱을 실행해 심사하며, 설치 경로가 App Store 하나뿐인 닫힌 생태계라 문지기 역할이 강하다."
},
{
"courseSlug": "app-store-deploy",
"question": "우리 웹 배포(Caddy·Docker)와 앱 스토어 배포의 '되돌리기(롤백)' 차이로 옳은 것은?",
"option1": "웹은 이전 Docker 이미지로 즉시 롤백되지만, 앱은 대개 고친 새 버전을 다시 올려 심사받아야 한다",
"option2": "둘 다 몇 초 만에 즉시 롤백된다",
"option3": "앱이 웹보다 롤백이 더 빠르다",
"option4": "웹은 원래 롤백이 불가능하다",
"answerIndex": 0,
"explanation": "웹은 이전 이미지로 즉시 되돌릴 수 있지만, 스토어는 즉시 롤백이 어려워 새 버전을 다시 올려 심사를 받아야 하므로 출시 전 테스트가 더 중요하다."
}
]