<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 오승연</title>
    <description>The latest articles on DEV Community by 오승연 (@seungyeon_).</description>
    <link>https://dev.to/seungyeon_</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3608254%2Fd8f68d4d-0262-4523-bbd9-d2c38253e505.jpg</url>
      <title>DEV Community: 오승연</title>
      <link>https://dev.to/seungyeon_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/seungyeon_"/>
    <language>en</language>
    <item>
      <title>[커리어 캠프] 2주차 회고: AI가 프롬프트도 잘 짜주는 시대, 내가 훈련해야 할 건 따로 있었다</title>
      <dc:creator>오승연</dc:creator>
      <pubDate>Tue, 01 Sep 2026 09:46:17 +0000</pubDate>
      <link>https://dev.to/seungyeon_/peurompeuteu-jagseong-bangsig-hoego-4273</link>
      <guid>https://dev.to/seungyeon_/peurompeuteu-jagseong-bangsig-hoego-4273</guid>
      <description>&lt;h2&gt;
  
  
  소개
&lt;/h2&gt;

&lt;p&gt;AI Native 커리어 캠프에 참여한 지 2주가 지났다. (26.08.04 기준)&lt;/p&gt;

&lt;p&gt;처음 5일 간은 최신 AI 기술 트렌드나 현업에서 AX 전환이 어떻게 되고 있는지, 포트폴리오에 어떻게 연결하는게 좋을 지에 대한 강의를 들었고,&lt;/p&gt;

&lt;p&gt;이후 일주일 간은 AI 리터러시를 높이기 위해 프롬프트 작성 방법에 대한 이론과 실습을 병행하고 있다.&lt;/p&gt;

&lt;p&gt;프롬프트 작성에 대해선 나름 노하우가 쌓였다고 생각하는데, 실습을 하다보니 프롬프트 작성 방식보다 근본적인 문제를 발견했다. 바로 AI에게 생각을 맡기는 습관이었다.&lt;/p&gt;

&lt;p&gt;이번 글에서는 이 습관을 어떻게 알아차렸고, 어떻게 개선하려 했는지 정리해보려고 한다.&lt;/p&gt;

&lt;h2&gt;
  
  
  본론
&lt;/h2&gt;

&lt;h4&gt;
  
  
  문제 인식
&lt;/h4&gt;

&lt;p&gt;실습은 개인과 조별로 진행을 한다. &lt;/p&gt;

&lt;p&gt;개인 실습의 예로는 모호한 지시를 4요소(역할, 맥락, 지시, 형식)을 포함해 개선해나가는 식이고, 조별 실습은 사내 회의 시나리오가 주어지고 안건으로 올릴 요약 대시보드 표를 만드는 식이다.&lt;/p&gt;

&lt;p&gt;내가 실습을 할 때는 바로 요청사항을 지시하기보다, 아래 내용을 포함해 프롬프트 생성 자체를 지시한다. (메타 프롬프팅이라고 한다.)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;프롬프트 엔지니어링 전문가라는 역할을 부여&lt;/li&gt;
&lt;li&gt;간단한 요청사항 추가&lt;/li&gt;
&lt;li&gt;더 필요한 정보는 질문해달라고 언급&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이 방법이 내가 직접 작성하는 것보다 빠르고 생각치 못한 부분도 챙겨줘서 애용한다.&lt;/p&gt;

&lt;p&gt;그런데 실습을 반복하면서 이 방식에만 기대는 게 AI 활용 역량 향상에 도움이 될까 하는 의문이 들었다. &lt;/p&gt;

&lt;p&gt;조별 실습과 발표를 할 때에도 어떤 흐름으로 할 지 AI에게 물어보고, 응답을 조합해서 발표하다 보니 어딘가 알맹이가 빠진 듯한 느낌을 받았다.&lt;/p&gt;

&lt;p&gt;그 느낌은 다른 조의 발표를 들으면서 뚜렷해졌다.&lt;/p&gt;

&lt;p&gt;인상 깊었던 조의 방식은 다음과 같다.&lt;/p&gt;

&lt;p&gt;어떤 문제를 해결하는 프롬프트를 작성하고 개선하는 실습이 있을 때, 문제를 해결하기 위한 방법을 조원들과 논의하고 직접 작성해서 응답을 받아본 다음, 아쉬운 점과 개선 방향을 논의해 다시 지시하는 것을 반복하는 흐름으로 수행했다고 한다.&lt;/p&gt;

&lt;p&gt;AI가 개입한 지점은 요청 사항대로 응답한 부분 뿐이었다. 문제 의식을 가지고 지시를 하고, 결과물에 대한 판단은 사람의 몫이었다.&lt;/p&gt;

&lt;p&gt;나는 문제를 어떻게 풀지, 결과가 괜찮은지 생각하지 않고 AI에게 바로 물어보고 있었다. 흔히 말하는 ‘생각의 외주화’를 하고 있었던 것이다.&lt;/p&gt;

&lt;p&gt;알맹이의 정체는 ‘주체성’이었다.  &lt;/p&gt;

&lt;h4&gt;
  
  
  실습 목표 설정
&lt;/h4&gt;

&lt;p&gt;이 문제를 개선하기 위해서 실습을 하기 전에 개인적인 목표를 설정해보기로 했다. 목표가 있으면 그 실습에서 무엇을 알고 싶은지가 분명해지고, 과정과 결과에 대한 판단을 내 몫으로 남길 수 있을 것 같았다.&lt;/p&gt;

&lt;p&gt;처음 적용한 실습은 내 업무에 반복적으로 사용할 직무 프롬프트를 만드는 것이었다. (실습 내용 페이지 링크)&lt;/p&gt;

&lt;p&gt;여기에 아래와 같은 목표를 추가하고, 실습을 진행했다.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;실습 목표&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI가 프롬프트도 잘 만들어주는 시대에, &lt;strong&gt;나 혼자서도 역할/맥락/지시/형식을 채울 수 있는 감을 키우기&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;AI가 만들어준 것과 내가 목적에 맞게 작성한 것의 &lt;strong&gt;결과 비교해보고 핵심 인사이트 얻기&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;뭐든 초반에 직접 생각해보지 않고 AI에게 통으로 맡기는 &lt;strong&gt;습관 회고해보기&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  두 가지 방식으로 프롬프트 작성
&lt;/h4&gt;

&lt;p&gt;처음으로는 4요소를 바탕으로, 프롬프트를 직접 / 메타-프롬프팅 방식으로 작성했다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4요소(역할, 맥락, 지시, 형식)을 개별적으로 작성&lt;/li&gt;
&lt;li&gt;직접 작성: 4요소를 참고해 하나의 프롬프트로 작성 (완벽주의가 있으니, 최소 목표를 지정하라는 개인적인 맥락 추가)&lt;/li&gt;
&lt;li&gt;메타 프롬프팅: 4요소를 붙여넣고 이런 상황에 사용할 직무 프롬프트를 만들어 달라고 요청&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;그 다음 응답을 비교했다. (응답 비교 링크)&lt;/p&gt;

&lt;h4&gt;
  
  
  결과 비교
&lt;/h4&gt;

&lt;p&gt;그 결과, 두 방식 모두 아래 기준을 만족하며, 작업을 이어나가는 데에는 충분했다. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;프롬프트 평가 기준&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;정확성: 원본(문서·이미지·검색 결과)과 맞는지 대조했는지&lt;/li&gt;
&lt;li&gt;형식: 원하는 형식(표·길이 등)으로 잘 나왔는지&lt;/li&gt;
&lt;li&gt;활용도: 즉시 쓸 수 있는지, 손이 얼마나 더 가는지&lt;/li&gt;
&lt;li&gt;안전: 개인정보나 회사 기밀이 담긴 파일은 올리지 않았는지&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;다만 직접 작성한 프롬프트에만 ‘완벽주의가 있는 특성’을 추가했는데, 그 차이 때문에 직접 작성한 쪽이 단점을 보완해서 더 유리해 보였다.&lt;/p&gt;

&lt;p&gt;곰곰히 생각해보면 이건 작성 방식보단 맥락의 차이라고 볼 수 있다. 그 내용도 메타 프롬프팅할 때 추가했으면 차이가 거의 없었을 것 같다.&lt;/p&gt;

&lt;p&gt;처음에는 막연히 ‘직접 작성하는 게 좋을까?’라고 생각했는데, 작성 방식보다는 맥락을 분명히하는게 중요하다는 인사이트를 얻었다.&lt;/p&gt;

&lt;h4&gt;
  
  
  목표 회고
&lt;/h4&gt;

&lt;p&gt;마지막으로 설정했던 실습 목표를 돌아봤다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;AI가 프롬프트도 잘 만들어주는 시대에, 나 혼자서도 역할/맥락/지시/형식을 채울 수 있는 감을 키우기&lt;/p&gt;

&lt;p&gt;→ 4요소 키워드만 떠올려도 뭘 채워야할 지 훨씬 분명해졌다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AI가 만들어준 것과 내가 목적에 맞게 작성한 것의 결과 비교해보고 핵심 인사이트 얻기&lt;/p&gt;

&lt;p&gt;→ 위에서 정리한 그대로다. 결과물의 질은 작성 방식이 아니라 맥락을 얼마나 구체적으로 채웠는지에 따라 달라진다는 걸 알았다.&lt;/p&gt;

&lt;p&gt;맥락을 채우는 방식에 있어서는 4요소를 개별적으로 작성해본게 도움이 됐다. 앞으로도 중요한 작업을 할 때에는 사전에 정리해보고 요청하는 습관을 들이려고 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;뭐든 초반에 직접 생각해보지 않고 AI에게 통으로 맡기는 습관 회고해보기&lt;/p&gt;

&lt;p&gt;→ 이 글을 쓰는 자체로 진행 중이다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  마무리
&lt;/h2&gt;

&lt;p&gt;이번 회고는 AI를 잘 활용하는 방법에 프롬프트 작성 방식 같은 스킬적인 것도 있지만, 본질적으로는 판단 기준과 맥락을 얼마나 명확히 갖고 있느냐가 우선이라는 걸 느낀 과정이었다.&lt;/p&gt;

&lt;p&gt;이 과정을 실질적인 개선으로 만들기 위해 몇 가지를 행동으로 옮겼다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;프롬프트 작성 방식 기준 정리&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmjqlojt2cx4x7dedov8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmjqlojt2cx4x7dedov8s.png" alt=" " width="800" height="693"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클로드 채팅 지침 업데이트 (기준이 흐지부지되지 않도록 시스템화)&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;[톤 &amp;amp; 스타일 - 항상]
&lt;span class="p"&gt;-&lt;/span&gt; 나는 완벽주의가 있음. 실행 위주로 가이드하고, 반복하며 완성도를 높이는 방향으로 응답할 것.
&lt;span class="p"&gt;-&lt;/span&gt; 내 계획을 먼저 이해·인정한 뒤, "이 부분은 어때?" 식으로 부드럽게 대안 제시. 놓친 관점은 질문으로 확장시킬 것.

[작업 흐름 - 결과물 생성 요청 시 (단순 질문/가벼운 대화는 제외)]
&lt;span class="p"&gt;-&lt;/span&gt; 시작 전: &lt;span class="gs"&gt;**역할·맥락·지시·형식(4요소) 중 빠진 게 있으면 임의로 채우지 말고 확인 질문.**&lt;/span&gt; 채워졌으면 "이번 요청의 최소 목표가 뭐야? 달성되면 끝낼까?" 먼저 물어볼 것.
&lt;span class="p"&gt;-&lt;/span&gt; 목표 달성 후: 임의로 마무리하지 말고 "여기서 마무리할까, 더 진행할까?" 먼저 물어볼 것.

[항상 적용 - 상황별 트리거]
&lt;span class="p"&gt;-&lt;/span&gt; 판단(주관·우선순위·기준)이 필요한 작업을 큰 단위로 지시하면, 바로 실행하지 말고 "어떤 순서/기준으로 나눠볼까?" 되물을 것.
&lt;span class="p"&gt;-&lt;/span&gt; 결과물을 그대로 쓸 가능성 있는 작업(글/카피/코드)은 마지막에 "저작권/편향 검증 필요, &lt;span class="gs"&gt;**의도와 일치 여부 확인 필요**&lt;/span&gt;" 한 줄로 짚을 것. // 주체성 체크 요소
&lt;span class="p"&gt;-&lt;/span&gt; 이력서·자기소개서·계약서·개인정보(연락처·주소·계정) 포함 가능성 높은 파일/텍스트 작업 시, 시작 전 "개인정보 포함 가능성 있음 — 민감 부분 가리거나 시크릿 채팅 권장" 안내할 것.
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;이렇게 정리한 내용을 바탕으로 조금씩 성장해나가고자 한다!&lt;/p&gt;

&lt;h3&gt;
  
  
  추신
&lt;/h3&gt;

&lt;h4&gt;
  
  
  강사님과의 대화
&lt;/h4&gt;

&lt;p&gt;강사님께 AI가 프롬프트도 잘 만들어주는 시대에, 좋은 프롬프트가 뭔지 알아보고 직접 작성해보는 목적이 뭔지를 여쭤봤다.&lt;/p&gt;

&lt;p&gt;그랬을 때 비용 최적화 측면에서, 좋은 모델로 무한히 요청할 수 없으니 이런 내용을 알아두고 한번에 괜찮은 프롬프트를 쓸 수 있게 연습해두는 게 중요하다고 하셨다.&lt;/p&gt;

&lt;p&gt;답변을 듣고 나니 바이브 코딩이 떠올랐다. 바이브 코딩에서도 개발을 알아야 성능, 보안 측면도 생각할 수 있는 것처럼 프롬프트도 비슷한 것 같았다. &lt;br&gt;
메타 프롬프팅으로 받은 프롬프트도 원하는 결과를 낼 수 있지만 구조를 모른다면 토큰이 낭비되는 부분/개선할 수 있는 부분 등을 판단할 수가 없다. &lt;/p&gt;

&lt;p&gt;바이브 코딩이든, 메타프롬프팅이든 AI 성능이 아무리 좋아져도 내가 직접 알아야 판단할 수 있는 부분은 여전히 남아있는 것이다.&lt;/p&gt;

&lt;h4&gt;
  
  
  더 보고 싶은 부분
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;글에서 언급한 키워드 관련 유튜브 2편 보기&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=J3BbFNYHvZM" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=J3BbFNYHvZM&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=_yumjhDbDWk" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=_yumjhDbDWk&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;프롬프트 작성 방식에 결과를 평가하는 전문적인 방법 찾아보기: 직관으로만 판단해서 업계 표준 평가 방식은 어떤지 궁금함&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/Q00/ouroboros/blob/main/README.ko.md" rel="noopener noreferrer"&gt;OUROBOROS&lt;/a&gt; 살펴보기: 명확한 프롬프트와 관련있는 도구로 추천받음&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>metaprompting</category>
    </item>
    <item>
      <title>[커리어 캠프] 최신 트렌드로 알아보는 AI 기술 현황 강연을 듣고</title>
      <dc:creator>오승연</dc:creator>
      <pubDate>Wed, 22 Jul 2026 09:34:55 +0000</pubDate>
      <link>https://dev.to/seungyeon_/jemog-gominjung-4cb</link>
      <guid>https://dev.to/seungyeon_/jemog-gominjung-4cb</guid>
      <description>&lt;h2&gt;
  
  
  소개
&lt;/h2&gt;

&lt;p&gt;원티드 AI 네이티브 커리어 캠프에 참여해 &lt;a href="https://www.linkedin.com/in/%EA%B8%B0%EC%88%98-%EC%A0%95-92596381/" rel="noopener noreferrer"&gt;정기수&lt;/a&gt;님의 강연을 들었습니다. &lt;/p&gt;

&lt;p&gt;AI 활용법에 대한 이야기는 많이 들어봤지만, 이번 강의에서는 조금 다른 관점의 이야기들을 들을 수 있었습니다. &lt;/p&gt;

&lt;p&gt;인상 깊었던 순서대로 정리해보겠습니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. 문제를 보는 눈이 달라지다
&lt;/h2&gt;

&lt;p&gt;가장 먼저 꽂힌 지점은 “어떤 도구가 필요한가”가 아니라 “진짜 풀어야 하는 문제가 무엇인가”부터 물어야 한다는 것이었습니다. CRM과 같은 도구를 파는 게 아니라, 어떤 문제를 풀어서 매출을 올려줄 것인가. 이 한 문장이 지금 AI 서비스 시장을 관통하는 기준처럼 느껴졌습니다.&lt;/p&gt;

&lt;p&gt;또 하나 인상적이었던 건 “계속 만들어내는 시기는 지났다”는 말이었습니다. 만드는 것 자체는 이제 쉬워졌고, 그래서 만드는 능력만으로는 차별화가 안 된다는 뜻이었습니다.&lt;/p&gt;

&lt;p&gt;사실 저에게는 만드는 것 자체도 쉽지 않았습니다. 그렇지만 많이 만들어보고 깨지거나 자신의 경험 안에서 직접 부딪혀보라는 말에서 힌트를 얻었습니다. 마침 Pro 요금제를 제공받았으니 이참에 바닥까지 긁어서 써봐야겠다는 생각이 들었습니다.&lt;/p&gt;

&lt;p&gt;좋은 회사를 보는 기준도 달라지고 있었습니다. 매출이 잘 나오는 곳도 좋지만, 장기적으로 AI를 잘 활용하는 곳이 좋은 회사라는 것. 면접에서 직접 질문해보면 확인할 수 있다는 말씀도 있었습니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. 지금 실제로 일어나고 있는 일
&lt;/h2&gt;

&lt;p&gt;실제 활용 사례들을 통해 지금 시장이 움직이는 방향을 확인할 수 있었습니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;슬랙·메일에서 할 일 추출 → 리포트&lt;/li&gt;
&lt;li&gt;회의 녹취록 주입 → 리포트 받는 사람의 뷰에 맞춰 요약&lt;/li&gt;
&lt;li&gt;원티드: 사내 정보를 데이터화·API화해서 Claude로 조회, 내부 버셀 구축&lt;/li&gt;
&lt;li&gt;보험사: 기존 사업을 AI로 재구축하고, 사람은 필요한 부분만 개입&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. 그래서 나는 어디에 서야 하는가
&lt;/h2&gt;

&lt;p&gt;강의에서 제시한 워크플로우 재설계 공식은 다음과 같았습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;워크플로우/구조 이해 → 재설계 → AI를 어디에 넣어 효율화할지 고민
=&amp;gt; 업무 효율성·생산성 향상
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;이 공식이 직무와 무관하게 동일하게 적용된다는 점이 특히 와닿았습니다.&lt;/p&gt;

&lt;p&gt;그리고 새로운 관점을 하나 얻었습니다. 직무 경계가 흐려지는 지금, 개발자만이 가질 수 있는 관점은 “운영” 차원에서 효율화할 수 있는 게 무엇인가 라는 것이었습니다.&lt;/p&gt;

&lt;p&gt;SDLC 관점에서 워크플로우를 설계하는 것, 예시로 아래와 같은 것이 있습니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;안정적으로 많은 것을 운영할 수 있는가&lt;/li&gt;
&lt;li&gt;AI로 빠르게 만들어진 코드를 기존 베이스에 맞게 정리할 수 있는가&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;추가로 도메인이나 기능 측면에서 기획이나 디자인도 넘볼 수 있는 부분도 고민해보고 싶어졌습니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  소감
&lt;/h2&gt;

&lt;p&gt;“AI를 활용하면 뭐든 빠르게 만들 수 있다”는 이야기를 들을 때마다 마음이 편치 않았습니다. &lt;/p&gt;

&lt;p&gt;문턱은 확실히 낮아졌는데, 정작 저는 미디어가 말하는 만큼의 변화를 만들어내지 못했기 때문입니다. 그 간극에서 뒤처진다는 불안이 생겼고, 이 상태로는 이도 저도 안될 것 같아 원래 작업 방식과 경험을 정리하는 쪽으로 방향을 잡으며 다독이고 있었습니다. &lt;/p&gt;

&lt;p&gt;그런데 오늘 외면하고 있던 부분을 실제 현업 관점에서 적나라하게 마주하게 되었습니다.&lt;/p&gt;

&lt;p&gt;이런 감정을 지피티에게 털어놨더니, 착시에 가깝다고 다독여줬습니다. 😇 미디어가 보여주는 건 결과물이고, 저는 지금 과정 한가운데 있으니 애초에 비교 대상이 다른 셈이라는 것입니다.&lt;/p&gt;

&lt;p&gt;여전히 방향은 흔들리지만, 이번 강의를 통해 적어도 나아가야 할 곳은 알게 된 것 같습니다. 남은 캠프 과정 동안 그 간극을 하나씩 메워보겠다는 생각으로 임할 생각입니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  액션 아이템
&lt;/h2&gt;

&lt;h3&gt;
  
  
  확정한 것
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;자신감 확보&lt;/strong&gt;: 완성도 대신 사용량 %로 체크. 이번 주 Pro 요금제 사용량을 최대한 소진해보기.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  캠프 과정 동안 고민해볼 것
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;프로젝트 아이디어를 "도구를 만드는 것 vs 문제 자체를 푸는 것" 기준으로 분류하기&lt;/li&gt;
&lt;li&gt;워크플로우 재설계 미니 프로젝트 기획?: 과거 반복 업무 1개 선정 → 병목 지점에 AI 적용 → Before/After 정리&lt;/li&gt;
&lt;li&gt;에듀테크 도메인 안에서 AI로 효율화 가능한 지점 구체적으로 리스트업하기&lt;/li&gt;
&lt;li&gt;도메인이나 기능 측면에서 개발자가 기여할 수 있는 부분 고민해보기 (마케팅, 심리학 등 찾아보기)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  추천 자료 모음
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.a16z.news/p/the-next-ai-goldrush-tokens-loops" rel="noopener noreferrer"&gt;https://www.a16z.news/p/the-next-ai-goldrush-tokens-loops&lt;/a&gt; (최근 2년 흐름 파악하기 좋음! 배경지식은 AI와 함께 보충)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twocents.xyz/" rel="noopener noreferrer"&gt;https://twocents.xyz/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://product.kyobobook.co.kr/detail/S000220293698" rel="noopener noreferrer"&gt;https://product.kyobobook.co.kr/detail/S000220293698&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>Next.js는 MPA인가 SPA인가 - (1) 깜빡임 없는 페이지 전환의 단서 찾기</title>
      <dc:creator>오승연</dc:creator>
      <pubDate>Mon, 22 Jun 2026 09:39:30 +0000</pubDate>
      <link>https://dev.to/seungyeon_/nextjsneun-mpainga-spainga-1-ggambbagim-eobsneun-peiji-jeonhwanyi-danseo-cajgi-2150</link>
      <guid>https://dev.to/seungyeon_/nextjsneun-mpainga-spainga-1-ggambbagim-eobsneun-peiji-jeonhwanyi-danseo-cajgi-2150</guid>
      <description>&lt;h2&gt;
  
  
  소개
&lt;/h2&gt;

&lt;p&gt;React를 주 스택으로 사용하면서 Next.js를 처음 공부했을 때, SSR(Server-Side Rendering)을 적용해 SPA + CSR의 SEO 문제를 해결한다는 걸 알게 됐습니다.&lt;/p&gt;

&lt;p&gt;그러다 한가지 의문이 생겼습니다.&lt;br&gt;
"SSR이면 서버에서 HTML을 생성해서 보내줄텐데, 페이지를 이동할 때마다 새로운 HTML을 받게되면 깜빡이는 것처럼 보이지 않나? 이건 MPA의 구조적 문제인데? Next.js는 MPA인가?"&lt;/p&gt;

&lt;p&gt;그런데 실제로 Next.js로 구축된 웹을 사용해보면 깜빡임 없이 부드럽게 전환됩니다.&lt;/p&gt;

&lt;p&gt;어떻게 서버에서 HTML을 새로 받으면서 깜빡임이 없는 건지 직접 확인해보기로 했습니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  탐구 1: 공식 문서 확인
&lt;/h2&gt;

&lt;p&gt;처음에는 Next.js 공식 문서에서 관련 내용을 찾아보았습니다.&lt;br&gt;
&lt;a href="https://nextjs.org/docs/app/guides/single-page-applications" rel="noopener noreferrer"&gt;https://nextjs.org/docs/app/guides/single-page-applications&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Next.js fully supports building Single-Page Applications (SPAs). &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next.js는 SPA를 완벽하게 제공한다고 합니다.&lt;/p&gt;

&lt;p&gt;제게는 &lt;code&gt;support&lt;/code&gt;가 보조의 느낌이라 'SPA로 동작합니다'보단 'SPA는 아니지만 SPA처럼 동작합니다'라고 느껴집니다. 🤔&lt;/p&gt;

&lt;p&gt;좀 더 살펴보겠습니다.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This includes &lt;strong&gt;fast route transitions with prefetching&lt;/strong&gt;, client-side data fetching, using browser APIs, integrating with third-party client libraries, creating static routes, and more&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;여기에 &lt;strong&gt;prefetching을 통한 빠른 경로 전환&lt;/strong&gt;에 대한 내용이 있습니다. prefetch가 부드러운 페이지 전환의 핵심일 것 같습니다.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Next.js can automatically code split your JavaScript bundles, and &lt;strong&gt;generate multiple HTML entry points into different routes&lt;/strong&gt;. This avoids loading unnecessary JavaScript code on the client-side, reducing the bundle size and enabling faster page loads.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;next/link component&lt;/strong&gt; automatically &lt;strong&gt;prefetches routes&lt;/strong&gt;, giving you &lt;strong&gt;the fast page transitions of a strict SPA&lt;/strong&gt;, but with the advantage of persisting application routing state to the URL for linking and sharing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;여러 경로에 대한 HTML 진입점&lt;/strong&gt;을 생성할 수 있다는 내용도 있고,&lt;br&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt;&lt;/strong&gt; 컴포넌트로 경로를 prefetch해서 &lt;a href="https://nextjs.org/docs/app/guides/single-page-applications#what-is-a-single-page-application" rel="noopener noreferrer"&gt;엄격한 SPA&lt;/a&gt;처럼 빠른 페이지 전환을 제공한다고 합니다.&lt;/p&gt;

&lt;p&gt;이로써 prefetch 하는 &lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt; 컴포넌트가 핵심이란 걸 알 수 있습니다.&lt;br&gt;
또한 여러 진입점을 생성한다는 것도 SEO와 관련해 중요해보입니다. 페이지 전환이 빠른건 SEO와는 독립적인 내용이니까요.&lt;/p&gt;

&lt;h2&gt;
  
  
  탐구 2: 데모 앱 실험
&lt;/h2&gt;

&lt;p&gt;공식 문서로 힌트는 얻었지만 아직 풀리지 않은 의문이 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt;로 prefetch 한다면 HTML을 미리 받아두는 걸까요? 그럼 전환할 때 또 깜빡이지 않을까요? 도대체 뭘 받아서 어떻게 하는 걸까요?&lt;/p&gt;

&lt;p&gt;간단한 앱을 만들어서 어떻게 동작하는지 살펴보겠습니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  데모 앱 구성
&lt;/h3&gt;

&lt;p&gt;실험 조건을 만들기 위해 간단한 Next.js 앱을 구성했습니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;next.js v16.2.9&lt;/li&gt;
&lt;li&gt;SSG 페이지 1개 (/ssg)&lt;/li&gt;
&lt;li&gt;SSR 페이지 1개 (/ssr)&lt;/li&gt;
&lt;li&gt;메인 페이지 1개&lt;/li&gt;
&lt;li&gt;메인에서 각 경로로 이동할 수 있도록 내비게이션 추가 (&lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt; 컴포넌트, &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 태그 각각 1개씩)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5fvrdwfggu1awzjigssl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5fvrdwfggu1awzjigssl.png" alt="메인 페이지" width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  개발자 도구 확인
&lt;/h3&gt;

&lt;p&gt;먼저 &lt;code&gt;&amp;lt;Link&amp;gt;&lt;/code&gt; 컴포넌트가 추가된 메인 페이지에 진입해 네트워크 탭을 확인했습니다.&lt;br&gt;
예상한대로 내비게이션이 추가된 페이지와 관련된 요청이 있었습니다.&lt;br&gt;
(참고로 production 환경으로 실행해야 정상적으로 prefetch 해오는걸 확인할 수 있습니다.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgif8eawhkythnfl59uhd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgif8eawhkythnfl59uhd.png" alt="_rsc 파라미터 요청" width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;요청 URL은 &lt;code&gt;/ssr?_rsc=...&lt;/code&gt;과 같은 형태이고, Content-Type이 &lt;code&gt;text/x-component&lt;/code&gt;인걸 봐서 html을 받아오는 건 아니라는 건 알 수 있었습니다. (rsc는 react server component를 의미하는 것 같습니다.)&lt;/p&gt;

&lt;p&gt;두개의 내비게이션 방식으로 페이지 전환을 해보겠습니다.&lt;/p&gt;

&lt;p&gt;Link 컴포넌트로 전환하면 메인 페이지에서 봤던 것과 동일한 요청이 있으며,&lt;br&gt;
헤더 탭을 살펴보면 응답 헤더에 &lt;code&gt;Content-Type: text/x-component&lt;/code&gt;가 있고, 요청 헤더에 &lt;code&gt;Rsc: 1&lt;/code&gt;이라는 수상한 헤더가 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh001v3u3jzs2fbotcfcm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh001v3u3jzs2fbotcfcm.png" alt="응답 헤더" width="800" height="555"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fobb6j68wc67g59oyh4f3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fobb6j68wc67g59oyh4f3.png" alt="요청 헤더" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;반면 a 태그로 전환하면 URL을 입력해 직접 진입하는 것과 동일하게 &lt;code&gt;Content-Type: text/html&lt;/code&gt;을 받아옵니다.&lt;/p&gt;

&lt;p&gt;두번째로 elements 탭을 살펴봤습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foqpd4o0pi8x4nqfaeg2d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foqpd4o0pi8x4nqfaeg2d.gif" alt="elements 탭 비교" width="560" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Link 컴포넌트로 이동하면 DOM 일부가 변경하는 것이 보이고, a 태그로는 전체 페이지를 새로고침하는 것이 보입니다.&lt;/p&gt;

&lt;p&gt;자세한 원리는 몰라도 Link 컴포넌트로 전환 시 x-component 형식을 받아오며, DOM 일부만 변경하는 방식으로 부드러운 전환이 일어난다는 것을 알 수 있습니다.&lt;/p&gt;

&lt;h4&gt;
  
  
  (추신) SSG는 어떨까?
&lt;/h4&gt;

&lt;p&gt;/ssr을 중심으로 살펴봐도 충분했지만, SSG에 흥미로운 점이 있어 덧붙이려 합니다.&lt;/p&gt;

&lt;p&gt;SSG는 빌드 타임에 HTML을 생성하는 방식입니다.&lt;br&gt;
그래서 'Link 컴포넌트로 전환하더라도 /ssr과 달리 HTML을 응답하지 않을까?'라고 예상했습니다.&lt;/p&gt;

&lt;p&gt;하지만 /ssg 경로로 전환 시 동일하게 &lt;code&gt;x-component&lt;/code&gt;를 응답했습니다.&lt;/p&gt;

&lt;p&gt;빌드 결과물을 확인해 보니 &lt;code&gt;ssg.html&lt;/code&gt;과 &lt;code&gt;ssg.rsc&lt;/code&gt; 두 파일이 생성되어 있었습니다.&lt;br&gt;
아마 클라이언트 사이드 전환을 지원하기 위해 &lt;code&gt;.rsc&lt;/code&gt; 형태의 파일을 생성하는 것으로 보입니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs3g9hj8u92ks23wi64xi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs3g9hj8u92ks23wi64xi.png" alt=".rsc 파일" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;정적 페이지인 SSG조차 부드러운 페이지 전환을 지원한다는 점이 흥미롭습니다. Next.js는 페이지에 진입하거나 이동하는 방식에 따라 다른 전략을 사용하는 프레임워크라는 사실을 다시 한번 확인할 수 있었습니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  결론
&lt;/h2&gt;

&lt;p&gt;Next.js는 직접 진입 시에는 HTML을 응답하는 MPA와 유사하게 동작하지만,&lt;br&gt;
Link 컴포넌트로 전환 시에는 x-component 형태의 응답을 받아 일부 DOM만 교체하며 SPA처럼 동작합니다.&lt;/p&gt;

&lt;p&gt;즉, 진입 방식에 따라 다르게 동작하며 SEO와 UX 문제를 모두 해결한 하이브리드 프레임워크라고 볼 수 있겠습니다.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;진입 방식&lt;/th&gt;
&lt;th&gt;요청 헤더&lt;/th&gt;
&lt;th&gt;응답 형태&lt;/th&gt;
&lt;th&gt;처리 방식&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;직접 URL 진입 / a 태그&lt;/td&gt;
&lt;td&gt;rsc 헤더 없음&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text/html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;전체 DOM 교체&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Link 내비게이션&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rsc: 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;text/x-component&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;변경 segment만 교체&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;SEO는 직접 진입 시 완성된 HTML을 받으므로 크롤러가 읽을 수 있습니다.&lt;/li&gt;
&lt;li&gt;UX는 Link 내비게이션으로 일부만 변경하므로 전체 페이지 깜빡임이 없습니다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  마무리
&lt;/h2&gt;

&lt;p&gt;이번 탐구를 통해 공식 문서에 나온 &lt;code&gt;Next.js fully supports building SPAs&lt;/code&gt;의 의미를 조금 더 이해할 수 있었습니다.&lt;/p&gt;

&lt;p&gt;또한 SSR을 단순히 서버에서 HTML을 생성해 응답한다는 걸로만 이해하고 있었는데, 응답 형태보다는 중요한 콘텐츠를 미리 포함시켜 응답하는게 핵심이 아닐까 하고, 관점을 바꾸게 되었습니다.&lt;/p&gt;

&lt;p&gt;다만 아직 _rsc 요청 파라미터나 &lt;code&gt;Rsc: 1&lt;/code&gt;과 같은 요청 헤더의 정체를 알지는 못했습니다.&lt;br&gt;
다음 글에서는 오픈소스를 따라가며 실제로 어떻게 동작하는지 좀 더 자세히 살펴보겠습니다. 🤓&lt;/p&gt;

&lt;p&gt;혹시나 잘못된 부분이 있다면 댓글로 알려주세요!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>frontend</category>
    </item>
    <item>
      <title>교육 산업을 읽는 법: 신문 스크랩을 시작하며</title>
      <dc:creator>오승연</dc:creator>
      <pubDate>Thu, 19 Mar 2026 08:35:12 +0000</pubDate>
      <link>https://dev.to/seungyeon_/gyoyug-saneobeul-ilgneun-beob-sinmun-seukeuraebeul-sijaghamyeo-188g</link>
      <guid>https://dev.to/seungyeon_/gyoyug-saneobeul-ilgneun-beob-sinmun-seukeuraebeul-sijaghamyeo-188g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;2025년 12월 21에 작성한 글입니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;취업 준비 중 지원동기를 고민하다가 우연히 경제 신문 스크랩에 관한 영상을 보게 됐다. (영상 링크는 아래에 있다.)&lt;/p&gt;

&lt;p&gt;처음엔 지원동기 작성에 도움이 될까 싶어 본 영상이었는데, 보다 보니 '신문 스크랩으로 산업을 분석할 수 있다'는 지점이 눈에 들어왔다.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://o5sy.notion.site/2d1d9c31c757803c92a6d8950a2cba52?v=2d1d9c31c7578049804c000c549dae30&amp;amp;source=copy_link" rel="noopener noreferrer"&gt;스크랩 아카이브 링크&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  왜 필요한가
&lt;/h2&gt;

&lt;p&gt;나는 도메인을 제대로 이해해야 더 좋은 해결책을 제시할 수 있다고 믿어왔다. 문제는 방법이었다. 도메인을 이해하려면 그 산업에 직접 몸담아 경험을 쌓거나 현직자 인터뷰를 해야 가능하다고 생각했다.&lt;/p&gt;

&lt;p&gt;그런데 신문 스크랩이라는 방법을 알게 되면서 생각이 바뀌었다. 꼭 현장에 있지 않아도, 신문을 통해 트렌드를 읽고 산업의 흐름을 파악할 수 있겠다는 가능성이 보였다.&lt;/p&gt;

&lt;h2&gt;
  
  
  어떻게 할 것인가
&lt;/h2&gt;

&lt;p&gt;영상에서 소개하는 스크랩 방법은 이렇다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;경제신문 A면을 전부 훑어보며 빠르게 스크랩할 기사를 본다&lt;/li&gt;
&lt;li&gt;선정한 기사를 스크랩 양식에 옮겨 붙인다&lt;/li&gt;
&lt;li&gt;숫자는 빨간색, 기술이나 트렌드는 파란색으로 표시한다&lt;/li&gt;
&lt;li&gt;추가 조사할 키워드를 발견한다&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;나는 좀 더 분명한 목적이 있었기에, 이에 맞게 스크랩 방법 또한 구체화했다.&lt;/p&gt;

&lt;p&gt;(1) 산업을 파악하고 교육에 대한 관심을 유지하는 것&lt;br&gt;
(2) 멘토링에 적용할 방법을 찾는 것&lt;/p&gt;

&lt;h3&gt;
  
  
  스크랩 방법 및 계획
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. 빠르게 스크랩할 기사를 체크한다&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;신문사는 &lt;a href="https://www.hangyo.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;한국교육신문&lt;/strong&gt;&lt;/a&gt;으로 정했다.&lt;/p&gt;

&lt;p&gt;1961년 창간 이래 교육 이슈와 교육 콘텐츠를 꾸준히 발행해온 곳으로, 매주 월요일 발행되는 &lt;a href="https://www.hangyo.com/news/pdf.html" rel="noopener noreferrer"&gt;주간지&lt;/a&gt;를 중심으로 살펴볼 예정이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;주로 찾아볼 기사는 다음과 같다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;성인 취업 교육과 에듀테크 산업 관련 기사&lt;/li&gt;
&lt;li&gt;효과적인 교육 방법을 다룬 기사&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;다만 공교육 중심의 내용이 많아서, 내가 원하는 내용의 기사가 없는 주도 있어 보인다. 그럴 땐 그 주에 발행된 기사를 훑어보면서 교육 전반의 흐름이라도 파악하려고 한다.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. 선정한 기사를 스크랩 양식에 옮긴다&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;스크랩 양식

&lt;ul&gt;
&lt;li&gt;헤드라인&lt;/li&gt;
&lt;li&gt;본문&lt;/li&gt;
&lt;li&gt;(옵션) 궁금한 점&lt;/li&gt;
&lt;li&gt;인사이트 / 적용할 점

&lt;ul&gt;
&lt;li&gt;IT 서비스를 통한 사업 기회 생각해보기 (토이 프로젝트 아이디어 발굴)&lt;/li&gt;
&lt;li&gt;멘토링 및 개발 학습에 적용할 방법 생각해보기&lt;/li&gt;
&lt;li&gt;등등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. 숫자는 빨간색, 기술이나 트렌드는 파란색으로 표시한다&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;하이라이팅 방법은 빠르게 본문을 훑어보기에 좋을 것 같아서 그대로 적용한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  앞으로는
&lt;/h2&gt;

&lt;p&gt;실제로 해보면서 인사이트가 생기는 대로 방향을 조절해 나갈 생각이다. 완벽한 계획보다는 일단 시작하고 꾸준히 하는 게 중요하다!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?si=gndyDr1onnDzqpxR&amp;amp;t=291&amp;amp;v=oCCooQ9IMTo&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;경제 신문 스크랩 영상 - 면접왕 이형&lt;/a&gt;&lt;/p&gt;

</description>
      <category>education</category>
    </item>
    <item>
      <title>[JavaScript] 데이터 복사 이해하기 (feat. 얕은 복사, 깊은 복사)</title>
      <dc:creator>오승연</dc:creator>
      <pubDate>Thu, 19 Mar 2026 08:26:44 +0000</pubDate>
      <link>https://dev.to/seungyeon_/javascript-deiteo-bogsa-ihaehagi-feat-yateun-bogsa-gipeun-bogsa-243e</link>
      <guid>https://dev.to/seungyeon_/javascript-deiteo-bogsa-ihaehagi-feat-yateun-bogsa-gipeun-bogsa-243e</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;2025년 12월 1일에 작성된 글입니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;객체를 복사했는데 원본까지 바뀌는 경험 있으신가요? JavaScript에서는 데이터를 복사할 때 타입에 따라 동작 방식이 다르기 때문에 이런 일이 발생합니다. 이 글에서는 복사의 기본 원리부터 실전 복사 전략까지 단계별로 알아보겠습니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  이 글을 통해 얻을 수 있는 것
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;데이터 타입에 따른 복사 방식의 차이를 이해한다&lt;/li&gt;
&lt;li&gt;객체 복사 시 주의해야 할 점을 안다&lt;/li&gt;
&lt;li&gt;상황에 맞는 복사 방법을 선택할 수 있다&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. JavaScript 데이터의 복사: 타입에 따라 다르다
&lt;/h2&gt;

&lt;p&gt;JavaScript의 타입은 크게 원시 값과 객체로 나뉩니다. 또한 변수에 값을 할당하거나 복사할 때, 값의 타입이 무엇인지에 따라 동작이 다릅니다.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JavaScript의 타입을 잘 모르겠다면 &lt;a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Data_structures" rel="noopener noreferrer"&gt;MDN 자료&lt;/a&gt;를 참고해보세요.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  원시 값 (Primitive Values)
&lt;/h3&gt;

&lt;p&gt;원시 값은 변수에 &lt;strong&gt;‘값 자체’&lt;/strong&gt;가 저장됩니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;종류&lt;/strong&gt;: &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;bigint&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;undefined&lt;/code&gt;, &lt;code&gt;symbol&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt; 가 있습니다.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;복사 시&lt;/strong&gt; 완전히 독립된 새로운 값이 생성됩니다.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// a의 값(100)이 복사되어 b에 저장&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c1"&gt;// b만 변경됨&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 100&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 50 (서로 독립적임)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2m7y17a5gq4wtb5066po.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2m7y17a5gq4wtb5066po.png" alt=" " width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  객체 (Object)
&lt;/h3&gt;

&lt;p&gt;객체는 변수에 값이 아닌 &lt;strong&gt;‘메모리 주소(참조)’&lt;/strong&gt;가 저장됩니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;종류&lt;/strong&gt;: &lt;code&gt;object&lt;/code&gt;, &lt;code&gt;array&lt;/code&gt;가 있으며, &lt;code&gt;function&lt;/code&gt;, &lt;code&gt;Date&lt;/code&gt; 또한 객체의 일종입니다.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;복사 시&lt;/strong&gt; 객체를 가리키는 주소가 복사됩니다.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;myArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;copyArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myArr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 배열을 가리키는 주소가 복사됨&lt;/span&gt;

&lt;span class="nx"&gt;copyArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 복사본을 수정&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;copyArr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ["hello"]&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myArr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// ["hello"]  (원본도 변경됨)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0f65h3ca3at5tx0plsv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa0f65h3ca3at5tx0plsv.png" alt=" " width="800" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. 객체 복사 시 주의점: 참조 공유 문제
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;const a = b;&lt;/code&gt;와 같이 단순 대입으로 객체를 복사하면 참조만 복사되므로, 원본과 복사본이 공유됩니다. &lt;/p&gt;

&lt;p&gt;이를 피하려면 새로운 객체를 생성해야 합니다.&lt;/p&gt;

&lt;p&gt;동일한 프로퍼티를 가지면서 새로운 객체를 생성하는 방법으로는 &lt;a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/assign" rel="noopener noreferrer"&gt;Object.assign()&lt;/a&gt;이나 배열의 경우 &lt;a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/slice" rel="noopener noreferrer"&gt;Array.prototype.slice()&lt;/a&gt; 등이 있지만, 글에선 &lt;a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax#%EA%B0%9D%EC%B2%B4_%EB%A6%AC%ED%84%B0%EB%9F%B4%EC%97%90%EC%84%9C%EC%9D%98_%EC%A0%84%EA%B0%9C" rel="noopener noreferrer"&gt;전개 연산자&lt;/a&gt;를 사용해보겠습니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  전개 연산자로 새 객체 만들기
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lee&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// 새로운 객체 생성&lt;/span&gt;

&lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 30 (원본 영향 없음)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 31&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;원본 객체의 속성들을 새로운 객체에 복사했고, 각 속성의 값은 원시 값이므로 독립적으로 수정할 수 있습니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  중첩 객체를 가진 경우
&lt;/h3&gt;

&lt;p&gt;이번에는 속성의 값으로 객체가 있는 경우를 같은 방식으로 복사해보겠습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lee&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Seoul&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;// 중첩 객체&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Busan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 'Busan' (원본도 변경됨)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;중첩 객체는 참조가 복사되므로 원본이 변경되었습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user → { name: 'Lee', address: → [0x001] }
copy → { name: 'Kim', address: → [0x001] }  (같은 주소 공유)
                                    ↓
                            { city: 'Busan' }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;왜 이런 일이 일어났을까요?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;데이터 복사는 값의 타입에 따라 달라진다는 것, 기억하시나요? &lt;/p&gt;

&lt;p&gt;전개 연산자를 통해 원본 객체의 속성을 복사하는 과정에서 원시 값은 ‘값 자체’를 복사했지만, 중첩 객체는 ‘메모리 주소(참조)’를 복사하면서 속성 값 변경 시 서로 영향을 미치게 되는 것입니다.&lt;/p&gt;

&lt;p&gt;이처럼 최상위 속성(= 1단계 깊이의 속성)만 복사하는 것을 복사 깊이가 얕다는 의미로, &lt;strong&gt;"얕은 복사(Shallow Copy)"&lt;/strong&gt;라고 합니다.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. 중첩 객체를 안전하게 복사하는 방법
&lt;/h2&gt;

&lt;p&gt;얕은 복사로 인한 문제를 해결하고, 원본을 보호하면서 복사하는 방법은 크게 두 가지가 있습니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  3-1. &lt;strong&gt;전개 연산자를 중첩해 필요한 부분만 새로 만들기&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;변경하려는 속성의 경로를 따라 전개 연산자를 중첩해서 사용하면, 필요한 부분만 새로 만들 수 있습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lee&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Seoul&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;12345&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// address.city만 변경하고 싶을 때&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// user의 최상위 속성들 복사&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;            &lt;span class="c1"&gt;// address를 새 객체로 덮어쓰기&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// 기존 address 속성들 복사 (zip 유지)&lt;/span&gt;
    &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Busan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;       &lt;span class="c1"&gt;// city만 변경&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    &lt;span class="c1"&gt;// 'Seoul' (원본 유지)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 'Busan'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;배열 내부 객체를 수정할 때는 &lt;a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map" rel="noopener noreferrer"&gt;Array.prototype.map()&lt;/a&gt;을 활용할 수도 있습니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lee&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Kim&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// id가 1인 사용자의 active만 변경&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;이처럼 전개 구문을 중첩해서 사용하면 필요한 부분만 새로 만들어 복사할 수 있습니다. 하지만 이 방법은 &lt;strong&gt;어떤 속성을 변경할지 미리 알고 있을 때&lt;/strong&gt; 유용합니다. &lt;/p&gt;

&lt;h3&gt;
  
  
  3-2. 모든 속성을 독립적으로 복사하기: 깊은 복사
&lt;/h3&gt;

&lt;p&gt;사용자가 자유롭게 데이터를 바꾸는 환경에서는, 편집 시작 시점의 원본 데이터를 통째로 보관해두는 것이 효율적입니다.&lt;/p&gt;

&lt;p&gt;또한 히스토리를 유지하거나 로그를 남겨야 하는 경우에도 각 시점의 상태를 독립적으로 저장해야 정확한 기록을 유지할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;예시 시나리오: 텍스트 에디터의 취소 기능&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;사용자가 문서를 편집하다가 "실행 취소(ctrl+z)"를 하면 이전 상태로 되돌아가야 합니다. 사용자가 어떤 부분을 수정할지 예측할 수 없으므로, 편집 전 문서 상태를 통째로 저장해두어야 합니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 현재 문서 상태&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentDocumentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;formatting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;italic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// 얕은 복사로는 안전하지 않음&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;currentDocumentState&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// formatting은 여전히 공유됨&lt;/span&gt;

&lt;span class="c1"&gt;// 사용자가 여러 작업 수행&lt;/span&gt;
&lt;span class="nx"&gt;currentDocumentState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello JavaScript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;currentDocumentState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formatting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fontSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;currentDocumentState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formatting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 실행 취소 시도&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentDocumentState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// formatting은 이미 변경되어 복구할 수 없는 문제 발생&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;이런 경우 &lt;strong&gt;모든 중첩된 객체를 완전히 새로운 메모리 공간에 복사&lt;/strong&gt;해야 합니다. 이를 &lt;strong&gt;"깊은 복사(Deep Copy)"&lt;/strong&gt;라고 합니다.&lt;/p&gt;

&lt;p&gt;그 중 &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone" rel="noopener noreferrer"&gt;structuredClone()&lt;/a&gt;은 최신 브라우저에서 지원하는 표준 API로, &lt;a href="https://developer.mozilla.org/ko/docs/Web/API/Web_Workers_API/Structured_clone_algorithm" rel="noopener noreferrer"&gt;structured clone 알고리즘&lt;/a&gt;을 사용하여 깊은 복사를 수행합니다.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 편집 전 깊은 복사로 스냅샷 저장&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;structuredClone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentDocumentState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 사용자가 수정&lt;/span&gt;
&lt;span class="nx"&gt;currentDocumentState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formatting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fontSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 실행 취소 시 안전하게 복원&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentDocumentState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentDocumentState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formatting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fontSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// 14 (원본 상태 유지)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;깊은 복사 방법 비교표&lt;/strong&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;방법&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;장점&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;단점&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;structuredClone()&lt;/td&gt;
&lt;td&gt;빠르고 표준&lt;/td&gt;
&lt;td&gt;호환성 확인 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;_.cloneDeep()&lt;/td&gt;
&lt;td&gt;모든 타입 복사 가능&lt;/td&gt;
&lt;td&gt;번들 사이즈 증가&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Immer&lt;/td&gt;
&lt;td&gt;불변 업데이트 간결&lt;/td&gt;
&lt;td&gt;러닝커브 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON.parse(JSON.stringify())&lt;/td&gt;
&lt;td&gt;라이브러리 없이 간단 사용&lt;/td&gt;
&lt;td&gt;Date, function, undefined 손실&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  요약
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;타입에 따라 복사 방식이 다름&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;원시 값: 값 자체 복사 → 독립적&lt;/li&gt;
&lt;li&gt;객체: 참조 복사 → 공유됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;객체 복사의 기본은 "얕은” 복사 방식&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;전개 연산자(&lt;code&gt;{...obj}&lt;/code&gt;, &lt;code&gt;[...arr]&lt;/code&gt;)는 1단계만 새로 만듦&lt;/li&gt;
&lt;li&gt;필요한 경로까지 중첩 전개로 해결 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;필요시 "깊은" 복사 방식 적용&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;중첩 객체 + 원본 보호 필요 시 &lt;code&gt;structuredClone()&lt;/code&gt; 등 API 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  퀴즈
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;다음 코드의 결과를 예측해보세요.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Lee&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;다음 코드의 결과를 예측해보세요.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Lee&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  참고 자료
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/ko/docs/Glossary/Shallow_copy" rel="noopener noreferrer"&gt;MDN - Shallow copy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/ko/docs/Glossary/Deep_copy" rel="noopener noreferrer"&gt;MDN - Deep copy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ko.javascript.info/object-copy" rel="noopener noreferrer"&gt;https://ko.javascript.info/object-copy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>개발자를 위한 AI 활용 학습법: 4단계 학습 방법론</title>
      <dc:creator>오승연</dc:creator>
      <pubDate>Thu, 19 Mar 2026 08:22:33 +0000</pubDate>
      <link>https://dev.to/seungyeon_/gaebaljareul-wihan-ai-hwalyong-hagseubbeob-4dangye-hagseub-bangbeobron-1ldf</link>
      <guid>https://dev.to/seungyeon_/gaebaljareul-wihan-ai-hwalyong-hagseubbeob-4dangye-hagseub-bangbeobron-1ldf</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;2025년 8월 12일에 작성된 글입니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;개발 학습자들이 자주 하는 질문이 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“강의는 다 들었는데, 실제 코드에 어떻게 적용할지 모르겠어요.”&lt;/em&gt;&lt;br&gt;
&lt;em&gt;“궁금한 게 있으면 질문하라는데, 무엇을 물어봐야 할지 모르겠어요.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;이론으로만 이해했다고 생각하고 넘어가면서 실제 적용에서 막히게 되는 것입니다.&lt;/p&gt;

&lt;p&gt;이 글에서는 AI를 활용해 능동적이고 체계적으로 기술을 학습할 수 있는 4단계 학습법을 소개합니다.&lt;/p&gt;
&lt;h2&gt;
  
  
  기존 학습법의 문제점
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. 수동적인 단방향 학습
&lt;/h3&gt;

&lt;p&gt;대부분의 학습 자료는 단방향으로 정보를 전달합니다. &lt;br&gt;
간단한 실습을 진행해도 능동적으로 사용하지 않으면 기억에 오래 남지 않습니다.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. 무한 루프에 빠진 학습
&lt;/h3&gt;

&lt;p&gt;모르는 내용을 발견하면 → 새로운 자료 찾기 → 또 다른 모르는 내용 발견 → 무한 반복&lt;br&gt;
결국 어떤 것도 제대로 마무리하지 못한 채 의욕만 떨어지게 됩니다.&lt;/p&gt;
&lt;h2&gt;
  
  
  AI로 달라진 학습 환경
&lt;/h2&gt;

&lt;p&gt;AI의 등장으로 효과적인 학습이 가능해졌습니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;즉시성&lt;/strong&gt;: 개념 학습 직후 실습 환경과 예제 생성&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;상호작용&lt;/strong&gt;: 실시간 질문과 피드백으로 능동적 학습&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;개인화&lt;/strong&gt;: 내 수준과 목적에 맞춘 맞춤형 컨텐츠 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  4단계 학습 방법론
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1단계: 개념 파악
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;대상&lt;/strong&gt;: 새로운 기술을 처음 학습하려는 학습자&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;목표&lt;/strong&gt;: 기술의 개념을 빠르게 파악하기&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;방법&lt;/strong&gt;: 기초 강의 수강, 공식 문서의 개요 섹션 읽기 + AI로 모호한 부분 즉시 해결&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;핵심은 깊이보다는 &lt;strong&gt;전체 흐름을 이해하는 것&lt;/strong&gt;입니다.&lt;/p&gt;

&lt;p&gt;처음 기술을 접하기 때문에 다양한 자료를 보며 용어와 개념에 익숙해져야 합니다.&lt;br&gt;
정의, 핵심 기능, 필요성(등장 배경), 기본 동작 원리를 1차적으로 설명할 수 있는 수준으로 학습하면 충분합니다.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;AI 활용 예시&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 용어 설명 요청
React에서 말하는 '상태'가 정확히 뭐야? 쉽게 설명해줘

// 문서 이해 보조
이 공식 문서 설명이 이해가 안 돼. 다른 방식으로 설명해줘
[문서 내용 붙여넣기]

// 큰 그림 정리
지금까지 [학습한 내용들]을 학습했어
[기술명]의 핵심 개념들을 하나의 흐름으로 연결해서 설명해줘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2단계: 기본 실습
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;대상&lt;/strong&gt;: 개념은 이해했지만 실제 적용이 어려운 학습자&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;목표&lt;/strong&gt;: 문법, 기본 API, 대표적 사용 패턴 익히기&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;방법&lt;/strong&gt;: AI 맞춤형 실습 진행&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;핵심은 사용법을 익히며 코드를 치는데 익숙해지는 것입니다.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;실습 진행 순서&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;맞춤형 실습 예제를 요청합니다.&lt;/li&gt;
&lt;li&gt;초반에는 ‘왜 이렇게 동작하는지’, ‘더 나은 방법은 무엇인지’ 같은 궁금한 점은 따로 메모해두고, 구현에 집중합니다.&lt;/li&gt;
&lt;li&gt;사용법이 익숙해지면 메모를 바탕으로 공식 문서나 레퍼런스를 참고해 적용해봅니다.&lt;/li&gt;
&lt;li&gt;의도와 맥락을 포함해 코드리뷰를 요청합니다.&lt;/li&gt;
&lt;li&gt;피드백을 바탕으로 개선해봅니다.&lt;/li&gt;
&lt;li&gt;다음 조건을 만족할 때까지 반복합니다.

&lt;ul&gt;
&lt;li&gt;예제 없이도 기본 구조를 구현할 수 있다.&lt;/li&gt;
&lt;li&gt;사용법을 다른 사람에게 설명할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;💡 &lt;strong&gt;AI 활용 프롬프트&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;실습 생성 요청&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[방금 배운 개념]을 바로 적용할 수 있는 실습을 만들어줘
목표는 문법, 기본 API, 대표적 사용 패턴을 익히는 거야
- 5분 소요 실습 1개 (기본 사용법)
- 15분 소요 실습 1개 (응용 사례)
- 각각 단계별 가이드와 예상 결과물 포함
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;코드리뷰 요청&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;내가 작성한 코드를 아래 형식에 맞춰 리뷰해줘
- 실습 목표: 문법과 기본 API, 대표적 사용 패턴을 익히고, 예제 없이도 구현 가능하게 되는 것
- 기본 문법, API 사용이 적절한지 평가
- 대표적 사용 패턴과 비교해 부족한 점 2가지 제시
- 이해를 돕기 위한 개선 예시 코드 작성
- 같은 기능을 더 효율적으로 구현할 수 있는 방법 제안
- 다음 단계로 공부/실습하면 좋을 주제 1개 추천

[코드 첨부]
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3단계: 심화 탐구
&lt;/h3&gt;

&lt;p&gt;기본 개념을 익힌 후, 목적에 따라 더 깊이 이해하는 단계입니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) 심화 개념 학습
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;대상&lt;/strong&gt;: 기본 개념은 이해했지만 내부 동작 원리가 궁금한 학습자&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;목표&lt;/strong&gt;: 기술의 동작 원리 등의 개념을 깊이 있게 이해&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;방법&lt;/strong&gt;: AI와 소크라테스식 문답 진행&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;💡&amp;nbsp;AI 활용 프롬프트&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;나는 지금까지 [기술명]의 [학습 내용]을 학습했어
소크라테스 문답법으로 내 이해도를 확인하고 심화 개념 학습을 도와줘
시작할 수 있게 먼저 질문을 던져줘

- 기본 개념 확인부터 시작
- 내부 동작 원리와 '왜 그렇게 설계됐는지' 중심으로 질문
- 틀리면 힌트만, 맞으면 더 깊은 질문
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2) 실제 프로젝트 적용
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;대상&lt;/strong&gt;: 학습한 내용을 실제 프로젝트에 써보고 싶은 학습자&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;목표&lt;/strong&gt;: 프로젝트 내 적용 가능한 부분을 찾아 상황에 맞게 적용&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;방법&lt;/strong&gt;: AI와 적용 전략 수립 및 구현&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;💡&amp;nbsp;AI 활용 프롬프트&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;학습한 [학습 내용]을 [프로젝트 상황]에 적용하려고 해
실무 관점에서 프로젝트 내에 적용 가능한 부분을 찾아, 상황에 맞게 적용할 수 있게 도와줘

- 언제, 어떻게 사용하는 게 적절한지 판단 기준
- 실제 코드 예시와 패턴
- 흔히 발생하는 실수와 주의할 점
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4단계: 학습 마무리
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;대상&lt;/strong&gt;: 학습한 내용을 정리하고 마무리하고 싶은 학습자&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;목표&lt;/strong&gt;: 진짜 이해했는지 최종 점검&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;방법&lt;/strong&gt;: 설명하기, 모의면접, 글 작성&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI에게 설명해보면서 막히는 부분을 체크하고, 더 궁금한 내용을 정리해봅니다.&lt;br&gt;
(설명은 음성인식으로 타이핑되는 기능을 활용해보세요.)&lt;/p&gt;

&lt;p&gt;시간에 따라 더 알아보거나 나중에 알아볼 내용으로 쌓아두고 마무리할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💡&amp;nbsp;AI 활용 프롬프트&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;개념 설명&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[기술명]을 이해했는지 확인하기 위해 설명해볼게
내 설명에서 부족한 부분이나 틀린 부분 지적해줘

[음성인식으로 설명]
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;모의 면접&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;너는 시니어 개발자이자 면접관이야
[기술명]에 대해 3개의 면접 질문을 해줘
- 기본 개념 이해도 확인 질문 1개
- 실무 적용 경험 1개
- 트러블슈팅/문제해결 1개
모든 답변이 끝나면 부족한 부분과 추가 학습 포인트 알려줘
&lt;/code&gt;&lt;/pre&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  결론
&lt;/h2&gt;

&lt;p&gt;기존 학습법의 문제점에서 출발해, 새로운 기술을 체계적으로 학습하는 방법을 정리해보았습니다.&lt;/p&gt;

&lt;p&gt;AI는 훌륭한 학습 도구이지만, 중요한 것은 능동적으로 활용하는 학습자의 태도입니다.&lt;br&gt;
기술 학습의 목적이 '문제 해결'이라는 것을 잊지 말고, AI가 제공하는 정보를 비판적인 태도로 검증하는 절차 또한 필요합니다.&lt;/p&gt;

&lt;p&gt;이 방법론이 기술 학습 시 이론과 실전 사이 간극을 메우는 데 도움이 되기를 희망합니다!&lt;/p&gt;

</description>
      <category>education</category>
      <category>promptengineering</category>
      <category>ai</category>
    </item>
    <item>
      <title>바이브코딩으로 10일 만에 완성한 자동화 도구 개발기</title>
      <dc:creator>오승연</dc:creator>
      <pubDate>Thu, 19 Mar 2026 08:19:39 +0000</pubDate>
      <link>https://dev.to/seungyeon_/baibeukodingeuro-10il-mane-wanseonghan-jadonghwa-dogu-gaebalgi-255o</link>
      <guid>https://dev.to/seungyeon_/baibeukodingeuro-10il-mane-wanseonghan-jadonghwa-dogu-gaebalgi-255o</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;2025년 7월 18일에 작성된 글입니다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2ywmmstu3paeuk4l927.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2ywmmstu3paeuk4l927.gif" alt="피드백 생성 동작" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. 바이브코딩으로 개발을 결심하기까지&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;반복되는 업무, 반복되는 고통&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;부트캠프에서 모의면접 멘토로 활동하며, 가이드대로 멘토링을 진행하고 있다. 준비하고 진행하기까지는 순조로운데, 이후 진행한 내용을 리포트로 정리해 제출해야 한다.&lt;/p&gt;

&lt;p&gt;여기서 고통이 시작된다. 리포트 작성에 멘토링 이상의 시간이 소요된다는 것이다.&lt;/p&gt;

&lt;p&gt;면접 중에는 멘티의 답변을 실시간으로 타이핑한다. 빠르게 치다 보니 오타가 많고, 마무리하지 못한 문장도 많다. 면접이 끝나면 메모한 내용을 자연스러운 문장으로 다듬어야 한다.&lt;/p&gt;

&lt;p&gt;답변에 대해 피드백도 제공하는데, 멘토링 중에는 말을 함과 동시에 타이핑을 해야해서 단어 정도만 메모하고, 나중에 다시 답변을 읽으며 상세한 피드백을 작성한다. 이미 구두로 전달한 내용을 다시 떠올리는 과정이 반복된다.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;자동화 가능한 지점 발견&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;이 과정에는 두 가지 패턴이 있다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. 답변 정제 작업&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;오타 수정과 문장 완성&lt;/li&gt;
&lt;li&gt;일관된 문체로 수정&lt;/li&gt;
&lt;li&gt;LLM을 통해 수정: 메모한 답변 복사+붙여넣기 → 수정 요청 → 정제된 답변 복사+붙여넣기&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. 피드백 작성 작업&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;기술 내용에 대해 잘 파악한 점과 틀린 점 작성&lt;/li&gt;
&lt;li&gt;소프트스킬(답변 형식과 태도)에 대해 좋은 점과 아쉬운 점 작성&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;둘 다 형식적이고 반복적인 작업이다. 이미 LLM을 활용하고 있었지만 매번 동일한 프롬프트를 요청했고, 복붙 과정까지도 자동화하면 더 시간을 단축할 수 있겠다는 생각이 들었다.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;바이브코딩에 대한 관심&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;얼마 전 바이브코딩 강의를 수강했다. (커서 IDE 유료 결제도 했으니 뽕을 뽑아야 했다. 😃)&lt;/p&gt;

&lt;p&gt;강의는 준비된 프롬프트로 간단한 프로젝트를 개발하는 실습 위주로 진행됐다. 하지만 툴 사용이 익숙하지 않고 개발 프로젝트에 대한 이해도 부족해서 주도적으로 작업하기보다는 따라하며 익숙해지는 시간이었다. &lt;/p&gt;

&lt;p&gt;이번 프로젝트가 수강한 내용을 직접 적용해보며 AI 활용 방법을 체감하기에 적합해 보였다.&lt;/p&gt;

&lt;p&gt;참고로 내가 생각하는 바이브코딩은 AI에 의존해 기획과 개발을 하지만, 필요한 부분에서는 직접 코드 수정과 디버깅을 하면서 작업하는 것이다. (25.10.20 현시점 증강 코딩이라고 하더라.)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. AI와 함께하는 기획부터 개발까지&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;문제 정의부터 다시 시작&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;작업의 첫 단계는 문제를 명확히 하는 것이었다. "자동화 툴을 만들려고 해. 문제 정의 단계를 하려는데 어떻게 시작하면 좋을까?"라고 하니, AI가 구체적인 질문들을 던져왔다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;현재 가장 반복적으로 하고 있는 작업들이 무엇인가요?&lt;/li&gt;
&lt;li&gt;하루 중 어떤 작업에 가장 많은 시간을 쓰고 계신가요?&lt;/li&gt;
&lt;li&gt;어떤 작업이 가장 번거롭고 시간이 오래 걸리나요?&lt;/li&gt;
&lt;li&gt;완전 자동화 vs 반자동화 중 어느 방향을 선호하시나요?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이런 질문들에 답하면서 요구사항이 구체화되었다. 두루뭉술했던 아이디어가 명확한 기능 명세로 바뀌었다.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;기술 스택 선택&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;어떤 형태의 애플리케이션으로 개발할지 고민하면서 AI에게 후보를 추천해달라고 했다. &lt;/p&gt;

&lt;p&gt;내 개발 경험과 요구사항을 고려해서 세 가지 옵션을 제시했다. 각각의 장단점과 적합도까지 정리해줘서 따로 조사하지 않고 여러가지를 고려해볼 수 있었다.&lt;/p&gt;

&lt;p&gt;최종적으로는 크롬 확장 프로그램으로 결정했다. 리포트 작성 툴이 구글 스프레드 시트라 별도 웹앱으로 개발하지 않고 헬퍼 도구로 사용하고자 했다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chrome Extensions&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;번들러

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vite (+ HMR을 위해 crxjs)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;라이브러리

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Sheets API&lt;/strong&gt;: 구글 시트에서 데이터를 읽고 쓰는 용도&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemini API&lt;/strong&gt;: 텍스트 수정 작업 용도&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React, Tailwind CSS&lt;/strong&gt;: 확장 프로그램의 팝업 UI를 편리하게 개발하기 위한 용도&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vitest&lt;/strong&gt;: 테스팅 용도&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;개발 워크플로우의 변화&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;기존 개발 방식과 가장 큰 차이점은 룰 파일을 생성하는 것과 기술 학습 시점이었다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;이전 방식:&amp;nbsp;기획 → 필요한 기술 학습 → 개발 → 막히면 다시 학습&lt;/li&gt;
&lt;li&gt;바이브코딩 방식:&amp;nbsp;기획 → &lt;strong&gt;룰 파일 생성&lt;/strong&gt; → 개발 → &lt;strong&gt;필요한 부분 학습&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;바로 구현하기 전에 룰 파일을 생성하고 태스크를 정의했다. 각 태스크마다 테스트 코드를 먼저 작성하고, 구현하고, 검증하는 사이클을 반복했다.&lt;/p&gt;

&lt;p&gt;React, Tailwind CSS를 제외하곤 처음 다루는 기술이 많아 그때그때 필요한 부분만 찾아보며 진행했다. (이는 시행착오의 아픔이 되었다.)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. 점진적 개선 과정&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;초기 MVP에서 겪은 시행착오&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;처음에는 AI가 제안하는 대로 계속 진행했다. (노룩 Run command ⌘⏎)&lt;/p&gt;

&lt;p&gt;TDD를 준수해 개발하도록 룰을 설정했기 때문에 테스트 코드는 통과하지만 실제로 구동해보니 동작하지 않았다. 내가 생각한 기능 범위를 벗어나 복잡한 구조로 작성하는 것도 많았다.&lt;/p&gt;

&lt;p&gt;여러 번 작업을 복구하면서 깨달았다. &lt;strong&gt;작업자인 인간이 통제권을 가지지 않으면 프로젝트가 산으로 간다.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;통제권 회복하기&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;이후 접근 방식을 바꿨다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;태스크를 더 작은 단위로 나누기&lt;/li&gt;
&lt;li&gt;각 태스크마다 동작 확인 필수&lt;/li&gt;
&lt;li&gt;MVP라는 점을 계속 강조하기&lt;/li&gt;
&lt;li&gt;복잡한 기능은 과감히 제거&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI에게 완전히 맡기지 않고 명확한 지시를 주고 결과를 검토하는 방식으로 변경했다.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;리팩토링에서 배운 교훈&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;MVP로 빠르게 만든 코드는 당연히 거칠었다. 사용하지 않는 메서드들, 일관성 없는 구조, 불필요한 타입 정의들이 많았다.&lt;/p&gt;

&lt;p&gt;이미 AI에게 일임해 한차례 산으로 갔기 때문에 이번엔 직접 구조를 파악하며 수정하기로 했다. 그러기 위해서는 사용하는 기술의 방법을 알아야 했기에, 크롬 확장 프로그램 구조, 개발 가이드, 라이브러리 API 사용법들을 학습했다.&lt;/p&gt;

&lt;p&gt;작은 범위에 한해서는 AI를 활용했다. (커서 IDE 요청 수를 아끼려고 Gemini CLI를 썼다. 나쁘지 않다.)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;사용하지 않는 코드 식별&lt;/li&gt;
&lt;li&gt;일관성 있는 구조로 수정할 때 코드 리뷰 요청&lt;/li&gt;
&lt;li&gt;폴더 구조 정리 및 import 경로 수정&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;단순 반복 작업은 AI가 정확하게 처리했다. 하지만 넓은 범위의 구조적 개선은 여전히 인간의 명확한 판단과 지시가 필요했다.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. 결과 및 소감&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;리포트 작성 시간 단축&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;기존: 1시간 20분 (답변 수정 20분 + 피드백 작성 1시간 이상)&lt;/li&gt;
&lt;li&gt;자동화 도구 사용 후: &lt;strong&gt;20~40분&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;답변 정제: 20초&lt;/li&gt;
&lt;li&gt;피드백 작성: 20~40분 (AI 피드백 생성 시간은 2분이지만 참고해서 작성하는 방향으로 진행)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;기존 1시간 20분에서 최소 20분으로 &lt;strong&gt;업무 시간이 절반 이상으로 단축&lt;/strong&gt;되었다.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;AI가 잘하는 일 vs 못하는 일&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;바이브코딩 강의 중 강사님께서 이런 말씀을 하셨다. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“AI의 능력을 파악하세요. 바이브코딩을 반복하면서 AI가 잘하는 일, 못하는 일에 대한 경험치를 쌓으세요.”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;직접 경험해보니, &lt;strong&gt;AI가 잘하는 일&lt;/strong&gt;은 다음과 같았다.&lt;br&gt;
&lt;strong&gt;추상적인 아이디어를 구체화&lt;/strong&gt;하는 것, &lt;strong&gt;핵심 요약과 정리&lt;/strong&gt;, TDD 등의 &lt;strong&gt;개발 원칙을 준수해 코드를 작성&lt;/strong&gt;하는 일, &lt;strong&gt;패턴이 명확한 반복 작업&lt;/strong&gt;, 여러 &lt;strong&gt;선택지를 비교&lt;/strong&gt;하고 그 이유를 &lt;strong&gt;논리적으로 설명&lt;/strong&gt;하는 일 등이 있었다.&lt;/p&gt;

&lt;p&gt;이런 점은 나처럼 완벽주의 성향이 있는 사람이 모호한 생각만 가지고도 일단 시작할 수 있게 만들어준다는 점에서 정말 큰 장점이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;반면, &lt;strong&gt;AI가 잘 못하는 일&lt;/strong&gt;은 다음과 같았다.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;복잡하고 큰 규모에서 일관성을 유지하며 처리&lt;/strong&gt;하는 일, &lt;strong&gt;실제 동작 환경에서의 디버깅&lt;/strong&gt;, &lt;strong&gt;프로젝트의 성격이나 사용자 관점을 고려한 개선&lt;/strong&gt;과 같은 것이다.&lt;/p&gt;

&lt;p&gt;사실 말로 설명할 수 있는 작업이라면 대부분 AI가 잘 해낼 거라고 생각한다. 그래서 ‘못하는 일’이라도 지시만 잘하면 상당 부분 해결할 수 있을 것이다. &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;결국 강사님 말씀처럼 AI와 함께 작업하며 경험치를 쌓아가고, 잘하고 못하는 일을 구분하면서 AI가 더 잘 일할 수 있도록 활용하는 방법을 익히는 게 중요하다는 걸 느꼈다.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;지속 가능한 코딩 에이전트 활용 방법&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;10일간의 경험을 통해 얻은 인사이트를 정리하며 글을 마무리하고자 한다.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI의 모든 결과물은 반드시 리뷰할 것&lt;/strong&gt;&lt;br&gt;
줄 단위까지 세세하게 이해할 필요는 없지만, 전체 구조와 핵심 로직은 파악해야 한다.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;작업의 통제권은 작업자인 사람이 가질 것&lt;/strong&gt;&lt;br&gt;
태스크 단위로 진행 상황을 점검하고, 복잡해질 땐 단순화하는 판단이 필요하다.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(새로운 기술을 사용할 경우) &lt;strong&gt;구조를 이해하고 실제 개발에 들어갈 것&lt;/strong&gt;&lt;br&gt;
실전에 쓰기 전에 간단한 실습을 통해 구조와 동작 방식을 먼저 익힌다.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>vibecoding</category>
      <category>productivity</category>
      <category>education</category>
      <category>업무자동화</category>
    </item>
    <item>
      <title>CSR vs SSR 속도 비교 (feat. Web Vitals)</title>
      <dc:creator>오승연</dc:creator>
      <pubDate>Sun, 08 Mar 2026 09:13:58 +0000</pubDate>
      <link>https://dev.to/seungyeon_/csr-vs-ssr-sogdo-bigyo-feat-web-vitals-4aih</link>
      <guid>https://dev.to/seungyeon_/csr-vs-ssr-sogdo-bigyo-feat-web-vitals-4aih</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;CSR의 단점을 설명할 때 빠지지 않는 내용이 있습니다.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"CSR은 초기 로딩 속도가 느리다."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;그런데 좀 더 생각해보면 한가지 의문이 생깁니다.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"SSR도 서버에서 데이터를 fetch하면 그동안 화면이 비는 거 아닌가? 그러면 SSR이 CSR에 비해 느릴 수도 있지 있을까?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;이렇게 헷갈리는 이유는 속도가 상대적인 개념이기 때문입니다. 무엇을 기준으로, 어느 시점부터 측정하느냐에 따라 설명이 달라질 수 있습니다.&lt;/p&gt;

&lt;p&gt;이 글에서는 CSR과 SSR의 속도를 비교해 명확히 설명할 수 있도록 TTFB, FCP, LCP 지표를 기준으로 알아봅니다.&lt;/p&gt;




&lt;h2&gt;
  
  
  CSR과 SSR이란?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CSR (Client-Side Rendering)
&lt;/h3&gt;

&lt;p&gt;브라우저(클라이언트)에서 JavaScript를 실행해 화면을 그리는 방식입니다.&lt;/p&gt;

&lt;p&gt;서버는 내용이 거의 없는 최소한의 HTML과 JS 파일 링크만 응답합니다. 브라우저가 HTML을 받은 뒤 JS를 요청하고, JS 엔진이 실행되고, React 같은 라이브러리가 DOM을 조작해 콘텐츠가 화면에 표시됩니다.&lt;/p&gt;

&lt;p&gt;HTML을 받은 이후부터 콘텐츠가 보이기까지 필요한 절차가 많은 만큼 흰 화면이나 로딩 UI가 표시됩니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgxummh8m7u6fqj8iygb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgxummh8m7u6fqj8iygb.png" alt="CSR 렌더링 프로세스" width="800" height="650"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://prismic.io/blog/client-side-vs-server-side-rendering#what-is-clientside-rendering" rel="noopener noreferrer"&gt;https://prismic.io/blog/client-side-vs-server-side-rendering#what-is-clientside-rendering&lt;/a&gt;



&lt;h3&gt;
  
  
  SSR (Server-Side Rendering)
&lt;/h3&gt;

&lt;p&gt;서버에서 HTML을 미리 완성해 브라우저에 전달하는 방식입니다.&lt;/p&gt;

&lt;p&gt;서버에서 렌더링한다는 것은 시각적으로 그린다는 게 아니라, 필요한 데이터를 포함한 완성된 HTML 문자열을 만들어 보낸다는 것을 의미합니다.&lt;/p&gt;

&lt;p&gt;브라우저는 받은 HTML을 파싱해 로딩없이 바로 콘텐츠를 표시할 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumvlmj6vefzig15wxkrg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumvlmj6vefzig15wxkrg.jpeg" alt="SSR 렌더링 프로세스" width="800" height="650"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://prismic.io/blog/client-side-vs-server-side-rendering#what-is-serverside-rendering" rel="noopener noreferrer"&gt;https://prismic.io/blog/client-side-vs-server-side-rendering#what-is-serverside-rendering&lt;/a&gt;






&lt;h2&gt;
  
  
  "CSR이 느리다"는 말이 헷갈리는 이유
&lt;/h2&gt;

&lt;p&gt;SSR 방식은 완성된 HTML을 응답하는 정적 SSR과 요청한 시점에 HTML을 생성해 응답하는 동적 SSR으로 나눌 수 있습니다.&lt;/p&gt;

&lt;p&gt;동적 SSR의 경우 외부 API를 호출하거나 DB 쿼리가 느리면, 데이터를 받아 HTML을 생성하기까지 전체 페이지 로드가 지연되게 됩니다.&lt;/p&gt;

&lt;p&gt;반면 CSR은 서버가 빈 HTML을 응답하고 JS가 실행된 후 브라우저에서 데이터를 불러오기 때문에, 데이터가 느리게 오더라도 그 사이에 로딩 UI를 보여줄 수 있습니다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;그렇다면 CSR이 SSR보다 빠른 걸까요?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;결론부터 말하면 기준에 따라 달라집니다.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpmfk2cs594psvo68qit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpmfk2cs594psvo68qit.png" alt="주요 이벤트 타임라인 그래프" width="800" height="163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;초기 로딩을 HTML 응답 ~ 화면 표시 시점으로 보면, JS 처리 시간이 소요되기 때문에 CSR이 SSR에 비해 느리다고 할 수 있습니다.

&lt;ul&gt;
&lt;li&gt;일반적으로 말하는 초기 로딩이 이 구간에 해당한다고 볼 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;초기 로딩을 페이지 요청 ~ 화면 표시 시점으로 보면, 서버 데이터 fetch 작업이 CSR의 JS 처리 시간보다 길어지게 될 경우 SSR이 CSR에 비해 느릴 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  TTFB / FCP / LCP로 보는 CSR vs SSR
&lt;/h2&gt;

&lt;h3&gt;
  
  
  웹 바이탈 지표
&lt;/h3&gt;

&lt;p&gt;웹 바이탈 지표는 웹의 품질을 수치화하고 개선하는데 참고할 수 있는 지표입니다.&lt;br&gt;
렌더링 방식의 속도를 비교할 때 이러한 지표로 보면 더욱 명확해집니다.&lt;br&gt;
이 글에서는 시간과 관련된 세가지 지표를 보겠습니다.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TTFB (Time to First Byte)&lt;/strong&gt;: 페이지를 요청한 시점부터 서버 응답의 첫 번째 바이트를 받는 시점까지의 시간&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsczs2nunite24fp2wsx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsczs2nunite24fp2wsx.png" alt="TTFB" width="800" height="306"&gt;&lt;/a&gt;&lt;/p&gt;
startTime와 responseStart 사이의 시간입니다.
    &lt;a href="https://web.dev/articles/ttfb?hl=ko" rel="noopener noreferrer"&gt;https://web.dev/articles/ttfb?hl=ko&lt;/a&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;FCP (First Contentful Paint)&lt;/strong&gt;: 페이지를 요청한 시점부터 콘텐츠의 일부가 화면에 처음 표시되는 시점까지의 시간&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4lprgv9fqjzwkemengt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4lprgv9fqjzwkemengt.png" alt="FCP" width="799" height="310"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://web.dev/articles/fcp?hl=ko" rel="noopener noreferrer"&gt;https://web.dev/articles/fcp?hl=ko&lt;/a&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LCP (Largest Contentful Paint)&lt;/strong&gt;: 페이지를 요청한 시점부터 주요 콘텐츠(가장 큰 이미지나 텍스트 블록)가 화면에 표시되는 시점까지의 시간&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4key0rsohtrio6gd7u2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4key0rsohtrio6gd7u2.png" alt="LCP" width="799" height="310"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://web.dev/articles/lcp?hl=ko" rel="noopener noreferrer"&gt;https://web.dev/articles/lcp?hl=ko&lt;/a&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CSR과 SSR 지표 비교
&lt;/h3&gt;

&lt;h4&gt;
  
  
  실험 설계
&lt;/h4&gt;

&lt;p&gt;이 글의 측정 결과는 아래 조건의 데모 앱을 기반으로 합니다. (&lt;a href="https://github.com/o5sy/blog/tree/main/web/csr_vs_ssr/demo" rel="noopener noreferrer"&gt;소스코드&lt;/a&gt;)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;스택&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CSR&lt;/td&gt;
&lt;td&gt;React 19 + Vite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSR&lt;/td&gt;
&lt;td&gt;Next.js 16 App Router (dynamic SSR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API 서버&lt;/td&gt;
&lt;td&gt;Express, &lt;code&gt;GET /api/posts?delay=&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;두 앱 모두 같은 API 서버를 바라보며, &lt;code&gt;delay&lt;/code&gt; 쿼리 파라미터로 응답 지연 시간을 조절할 수 있습니다. 렌더링 방식별 차이를 명확히 드러내기 위해 2000ms의 지연을 의도적으로 설정했습니다.&lt;/p&gt;

&lt;h4&gt;
  
  
  CSR
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6gyke9cvz08ugjo5qqsm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6gyke9cvz08ugjo5qqsm.png" alt="CSR LCP 퍼포먼스 타임라인" width="800" height="587"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuozmas2i29z2rwyl6z19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuozmas2i29z2rwyl6z19.png" alt="CSR 타임라인 그래프" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;지표&lt;/th&gt;
&lt;th&gt;시간&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TTFB&lt;/td&gt;
&lt;td&gt;13ms&lt;/td&gt;
&lt;td&gt;빈 HTML을 즉시 반환하므로 매우 빠릅니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FCP&lt;/td&gt;
&lt;td&gt;516ms&lt;/td&gt;
&lt;td&gt;HTML 수신 → JS 요청 → JS 실행 → DOM 조작 순서를 거쳐야 첫 콘텐츠가 표시됩니다. JS 번들이 커질수록 길어질 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LCP&lt;/td&gt;
&lt;td&gt;2.52s&lt;/td&gt;
&lt;td&gt;JS 실행 이후 API를 호출하기 때문에, API 지연(2000ms)이 그대로 반영됩니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;TTFB가 매우 빠르고, FCP는 JS 처리 시간만큼, LCP는 API 지연까지 더해져 느려집니다.&lt;/p&gt;

&lt;p&gt;일반적으로 LCP의 체감 시간을 줄이기 위해 로딩 UI(스켈레톤, 스피너 등)를 표시합니다.&lt;/p&gt;

&lt;h4&gt;
  
  
  SSR
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsn7jn3wyczxp1zu4z0ie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsn7jn3wyczxp1zu4z0ie.png" alt="SSR LCP 퍼포먼스 타임라인" width="800" height="587"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrkey8xyijnf9cyxsnmh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrkey8xyijnf9cyxsnmh.png" alt="SSR 타임라인 그래프" width="800" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;지표&lt;/th&gt;
&lt;th&gt;시간&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TTFB&lt;/td&gt;
&lt;td&gt;2.02s&lt;/td&gt;
&lt;td&gt;정적 SSR에선 빠르지만, 동적 SSR에서 데이터 fetch 등 작업이 많을수록 느려질 수 있습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FCP&lt;/td&gt;
&lt;td&gt;2.42s&lt;/td&gt;
&lt;td&gt;HTML을 받으면 바로 콘텐츠를 표시할 수 있어, TTFB 직후 빠르게 렌더링됩니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LCP&lt;/td&gt;
&lt;td&gt;2.42s&lt;/td&gt;
&lt;td&gt;주요 콘텐츠가 이미 HTML에 포함되어 있어 FCP와 거의 동시에 표시됩니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;FCP와 LCP가 빠른 대신 TTFB가 서버 처리 속도에 영향을 받아 느려질 수 있습니다.&lt;/p&gt;

&lt;h3&gt;
  
  
  기준에 따른 비교 설명
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;TTFB 기준: 크게 차이 안나지만, 동적 SSR은 서버 작업이 길어질 경우 CSR보다 느려질 수 있습니다.&lt;/li&gt;
&lt;li&gt;FCP 기준: 일반적으로 SSR이 빠릅니다. 단, SSR의 TTFB가 CSR의 JS 처리 시간보다 길면 역전될 수 있습니다.&lt;/li&gt;
&lt;li&gt;LCP 기준: 일반적으로 SSR이 빠릅니다. CSR에서 주요 콘텐츠가 초기 렌더링에 포함되지 않는다면 워터폴로 인해 늦어질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  마무리
&lt;/h2&gt;

&lt;p&gt;이제 렌더링 방식의 속도를 기준점에 따라 명확하게 설명할 수 있게 됐습니다.&lt;/p&gt;

&lt;p&gt;"CSR이 초기 로딩이 느리다"는 것도 HTML 응답부터 첫 콘텐츠 렌더링에 걸린 시간(FCP에서 TTFB를 뺀 시간)으로 보면 그렇다고 할 수 있습니다. 돌아보면 이 말이 드러내고자 했던 건 CSR에 JS 처리 과정이 있다는 점이라고 생각됩니다. 충분한 맥락과 기준점 없이 쓰이다 보니 헷갈리는 요소가 된 것입니다.&lt;/p&gt;

&lt;p&gt;"CSR은 초기 로딩 느림, SSR은 빠름"으로만 기억한다면 초기 로딩이 느릴 때 렌더링 방식을 바꾸는 것만을 떠올리게 됩니다. 하지만 세부 맥락을 이해하면 원인을 좁혀 다양한 최적화 방안을 고려할 수 있습니다.&lt;/p&gt;

&lt;p&gt;TTFB가 느리다면 CDN과 캐싱 전략을, FCP가 느리다면 코드 스플리팅과 번들 사이즈 최적화 등을 검토할 수 있습니다.&lt;/p&gt;

&lt;p&gt;이처럼 일반적인 사실을 그대로 받아들이기보다 숨겨진 맥락을 파악하는 게 중요합니다. 그래야 문제가 생겼을 때 적합한 선택지를 고를 수 있기 때문입니다.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;참고&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://prismic.io/blog/client-side-vs-server-side-rendering" rel="noopener noreferrer"&gt;Client-side vs. Server-side Rendering&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://lurgi.github.io/Development/Enhancing-UX-with-SSR" rel="noopener noreferrer"&gt;SSR로 사용자 경험 향상시키기&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://hwanheejung.tistory.com/67" rel="noopener noreferrer"&gt;리액트의 렌더링 전략&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/vitals?hl=ko" rel="noopener noreferrer"&gt;Web Vitals — web.dev&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/articles/ttfb?hl=ko" rel="noopener noreferrer"&gt;Time to First Byte (TTFB)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/articles/fcp?hl=ko" rel="noopener noreferrer"&gt;First Contentful Paint (FCP)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/articles/lcp?hl=ko" rel="noopener noreferrer"&gt;Largest Contentful Paint (LCP)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://theodorusclarence.com/blog/nextjs-fetch-method" rel="noopener noreferrer"&gt;Understanding Next.js Data Fetching (CSR, SSR, SSG, ISR)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://theodorusclarence.com/blog/nextjs-fetch-usecase#introduction" rel="noopener noreferrer"&gt;How to choose between Next.js CSR, SSR, SSG, and ISR&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
