<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>soap.log</title>
        <link>https://velog.io/</link>
        <description>치열하게 살지는 않아도 후회되는 순간은 만들지 말자</description>
        <lastBuildDate>Thu, 04 Dec 2025 12:35:07 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>soap.log</title>
            <url>https://velog.velcdn.com/images/lazy_hong/profile/cb921098-2321-42dd-acec-5502d294e7d5/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. soap.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/lazy_hong" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[패키지 매니저] npm, pnpm, yarn 사아알짝 보기]]></title>
            <link>https://velog.io/@lazy_hong/%ED%8C%A8%ED%82%A4%EC%A7%80-%EB%A7%A4%EB%8B%88%EC%A0%80-npm-pnpm-yarn</link>
            <guid>https://velog.io/@lazy_hong/%ED%8C%A8%ED%82%A4%EC%A7%80-%EB%A7%A4%EB%8B%88%EC%A0%80-npm-pnpm-yarn</guid>
            <pubDate>Thu, 04 Dec 2025 12:35:07 GMT</pubDate>
            <description><![CDATA[<p>리액트 기초 다질 겸 과제도 준비할 겸 블로그를 하나 만들고 있는데
npm install 하다가.. 내가 패키지 매니저에 대해서 공부를 제대로 한 적이 있던가..? 라는 생각을 하며 정리해보려고 한다. 
공부하다보니 최근 프로젝트에서 package-lock.json 파일 때문에 고생을 한 것이 사실은 기본적인게 개념이 안 잡혀 있어서 그랬다는 걸 깨달은 건 안 비밀...입니다.</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/5756089b-e214-4a5b-873d-c1051091e1b7/image.png" alt=""></p>
<hr>
<br/>

<h2 id="패키지-매니저란">패키지 매니저란?</h2>
<blockquote>
<p>간단하게 말하면 버저닝 문제 해결사.</p>
</blockquote>
<p>모든 사람이 같은 버전을 쓰면 좋으련만,, 언제 설치했는지 어떤 네트워크 환경인지에 따라 쓰는 버전이 다르다. 모든 개발자가 독같은 버전을 설치하게 만들자! 가 목적</p>
<pre><code>{
  &quot;dependencies&quot;: {
    &quot;react&quot;: &quot;^18.2.0&quot; 
  }
}</code></pre><p><code>^</code> 이 붙으면 18.x.x 버전 전부 가능하다. 이렇게 명시가 되어 있다면 앞서 말했든지 사용하는 사람마다 다른 버전이 설치될 수 있다.</p>
<h3 id="패키니-매니저-종류--npm-pnpm-yarn">패키니 매니저 종류 : npm, pnpm, yarn</h3>
<p>lock 파일을 보면 어떤 패키지 매니저를 사용하는지 알 수 있다.
<img src="https://velog.velcdn.com/images/lazy_hong/post/ca76bc7c-399e-4fb2-a152-1a734d80e651/image.png" alt=""></p>
<p>npm만 스크립트 실행문이 다르다. 다만 기본적인 </p>
<pre><code>start, test, stop, restart</code></pre><p>는 run 없이 실행
<img src="https://velog.velcdn.com/images/lazy_hong/post/e2bbf5b2-84d0-46a4-8b2e-d2831efb4aba/image.png" alt=""></p>
<br/>

<hr>
<br/>

<h2 id="패키지-매니저가-동작하는-3가지-단계">패키지 매니저가 동작하는 3가지 단계</h2>
<blockquote>
<p>Resolution, Fetch, Link</p>
</blockquote>
<h3 id="resolution">Resolution</h3>
<p>1) 의존성 버전 고정
2) 의존성의 의존성도 고정
3) 그 결과를 파일(lock 파일) 에 저장</p>
<p>npm : package-lock.json
pnpm : pnpm-lock.yaml
yarn : yarn.lock</p>
<h3 id="fetch">Fetch</h3>
<p>Resolution의 결과로 결정된 버전을 실제로 다운로드 하는 과정</p>
<h3 id="link">Link</h3>
<p>Resolution, Fetch 된 라이브러리를 소스코드에서 사용할 수 있는 환경을 제공하는 과정으로 설치한 의존성을 import 할 수 있도록 하는 것이다.</p>
<p>Link 방식이 3가지 패키지 매니저마다 다르다.</p>
<p>패키지 매니저 | Linker 방식    | 설명 | 생성 파일
| --- | --- | --- | --- |
npm    | npm Linker |node_modules에 실제 파일을 복사해 설치|package-json.lock
pnpm | pnpm Linker    | Hard Link(Copy-on-write) 기반, 용량/속도 최적화 | pnpm-lock.yaml
Yarn v1 (Classic)| node_modules Linker|    npm과 동일 방식(호환성 우수) | yarn.lock
Yarn v2+ (Berry)|    PnP (Plug’n’Play)|    node_modules 없이 Map 기반으로 의존성 관리 | yarn.lock , yarnc.yaml, pnp.cjs</p>
<ul>
<li>npm은 하나의 책을 사람들이 사용하기 위해 전부 다 복사본을 만들어서 책을 보는 것</li>
<li>pnpm은 하나의 책을 접속하는 링크를 생성해서 그 책을 보는 것</li>
<li>yarn은 도서 DB에서 책 위칫값만 관리하여 필요할 때 즉시 제공 </li>
</ul>
<p>이라고 비유를 하면 그렇다.</p>
<hr>
<p>이러한 3단계의 과정 때문에 우리는 버전이 다른 팀원과 협업할 수 있는 것이다. </p>
<p>아까 .. 고생은.. 사실 나름 1시간동안 팀원과 고민했던 것이였는데 pull받고 merge 해서 lock 파일도 동일한데 실행하면 충돌/오류가 나는 문제가 있었다. 그렇다고 ignore 파일에 package-lock.json 넣는 것도 말도 안되는 상황이였다.</p>
<p>사실 우린 변경사항만 다운로드 한 것이지, 실제 설치된 패키지를 업데이트 한 것이 아니였다. 
<code>npm install -&gt; npm run ~</code>  </p>
<p>최신 의존성 설치 이후 실행하자는 패키지 관리 워크플로우를 얻는 경험이였다. 기본에 충실하자.</p>
<br/>
<br/>

<p><img src="https://velog.velcdn.com/images/lazy_hong/post/40fad088-7811-4fd6-ac48-d97caaccada4/image.png" alt=""></p>
<br/>

<p><a href="https://young-taek.tistory.com/366">캡처 이미지 자료 : https://young-taek.tistory.com/366</a>
<a href="https://toss.tech/article/lightning-talks-package-manager">토스 테크 블로그 : 패키지 매니저</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘 개념 간단 정리 + 푸는 법 (코테 준비 참 빨리하네요..)]]></title>
            <link>https://velog.io/@lazy_hong/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%9C%EB%85%90-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC-%ED%91%B8%EB%8A%94-%EB%B2%95-%EC%BD%94%ED%85%8C-%EC%A4%80%EB%B9%84-%EC%B0%B8-%EB%B9%A8%EB%A6%AC%ED%95%98%EB%84%A4%EC%9A%94</link>
            <guid>https://velog.io/@lazy_hong/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EA%B0%9C%EB%85%90-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC-%ED%91%B8%EB%8A%94-%EB%B2%95-%EC%BD%94%ED%85%8C-%EC%A4%80%EB%B9%84-%EC%B0%B8-%EB%B9%A8%EB%A6%AC%ED%95%98%EB%84%A4%EC%9A%94</guid>
            <pubDate>Fri, 14 Nov 2025 06:54:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/10cfed39-9c98-46cb-a90e-bb0afacc59c7/image.png" alt=""></p>
<p>이번년도를 잘 마무리하자.</p>
<h2 id="그래프-탐색">그래프 탐색</h2>
<blockquote>
<p>DFS (Dept First Search) : 깊이 우선 탐색
BFS (Bredth First Search) : 넓이 우선 탐색</p>
</blockquote>
<p>깊이 우선 탐색 == 드라마 마지막화까지 나오길 기다렸다가 정주형
넓이 우선 탐색 == 여러 드라마를 1-2화씩 보기</p>
<p>라고 생각하면 좋다</p>
<h3 id="그래프란">그래프란?</h3>
<p> &quot;<strong>정점(vertex)</strong>과 이 정점들을 연결하는 <strong>간선(edge)</strong>으로 구성된 자료구조&quot;</p>
<p>=&gt; 따라서 여러개체 중에 1개의 개체를 찾는 문제라면 그래프 탐색 알고리즘이다! 까지 가면 좋다</p>
<blockquote>
</blockquote>
<p>✅ A -&gt; B까지 가는데 최소 거리, 최소 시간 구하는 : <strong>경로 탐색</strong>
✅ 여러 개체들이 주어진 상태에서 연결되어 있는 그룹의 개수 구하기 : <strong>네트워크연결</strong>
✅ <strong>조합 유형</strong></p>
<br/>

<h3 id="구현방법">구현방법</h3>
<p>DFS : 재귀함수</p>
<p>BFS : Queue / LinkedList</p>
<h3 id="dfs-vs-bfs">DFS vs BFS</h3>
<p>우선, DFS로 간다.
DFS는 중간에 틀린 것 찾기가 쉽기 때문이다.</p>
<p>그렇지만, 최악의 경우 모든 조합을 다 봐야하는 수가 생길 수도 있다.
그리고 DFS를 할 때 각각의 조합이 너무 오래 걸리게 되면 BFS로 가야한다.</p>
<p>문제가 앞쪽+쉬움 =&gt; DFS, 뒤쪽+어려움 =&gt; BFS</p>
<h3 id="공부-방법">공부 방법</h3>
<p>한 문제를 DFS, BFS 두 문제로 다 풀어보기</p>
<hr>
<h2 id="dp--다이나믹-프로그래밍">DP : 다이나믹 프로그래밍</h2>
<p>DP를 쓰게 된 배경부터 보자면,,,
DFS, BFS로 풀기에는 경우의 수가 너무 많은 문제를 해결하기 위해서 나온 것이다.</p>
<p>DP의 목적은 연산결과를 저장해서 중복연산을 줄이기 위함이기 때문에, 연산을 다시 하지 않으면서 어떤 식으로 정보를 누적해야 되는지 고민을 해야 한다.
같은 말로 <strong>어떤 정보를 담아야 이전 단계로 돌아가지 않는가</strong>!</p>
<h3 id="공부-방법-1">공부 방법</h3>
<ol>
<li>30분 동안 고민</li>
<li>안되면 다른 사람 풀이 참고해서 구현만</li>
</ol>
<hr>
<h2 id="그리디-탐욕-알고리즘">그리디 (탐욕 알고리즘)</h2>
<p>: 미래를 고려하지 않고 오직 현재 시점에 가장 좋은 선택을 한다.</p>
<p>그렇기 때문에.. 항상 최적이 보장되어야 하는 코테에서는 <strong>2가지 조건</strong>을 모두 만족해야 사용할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/2b9e8fff-511f-47de-86fc-412e81ebda9a/image.png" alt=""></p>
<h4 id="조건1--현재의-선택이-미래의-선택에-영향을-주지-않는다">조건1 : 현재의 선택이 미래의 선택에 영향을 주지 않는다.</h4>
<p>A 에서 B까지 가는 경로 2개 중 어떤 걸 선택해도 B에서 C를 선택하는 것에 영향을 주지 않는다.</p>
<h4 id="조건2--부분의-최적-해가-모이면-전체-최적-해가-된다">조건2 : 부분의 최적 해가 모이면, 전체 최적 해가 된다.</h4>
<p>(전체) <strong>A에서 C까지</strong> 가는데 최소 시간을 구해라! 라는 문제이면 </p>
<p>(부분) A에서 B 최소 시간 + (부분) B에서 C 최소 시간 = (전체) A 에서 C 최소 시간</p>
<p>이 되는 문제 같은 경우를 말한다.</p>
<h3 id="구현-방법">구현 방법</h3>
<p>목적 : 어떻게 정렬을 해야 위의 두 가지 조건을 만족할 수 있을까를 생각해야 한다.</p>
<h3 id="문제">문제</h3>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/f7417b69-5dbb-4596-aba5-0d228c0275ce/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SOLID 원칙 중 SRP(Single Responsibility Principle)]]></title>
            <link>https://velog.io/@lazy_hong/SOLID-%EC%9B%90%EC%B9%99-%EC%A4%91-SRPSingle-Responsibility-Principle</link>
            <guid>https://velog.io/@lazy_hong/SOLID-%EC%9B%90%EC%B9%99-%EC%A4%91-SRPSingle-Responsibility-Principle</guid>
            <pubDate>Wed, 12 Nov 2025 08:22:19 GMT</pubDate>
            <description><![CDATA[<p><a href="https://tech.kakaoent.com/front-end/2023/230330-frontend-solid/">카카오 TECH BLOG : 프론트엔드와 SOLID</a></p>
<p>** 위의 글은 실무레벨로 다시 용어를 적립한 글이여서 매우 많이 참고하여 적는다. 그렇기 때문에 상단에 박제하겠다.</p>
<p>일단 공통 컴포넌트의 기준을 정할때 경계를 명확히하기 전에 SRP(Single Responsibility Principle) : 단일 책임 원칙에 대해서 명확하게 하고 갈 필요가 있어서 정리하게 되었다.</p>
<blockquote>
<p>“SOLID 원칙 중에서 그 의미가 가장 잘 전달되지 못한 원칙은 바로 단일 책임 원칙(SRP)이다. 아마도 현저히 부적절한 이름 때문이기도 할 것이다.” - 로버트 C. 마틴(클린 아키텍처)</p>
</blockquote>
<br/>

<p><img src="https://velog.velcdn.com/images/lazy_hong/post/f478b5a8-55e9-45da-938f-cb6434656bfc/image.png" alt=""></p>
<br/>

<h2 id="🍋-srp--single-responsibility-principle">🍋 SRP : Single Responsibility Principle</h2>
<p>: 콘웨이 법칙에 입각해 소프트웨어 구조를 조직의 커뮤니케이션 구조와 유사하게 만들 수 있도록 도와주는 원칙이다.</p>
<blockquote>
<p>SOLID 원칙의 대전제 : 콘웨이 법칙
소프트 웨어 구조는 해당 소프으퉤어를 개발한 조직의 커뮤니케이션 구조와 같아야 한다.</p>
</blockquote>
<br/>

<h3 id="1-단일-책임-원칙은-단일-동작-원칙이-아님">1. 단일 [책임] 원칙은 단일 [동작] 원칙이 아님</h3>
<p>컴포넌트를 동작으로 쪼개면 기준이 애매하고 자잘하게 컴포넌트가 쪼개질 수 있다.
<strong>단일한 동작을 가지는 것은 컴포넌트가 아니라 순수한 함수 한정</strong>이다.</p>
<blockquote>
<p>“SRP의 최종 버전은 다음과 같다. 하나의 모듈은 하나의, 오직 하나의 액터에 대해서만 책임져야 한다.” - 로버트 C. 마틴(클린 아키텍처)</p>
</blockquote>
<p>모듈 ==  컴포넌트
액터 == 사용자 또는 책무 단위</p>
<p><strong>🔥 즉, SRP 원칙을 지킨다는 것은 컴포넌트를 설계할 때 <code>요구사항을 전달하는 책무단위</code>로 설계한다</strong></p>
<br/>

<h3 id="2요구사항을-전달하는-책무-기반-컴포넌트-설계">2.<code>요구사항을 전달하는 책무</code> 기반 컴포넌트 설계</h3>
<p>글을 정리하면서 제일 어려웠던 부분이였다.</p>
<blockquote>
<p>컴포넌트의 경계는 그 컴포넌트가 감당해야할 변경의 범위와 일치해야한다.</p>
</blockquote>
<p><del>기획과 디자인 조직이 분리되어 있다면, 해당 책임을 서로 다른 컴포넌트로 분리하고, 반대로 디자이너가 기획까지 수행하는 조직(내가 리팩토링을 할려는 프로젝트)이라면, UI와 비즈니스 규칙이 결합된 컴포넌트로 해도 무방하다.</del> </p>
<p><del>조직 구조에 따라 컴포넌트의 경계가 달라진다는 말로 나는 이해를 했다.</del></p>
<p>위와 같은 이론이라면 팀의 구조가 바뀌면 이전에 짰던 컴포넌트들이 SRP 원칙에 위반된다는 말에 더 가깝다. 다시 정리를 해보자면</p>
<p><strong>컴포넌트의 경계</strong> = 변경의 이유(Responsibility)
즉, 컴포넌트가 언제 수정되어야 하는가를 기준으로 나눠야한다는 뜻이다.</p>
<p>피드백의 예시를 그대로 쓰자면,</p>
<pre><code>// A 컴포넌트: a 비즈니스 로직 전담
function AComponent() {
  const data = useALogic(); // a 관련 로직만 수행
  return &lt;AView data={data} /&gt;;
}</code></pre><p>❌ 잘못된 경우</p>
<pre><code>// A 컴포넌트 내부에서 a와 b 로직을 모두 처리
function AComponent() {
  const aData = useALogic();
  const bData = useBLogic(); // b 비즈니스 로직까지 함께 수행
  return &lt;AView aData={aData} bData={bData} /&gt;;
}</code></pre><p>b 로직이 바뀌면 A도 수정해야 함
→ “A는 a 비즈니스만 책임진다”는 단일 책임 원칙(SRP)을 깨트림
→ 즉, A가 b의 책무까지 침범한 것</p>
<h3 id="✅-예시1">✅ 예시1</h3>
<p>책임: 데이터가 어떤 디자인과 연결될지, 화면 단위 컴포넌트 구조 정의
<strong>변경 이유: 기획/UX 변경</strong></p>
<pre><code>function SingleSection({ title, more, items }) {
    return (
        &lt;Section&gt;
            &lt;Section.Title title={title} /&gt;
            &lt;Section.More text={more} /&gt;
            &lt;Section.SingleListView items={items} /&gt;
        &lt;/Section&gt;
    );
}</code></pre><p>테스트 예시: 기획서 제약사항 검증</p>
<pre><code>describe(&#39;Section.Title&#39;, () =&gt; {
    it(&#39;섹션 타이틀은 최대 15자 이내로 보여져야 합니다&#39;, () =&gt; {
        const title = &quot;15자가 넘으면 15자까지만 보여집니다.&quot;;
        const { getByText } = render(&lt;Section.Title title={title} /&gt;);
        expect(getByText(title.substring(0, 15))).toBeInTheDocument();
    });
});</code></pre><h3 id="✅-예시2">✅ 예시2</h3>
<p>책임: 시각 요소, 레이아웃, 패딩, 마진, 색상 등
<strong>변경 이유: UI/디자인 정책 변경</strong></p>
<pre><code>// Atom: BaseButton
function BaseButton({ children, className, onClick }) {
  return &lt;button className={`base-button ${className}`} onClick={onClick}&gt;{children}&lt;/button&gt;;
}

// Molecule: BrandButton
function BrandButton({ brand, children, onClick }) {
  const styles = {
    naver: &quot;bg-[#03c75a] text-white&quot;,
    kakao: &quot;bg-[#fee500] text-[#3c1e1e]&quot;,
    google: &quot;bg-white border text-gray-700&quot;,
  };
  return &lt;BaseButton className={styles[brand]} onClick={onClick}&gt;{children}&lt;/BaseButton&gt;;
}</code></pre><h3 id="✅-예시3">✅ 예시3</h3>
<p>책임: API 호출, 상태 관리, 로직 처리
<strong>변경 이유: 서비스 정책/비즈니스 로직 변경</strong></p>
<pre><code>// Hook 기반 로그인 로직
function useLogin() {
    const [loading, setLoading] = useState(false);
    const login = async (credentials) =&gt; {
        setLoading(true);
        await authApi.login(credentials);
        setLoading(false);
    };
    return { login, loading };
}

// 화면에서 훅과 UI 연결
function LoginButton({ brand }) {
    const { login, loading } = useLogin();
    return &lt;BrandButton brand={brand} onClick={() =&gt; login({})} /&gt;;
}</code></pre><p>SRP 기준: 화면 단위 컴포넌트는 “UI + 훅 연결” 역할만</p>
<h4 id="각각의-예시들의-변경-이유외에-다른-이유로-컴포넌트를-변경해야한다면-srp-위반이다">각각의 예시들의 변경 이유외에 다른 이유로 컴포넌트를 변경해야한다면 SRP 위반이다.</h4>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/d9b6860d-0630-4b45-9795-b1e05320893b/image.png" alt=""></p>
<p>위의 글을 보면 아토믹 디자인 개념을 사용해서 각 컴포넌트가 하나의 역할만 하도록 정리할 수 있고 이렇게 하면 디자이너와 개발자가 같은 단위(컴포넌트)를 기준으로 이야기할 수 있게 된다고하고 디자인 컴포넌트와 1:1 매칭을 할 수 있게 된다고 한다.</p>
<p>즉, 디자인의 최소단위와 코드의 최소 단위를 똑같이 맞춘다는 뜻이다. 이렇게 되면 디자이너와 개발자가 같은 기준으로 소통이 가능하다는 장점이 있는 것이다.</p>
<br/>

<h3 id="3-아토믹-디자인이란">3. 아토믹 디자인이란</h3>
<p> 컴포넌트를 atom, molecule, organism, template, page의 5가지 레벨로 나누는 것
 <img src="https://velog.velcdn.com/images/lazy_hong/post/b370569c-5526-45fd-9e60-45818f18ef4c/image.png" alt="">
<img src="https://velog.velcdn.com/images/lazy_hong/post/04430fdd-ee5b-4ede-984a-99452ce85fe6/image.png" alt=""></p>
<ol>
<li><p>Atom : 더 이상 분해할 수 없는 기본 컴포넌트
<img src="https://velog.velcdn.com/images/lazy_hong/post/1a66b706-a10d-4fee-b2dd-b9e6b8cb9357/image.png" alt=""></p>
</li>
<li><p>Molecule : 여러개의 atom으로 결합하여 고유한 특성을 가지는 것
<img src="https://velog.velcdn.com/images/lazy_hong/post/8c4c6eb6-e85a-4be8-8fa0-b6b92a0f7545/image.png" alt=""></p>
</li>
<li><p>Organism : 여러개의 atom, moluecule, organism
<img src="https://velog.velcdn.com/images/lazy_hong/post/52b7a9c3-2c2c-40be-9ee0-7c6feea1e9bc/image.png" alt=""></p>
</li>
</ol>
<p>위의 예시는 header organism인데
로고: atom + 네비게이션 : moluecule + search form : moluecule 로 구성되어 있다.</p>
<ol start="4">
<li>Template : 여러개의 organism과 molecule로 구성</li>
<li>Page: 유저가 볼 수 있는 실제 콘텐츠를 담고 있음</li>
</ol>
<br/>
<br/>

<h2 id="🍋-but">🍋 But,,,</h2>
<p>동작 단위가 아니라 책무 단위까지라는 말은 위의 글을 통해서 이해를 했다. 카카오 테크 블로그 컴포넌트 관련 다른 글을 읽어도 폴더가 
이렇게 아토믹 디자인 단위: atom &gt; molecules &gt; organisms &gt; template &gt; page 순으로 되어 있는데</p>
<pre><code>components/
 ┣ atoms/
 ┃ ┗ Button.tsx
 ┣ molecules/
 ┃ ┗ SearchBar.tsx
 ┣ organisms/
 ┃ ┗ Header.tsx
 ┣ templates/
 ┃ ┗ MainLayout.tsx
 ┗ pages/
   ┗ HomePage.tsx
</code></pre><p>이런 구조는 사실 대규모 디자인 시스템 팀이나 토스,네이버,카카오 같은 조직형 아키텍처에서 가능한 방식인 것 같다. 대규모 디자인 시스템 프로젝트가 아닌 소규모 프로젝트를 자주 경험한 나로서는 오히려 디자인 단위와 코드 단위가 1:1로 맞추는 건 이론적인 이야기인 것 같다. 왜냐면, 프론트하면서 제가 디자인까지 담당하기 때문이죠..</p>
<p>여기서 요점은 SRP는 단위책임원칙에서 책임은 동작단위가 아니라는 것!! <strong>책무 단위</strong>라는 것이다. 위의 디자인 단위와 코드 단위를 1:1로 맞추는 경험을 나도 하고 싶지만,, 내가 속한 상황에서는 <strong>책임이 다르고, 변경 주기가 다를 때만 파일을 나눈다</strong>로 해야한다.</p>
<pre><code>components/
 ┣ common/
 ┃ ┣ Button.tsx  // Atom
 ┃ ┗ Input.tsx   // Atom
 ┣ layout/
 ┃ ┗ Header.tsx  // Organism
 ┗ pages/
   ┗ Home.tsx     // Page
</code></pre><p>요로콤..</p>
<h3 id="그러면-현실적으로-소규모-프로젝트에서-위의-관점을-대입해서-할-수-있는-방향은">그러면 현실적으로 소규모 프로젝트에서 위의 관점을 대입해서 할 수 있는 방향은?</h3>
<blockquote>
<p>필요할 때만 분리하고, 변경 주기가 다를 때만 파일로 나눈다.
Organism 단위 + common 폴더 구조로 간다.</p>
</blockquote>
<p><strong>&gt;&gt; Atomic의 개념은 유지하되 파일은 최소화하기</strong></p>
<p>나는 프로젝트할때 item &gt; box &gt; container &gt; section 으로 컴포넌트를 세분화 했었다. 아토믹 디자인과 명칭은 다르지만 단계가 같았다. 그러나 이를 나누는 기준을 명확하게 문서와하지 못 해 리팩토링 시 아토믹 디자인 정의 기준에 따라 명확하게 할 것이다. </p>
<pre><code>src/
 ┣ components/
 ┃ ┣ common/              ← Atom, Molecule 수준 (재사용 UI)
 ┃ ┃ ┣ Button.tsx
 ┃ ┃ ┣ Input.tsx
 ┃ ┃ ┗ Modal.tsx
 ┃ ┣ layout/              ← Organism 수준 (헤더, 푸터, 사이드바 등)
 ┃ ┃ ┣ Header.tsx
 ┃ ┃ ┗ Footer.tsx
 ┃ ┣ sections/            ← 페이지 내 큰 블록 (Organism)
 ┃ ┃ ┣ ProfileSection.tsx
 ┃ ┃ ┣ CoinChartSection.tsx
 ┃ ┃ ┗ RankingSection.tsx
 ┃ ┗ pages/               ← Template/Page 수준
 ┃   ┗ MyPage.tsx
 ┣ hooks/
 ┣ store/
 ┣ utils/
 ┗ styles/
</code></pre><br/>

<h3 id="이제-이-개념에-공통-컴포넌트-살짝-맛보기">이제 이 개념에 공통 컴포넌트 살짝 맛보기</h3>
<p>버튼을 예시로 가져와서 적용해보자.
버튼에는 종류가 두 가지가 있는데, 하나는 브랜드별 시각만 있는 버튼이고 다른 하나는 로그인 동작을 하는 버튼이다.</p>
<pre><code>1. BaseButton : 버튼의 기본 구조, 공통 스타일 제공 (padding, border, radius)
2. BrandButton : 브랜드별 시각적 스타일 책임 (color, logo, hover 색상)
3. ActionButton : (옵션)    기능적 상태 관리 (loading, disabled)</code></pre><h4 id="결론">결론</h4>
<p>BaseButton.tsx -&gt; <code>components/common/</code> (재사용 UI, Atom)
BrandButton.tsx -&gt; <code>components/common/brand/</code> (공통 UI의 파생 스타일, Molecule)
ActionButton.tsx -&gt; <code>features/auth/</code> OAuth 로직까지 포함한 “로그인 버튼”(토큰 처리, 중복클릭 방지, 로딩 등) 도메인 폴더로</p>
<pre><code>src/
 ┣ components/
 ┃ ┗ common/
 ┃    ┣ BaseButton.tsx            ← 공통 버튼(Atom)
 ┃    ┣ brand/
 ┃    ┃  ┣ BrandButton.tsx        ← 브랜드 스타일만 책임(Molecule)
 ┃    ┃  ┗ brandTokens.ts         ← 브랜드 색/로고 토큰
 ┃    ┗ ...
 ┗ features/
    ┗ auth/
       ┗ OAuthLoginButton.tsx      ← OAuth 로직(도메인) 포함
</code></pre><br/>
<br/>

<p><a href="https://tech.kakaoent.com/front-end/2022/220505-how-page-part-use-atomic-design-system/">카카오 TECH BLOG : 아토믹 디자인</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[재사용만이 가치 있는 공통 컴포넌트 일까?]]></title>
            <link>https://velog.io/@lazy_hong/%EA%B0%80%EC%B9%98-%EC%9E%88%EB%8A%94-%EA%B3%B5%ED%86%B5-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@lazy_hong/%EA%B0%80%EC%B9%98-%EC%9E%88%EB%8A%94-%EA%B3%B5%ED%86%B5-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 10 Nov 2025 05:08:08 GMT</pubDate>
            <description><![CDATA[<p>과거(이글을 쓰기 10분 전)의 무지한 저는 말이죠..
하나의 제대로 된 컴포넌트를 만능으로 만들어서 재사용할 수 있다고 믿었고, 그렇게 하고 싶었습니다. 그리고 공통 컴포넌트는 재사용을 위한 것이다 라고만 생각했구요.. 하핳</p>
<p>그럼 어떻게 되냐.. props로 디테일한 걸 다 받아야 해요.
다행인지 아닌지 최근 프로젝트에서는 2-3개정도만 추가해서 끝났지만, 만약 회사 같이 어떤 요구사항이 어떤식으로 추가될지 모르는 상황 속에선 전 무능력한 자입니다.</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/728358db-b4c4-4c0e-bc19-46ad567980b0/image.png" alt=""></p>
<h2 id="들어가기-전에">들어가기 전에..</h2>
<blockquote>
<p>(단일 책임 원칙)&gt; 확장 규칙 설계 &gt; 네이티브 요소의 활용 &gt; 웹 접근성</p>
</blockquote>
<p>여기서 요점은 공통 컴포넌트가 단지 재사용을 하기 위한 컴포넌트가 아니라 위의 3가지를 활용하여 완성도 있는 컴포넌트를 만들어야 한다는 것이다.</p>
<p>아래의 링크를 통해 단일 책임 원칙 글을 미리 보고 오면 좋을 것 같다.</p>
<p><a href="https://velog.io/@lazy_hong/SOLID-%EC%9B%90%EC%B9%99-%EC%A4%91-SRPSingle-Responsibility-Principle">단일 책임 원칙 글</a></p>
<h2 id="1-확장-규칙-설계">1. 확장 규칙 설계</h2>
<p>내가 공통 컴포넌트를 정하는 기준은 &quot;두 군데 이상에서 반복&quot; 이였다. </p>
<p><strong>[반복]</strong> 된다는 이 기준은 명확한 것인가? 
디자인과 안의 구성 패턴이 같으면 반복되는 것이라고 볼 수 있는가? 
아니면 디자인 + margin/padding 까지 고려해야 하는가? 
아니면 디자인 + margin/padding + 부모요소 + 사용하는 함수?</p>
<p>프로젝트 할 때, 처음에는 디자인과 안의 구성 패턴이 같아서 공통 컴포넌트로 뒀는데 아니였다. 작은 차이는 영향이 없을 거라고 생각했는데,, 부모요소의 <code>position</code> 에 따라 <code>margin/padding</code> 이 달라지고 폰트가 바뀌고 개발하다가 추가 되는 기능들로 인해 추가되는 함수가 생겨버려서 prop에 점점 디테일한 요소가 추가된 결론까지 도달 했다.</p>
<p>유지보수를 위한 공통 컴포넌트가 유지보수성이 점점 떨어진다는 결론에 도달..</p>
<h3 id="1-1-명확한-컴포넌트-역할을-정하기-단-만능은-없다">1-1. 명확한 컴포넌트 역할을 정하기 (단, 만능은 없다)</h3>
<blockquote>
<p>공통 컴포넌트 역할의 <code>경계</code>를 명확하게 하자</p>
</blockquote>
<p>내가 가져온 예시 코드들은 카카오 기술 블로그의 예시와 GPT에게 물어본 추가 코드들이다.
Bad Example은 내가 프로젝트에서 짠 코드다.ㅎ</p>
<p>암튼</p>
<p>공통 컴포넌트의 목적은 &quot;코드를 재사용해서 개발 속도와 유지보수를 쉽세 만드는 것&quot;이다.
그런데 너무 범용적으로 만들면, 매번 많은 props를 줘야 해서 복잡해진다.</p>
<p>예시를 버튼으로 들어 역할을 나누면
<img src="https://velog.velcdn.com/images/lazy_hong/post/0f01568a-314f-4041-a65f-4b6f10c410ec/image.png" alt=""></p>
<h4 id="기본-버튼--구조만-잡기">기본 버튼 : 구조만 잡기</h4>
<pre><code>// BaseButton.tsx
import cn from &quot;classnames&quot;;

interface Props {
  className?: string;
  children: React.ReactNode;
}

export default function BaseButton({ className, children }: Props) {
  return &lt;button className={cn(&quot;base-button&quot;, className)}&gt;{children}&lt;/button&gt;;
}
</code></pre><h4 id="브랜드-버튼--기본--시각적인-역할">브랜드 버튼 : 기본 + 시각적인 역할</h4>
<pre><code>// BrandButton.tsx
import BaseButton from &quot;./BaseButton&quot;;

const brandStyles = {
  naver: &quot;bg-[#03c75a] text-white&quot;,
  kakao: &quot;bg-[#fee500] text-[#3c1e1e]&quot;,
  google: &quot;bg-white border text-gray-700&quot;,
};

interface BrandButtonProps {
  brand: keyof typeof brandStyles;
  children?: React.ReactNode;
  onClick?: () =&gt; void;
}

export default function BrandButton({ brand, children, onClick }: BrandButtonProps) {
  return (
    &lt;BaseButton onClick={onClick} className={brandStyles[brand]}&gt;
      {children || `${brand}로 로그인`}
    &lt;/BaseButton&gt;
  );
}
</code></pre><p>호출시</p>
<pre><code>&lt;BrandButton brand=&quot;naver&quot; /&gt;
&lt;BrandButton brand=&quot;kakao&quot; /&gt;
&lt;BrandButton brand=&quot;google&quot;&gt;Google Login&lt;/BrandButton&gt;
</code></pre><h4 id="액션-버튼--기본--로직처리">액션 버튼 : 기본 + 로직처리</h4>
<pre><code>// LoadingButton.tsx
export default function LoadingButton({ loading, children }) {
  return (
    &lt;BaseButton className=&quot;loading-btn&quot;&gt;
      {loading ? &quot;Loading...&quot; : children}
    &lt;/BaseButton&gt;
  );
}</code></pre><p><a href="https://tech.kakaoent.com/front-end/2024/240116-common-component/">https://tech.kakaoent.com/front-end/2024/240116-common-component/</a>
<a href="https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout">https://developer.apple.com/documentation/uikit/uicollectionviewcompositionallayout</a>
<a href="https://tech.kakaoent.com/front-end/2022/220505-how-page-part-use-atomic-design-system/">https://tech.kakaoent.com/front-end/2022/220505-how-page-part-use-atomic-design-system/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[현대카드를 내가 어쩌다 사용하게 되었나]]></title>
            <link>https://velog.io/@lazy_hong/PLCC-GPCC</link>
            <guid>https://velog.io/@lazy_hong/PLCC-GPCC</guid>
            <pubDate>Sun, 09 Nov 2025 06:15:07 GMT</pubDate>
            <description><![CDATA[<p>현재 나는 카드가 많을 일이 없는 취준생으로서 가지고 있는 카드가 4장 정도 있지만, 그 중에 2장은 현대카드다.</p>
<p>내가 어쩌다 현대카드를 두 장씩이나 가지고 있게 되었는지 생각해보자..</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/938dd8dd-b664-4da3-a656-3732cc349214/image.png" alt=""></p>
<p>하나는 The CJ-현대카드(M 시리즈)</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/349496de-3c3c-4bae-8149-51c6c61a5b53/image.png" alt=""> </p>
<p>다른 하나는 현대M 체크 카드
<img src="https://velog.velcdn.com/images/lazy_hong/post/11937ec1-d86e-427d-b04e-07ba7576a444/image.png" alt=""></p>
<p>The CJ는 올리브영 알바 당시(나름 정직원이라 신용카드 발급 가능) 결제를 할 때, 등급별 쿠폰보다 제휴카드 할인이 더 높은 것을 보고 발급한 카드다.</p>
<p>아 물론 등급별 쿠폰이 14% 이럴 때도 있다. 근데 6개월마다 등급이 바껴서 등급을 유지할려면 소비를 해야하는 무한굴레에 빠지고, 특정 세일때 나오는 한시적인 쿠폰이나 보니 예상치 못한 지출을 나가게 하는 주범이랄까..? 
제휴카드는 결제할때마다 10% 할인에 M포인트랑 CJ 포인트도 쌓이니깐 더 좋다고 판단하였고, CJ외식가맹점 이용시 할인도 많고 그리고.. 카드 디자인이 내 취향저격이였다. ㅎ</p>
<p>현대M 체크 카드는 Apple Pay 가능한 체크카드라서 발급했다. 진짜 한 줄로 끝이다.</p>
<h3 id="apple-pay">Apple Pay</h3>
<p>2020년 5월즘에 Apple Card를 PLCC(Private Label Credit Card)형태로 현대카드에서 도입될지도 모른다는 루머가 퍼졌다.
둘 다 사실무근.. 이라고 했지만, 카드 업계 이야기 중 Apple이 지난 5년간 국내 한 카드사와 지속적으로 협의를 진행했다는 사실이 밝혀졌다. 특정 카드사와만 파트너십을 맺는 일명 &#39;코스트코&#39; 방식이라는데, 그중에서 현대카드가 도입될 가능성이 높다고 했으나, 현대카드 측에서는 사실을 부인하며 전혀 논의된 사항이 없고, Apple Pay와 관련하여 밝힐 입장이 없다고 전해졌었다...</p>
<p>2022년 9월 오는 12월부터 편의점 등 60개 브랜드에서 Apple Pay를 사용할 수 있다는 기사가 보도되었다. 계약 체결을 위해 현대카드 정태영 대표이사 부회장이 직접 미국 Apple Park를 방문했다고 했으며, NFC 단말기 설치 비용의 60%를 현대카드가 부담을 한다는 이야기까지 나왔었다. </p>
<p>그렇지만 둘 다 난 몰라요..</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/6e2b6b29-943b-4bea-8d8c-70b76bc9641e/image.png" alt=""></p>
<p>암튼,, 2023년 2월 8일, 마침내 애플코리아와 현대카드는 Apple Pay를 한국에 출시할 예정이라고 공식적으로 밝혔다. 이때 대학교 3학년이였던 나도 수업 중에 옆자리 친구가 &quot;와.. 이제 휴대폰으로 결제된다 우리! 심지어 체크카드도 된데&quot; 라고 말했던 기억이 난다.</p>
<p>&quot;그럼 난 무조건 발급할거야&quot; 라고 대답까지 했다.</p>
<h3 id="현대카드가-plcc와-gpcc-분야를-모두-잘-해요">현대카드가 PLCC와 GPCC 분야를 모두 잘 해요..</h3>
<blockquote>
<p>현대카드는 최근 국내 대표 뷰티 플랫폼 올리브영과 함께한 ‘올리브영 현대카드’를 출시했다. 지난 2015년 ‘이마트e카드’로 국내에서 처음 PLCC를 선보인 현대카드는 이제 올리브영 등 19개 파트너사(社)와 제휴를 맺게 됐다. 올해 현재 현대카드는 국내 PLCC 발급 매수의 86%를 차지할 정도로 압도적 지위를 갖고 있다. 현대카드의 PLCC 회원 비중 역시 2018년 10%에서 올해 44%로 늘었다. -조선일보-</p>
</blockquote>
<p>정말~! PLCC와 GPCC 분야 모두 잘한다고 생각한다. 내가 PLCC(현대카드 X APPLE), GPCC(The CJ) 둘 다 가지고 있다..</p>
<p>PLCC(Private Label Credit Card·상업자 전용 신용카드)로 브랜드와 카드사가 1:1로 협업한 단독 브랜드 제휴 카드이다.
예를 들면, 현대카드 X 무신사 / 현대카드 X 배달의 민족 / 현대카드 X 올리브영 등이 있다. </p>
<p>현대카드 X APPLE은.. 애플카드 자체를 PLCC로 발급하고 있지는 않지만, 최초이기도 하고 단독이기 때문에 거의 PLCC 마케팅 전략이라고 봐도 무관하다고 본다.</p>
<p>GPCC(General Purpose Credit Card·범용 신용카드)로 복수 브랜드 혹은 제휴사들이 이용하는 일반 제휴카드이다. 여러 브랜드에서 혜택을 공유하거나 특정 그룹(예: CJ, SKT 등)에 속한 서비스 전반에 혜택 제공한다.</p>
<p>그러면 이쯤에서 궁금한게..</p>
<p>비은행권 회사인 현대카드는 어떤 전략으로 PLCC와 GPCC 분야까지 잘 하게 되었을까??</p>
<h3 id="다양한-업종을-아우름--카드-디자인">다양한 업종을 아우름 + 카드 디자인</h3>
<p>현대카드는 그동안 “어떤 브랜드들과 카드 제휴를 맺느냐”라는 전통적인 PLCC에서 한 발 더 나아가, 브랜드가 원하면서도 소비자들에게 매력적인 혜택을 정교하게 설계하는 방향으로 생태계를 확대해 왔다고 한다.</p>
<ul>
<li>다양한 업종을 아우르는 PLCC 전략</li>
<li>브랜드의 아이덴티티를 잘 살리면서도 세련된 디자인의 카드 (인정..)</li>
<li>다양한 디자인 선택지</li>
</ul>
<br/>

<h3 id="왜-브랜드들은-현대카드를-선택하는가">왜 브랜드들은 현대카드를 선택하는가</h3>
<blockquote>
<p>단순한 ‘카드 제휴’가 아닌 데이터 협력 플랫폼</p>
</blockquote>
<p>현대카드는 PLCC를 <strong>“데이터 기반 협력체계(Data Collaboration Platform)”</strong>로 정의하였다. </p>
<p>파트너 브랜드의 충성 고객을 그대로 카드 회원으로 끌어오는 ‘1차원적 제휴’가 아니라, 서로 다른 업종 간의 데이터를 교류·분석해 새로운 마케팅 인사이트를 창출하는 구조를 만들었기때문에 브랜드가 선택하는 것이였다.
도메인 갤럭시(Domain Galaxy)’ — 업종 간 크로스 마케팅 허브</p>
<blockquote>
<p>현대카드는 업종별 챔피언 기업들과 함께 <strong>‘도메인 갤럭시’(Domain Galaxy)</strong>라는 네트워크를 운영.</p>
</blockquote>
<p>지금까지 2,000건 이상의 공동 마케팅 캠페인이 이 구조를 통해 실행되어 왔으며, 현대카드는 PLCC를 통해 브랜드 간 데이터 생태계를 연결하는 ‘마케팅 오케스트레이터’ 역할을 수행했다고 한다.</p>
<blockquote>
<p>초개인화 AI 플랫폼 ‘유니버스(UNIVERSE)’입니다. 고객 행동을 실시간으로 예측해 필요한 시점에 최적의 혜택을 제안할 수 있는 인프라</p>
</blockquote>
<p>데이터를 정의하고 구조화하는 &#39;태그(Tag)&#39;로 개인의 행동·성향·상태 등을 예측해 고객을 직접 타기팅(Targeting)할 수 있고, 업종에 상관 없이 비즈니스의 전 영역에 적용</p>
<br/>

<h3 id="2023년-3월-현대카드만-도입했던-애플페이-론칭효과">2023년 3월 현대카드만 도입했던 애플페이 론칭효과</h3>
<p>도입 직후부터 점유율과 신규회원이 폭증했다.(나도..)</p>
<p>작년 5월에는 CJ 올리브영이 19번째 PLCC파트너사로 합류하기도 했고 2018년 현대카드가 18년 만에 삼성카드를 밀어내고 따낸 코스트코 전용결제카드도 지금까지 점유율 확대에 큰 역할을 하고 있는 것으로 알려졌다.</p>
<p>현대카드는 마케팅 비용도 아끼지 않는 것으로 알려졌다.</p>
<p>올해 4~5월 카드실적을 살펴보면, 온라인쇼핑 중에서도 음식서비스와 음식료품 부문의 실적이 크게 증가했지만, </p>
<p><del><em>음식서비스(배달앱) 결제액은 5조8140억원이 거래되며 전년 동기 대비 14.1% 급증했고, 식음료품 부문은 5조7190억원이 거래되며 7.3% 증가</em></del></p>
<p>반면, 같은 시기 백화점 등 오프라인 중심의 소매업종 매출은 감소</p>
<p><em><del>백화점(-2.1%), 대형마트(-2.0%)</del></em></p>
<p>이러한 배경 속에 카드사들은 고객들의 소비패턴의 변화에 발맞춰, 생활 소비 영역의 브랜드와 협력해 PLCC카드를 내놓고 있기 때문에 애플페이 론칭효과 이후로도 계속 유지되고 있는 것이다.</p>
<h3 id="데이터를-어떻게-활용하는지가-중요">데이터를 어떻게 활용하는지가 중요</h3>
<p>최근에 한 프로젝트도 비정형 데이터를 어떻게 활용해야 사용자의 니즈에 맞출 수 있는가! 에 대해서 많이 고민 했던 터라.. 현대카드에 대해서 알아보았다.</p>
<p>현대카드가 &#39;금융사&#39;에서 &#39;테크기업&#39;으로의 전환 + 인터렉션 디자인도 신경씀..</p>
<p><a href="https://openads.co.kr/content/contentDetail?contsId=16014#:~:text=%EC%9D%B4%EC%B2%98%EB%9F%BC%20%EC%9E%90%EC%8B%A0%EC%9D%B4%20%EC%9E%98%ED%95%A0%20%EC%88%98%20%EC%9E%88%EB%8A%94%20%EB%B6%84%EC%95%BC(%EA%B2%B0%EC%A0%9C%C2%B7%EB%8D%B0%EC%9D%B4%ED%84%B0)%EB%A5%BC%20%ED%86%A0%EB%8C%80%EB%A1%9C,%EA%B3%BC%EC%A0%95%EC%97%90%EC%84%9C%2C%20%EC%96%BC%EB%A7%88%EB%82%98%20%EC%A0%95%EA%B5%90%ED%95%98%EA%B2%8C%20%E2%80%9C%EC%83%81%EB%8C%80%EB%B0%A9%EC%9D%B4%20%EC%9B%90%ED%95%98%EB%8A%94%20%EA%B0%80%EC%B9%98%EB%A5%BC%E2%80%9D%20%EB%B6%84%EC%84%9D%ED%95%98%EA%B3%A0">현대카드는 어떻게 수많은 브랜드와 PLCC를 만들 수 있었나</a>
<a href="https://www.hyundaimotorgroup.com/ko/news/CONT0000000000162607">현대카드, 유니버스</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JSX로 마크업 작성하기]]></title>
            <link>https://velog.io/@lazy_hong/JSX%EB%A1%9C-%EB%A7%88%ED%81%AC%EC%97%85-%EC%9E%91%EC%84%B1%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@lazy_hong/JSX%EB%A1%9C-%EB%A7%88%ED%81%AC%EC%97%85-%EC%9E%91%EC%84%B1%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 04 Nov 2025 06:49:31 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/17215b18-14d6-47b4-9efd-d9d7248dab6d/image.png" alt=""></p>
<p>부족한 공부를 어떤 식으로 채워나가야 할 지를 고민하던 중, 나는 취준생이기에.. 이력서에 적은 프로젝트에 나올 수 있는 질문들을 추려서 하나씩 지워나가는 식으로 공부하기로 했다.</p>
<blockquote>
<p>&quot;Next.js의 SSR/CSR 중 어느 방식을 주로 채택했고, 선택 근거는 무엇이었나요?&quot;</p>
</blockquote>
<p>최근에 Next.js를 사용한 프로젝트에서 나올 법한 기본적인 질문이기에 먼저 시작했는데.. 난 기교만 부리는 개반인이였나보다..ㅋㅋㅋ</p>
<p>암튼.. JSX로 마크업 &gt; React의 render와 commit &gt; SSR,CSR순으로 정리를 시작하겠다.</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/7b6f1b0a-c4cd-4a92-adf4-e488c8bc385f/image.png" alt=""></p>
<h3 id="jsx로-마크업-작성하기">JSX로 마크업 작성하기</h3>
<p>HTML인척 하는 JSX는 확장된 문법이다. 이름에서부터 알 수 있는데 HTML이였다면 JSH였겠지만, JSX에서 X는 XML(eXtensible Markup Language)이다.
HTML 태그와 유사하지만 사용자가 자신의 태그를 정의할 수 있다는 점이 다르다.</p>
<p>내가 처음에 시작한 프로젝트는 거의 모든 입문자가 하는 바닐라JS 프로젝트였다. 
HTML, CSS, JavaScript가 각각 분리된 파일로 있는 즉, 로직과 마크업을 분리한 형태인 파일 구조.
그 다음으로 이제 React를 사용하면서 JavaScript가 HTML을 담당하게 되는 프로젝트를 하게 되었다.</p>
<p>React에는 컴포넌트라는 개념이 있는데 그 개념을 구현하기 위해 JSX가 만들어진거라고 봐도.. 무방하다고 생각한다. React 컴포넌트는 React가 브라우저에서 마크업을 렌더링할 수 있는 *<em>JS함수 *</em> 이기때문에 로직 + return을 통해 &quot;값 하나&quot;만 반환해야한다는 점이 기본 베이스다. 그렇기 때문에 HTML보다는 조금 엄격한(?) 규칙이 있다.</p>
<h3 id="일단-html---jsx로">일단 HTML -&gt; JSX로!</h3>
<ul>
<li><p>html</p>
<pre><code class="language-html">&lt;h1&gt;Hedy Lamarr&#39;s Todos&lt;/h1&gt;
&lt;img
src=&quot;https://i.imgur.com/yXOvdOSs.jpg&quot;
alt=&quot;Hedy Lamarr&quot;
class=&quot;photo&quot;
&gt;
&lt;ul&gt;
  &lt;li&gt;Invent new traffic lights
  &lt;li&gt;Rehearse a movie scene
  &lt;li&gt;Improve the spectrum technology
&lt;/ul&gt;</code></pre>
</li>
<li><p>jsx</p>
<pre><code class="language-JavaScript">export default function TodoList(){
  return (
      &lt;h1&gt;Hedy Lamarr&#39;s Todos&lt;/h1&gt;
      &lt;img
        src=&quot;https://i.imgur.com/yXOvdOSs.jpg&quot;
        alt=&quot;Hedy Lamarr&quot;
        class=&quot;photo&quot;
      &gt;
      &lt;ul&gt;
          &lt;li&gt;Invent new traffic lights
          &lt;li&gt;Rehearse a movie scene
          &lt;li&gt;Improve the spectrum technology
      &lt;/ul&gt;
  );
}
</code></pre>
</li>
</ul>
<pre><code>당연히 오류가 난다. 
![](https://velog.velcdn.com/images/lazy_hong/post/4e48fa7c-5749-4071-8049-c3e139dc3d05/image.png)

앞서 말했듯이 엄격한(?) 규칙이 존재하기 때문이다.

### JSX 규칙1: 하나의 루트엘리먼트로 반환하기

React에서 컴포넌트는 동적로직과 마크업을 JavaScript 객체로 반환하는 함수이기 때문에 **값이 하나** 여야 한다.

그렇기 때문에 한 컴포넌트 (한 함수)에서 여러개의 엘리먼트를 반환하려면 하나의 부모로 묶어줘야 한다.

보통 `&lt;div&gt;` 태그나 의미가 없는 `&lt;&gt;&lt;/&gt;`빈 태그로 묶어준다.
여기서 빈 태그를 Fragment라고 한다. 나도 주로 Fragments를 사용하여 브라우저상의 HTML 트리 구조에서 흔적을 남기지 않으려고 한다.

```JavaScript

...

return(
  &lt;&gt;
    &lt;h1&gt;Hedy Lamarr&#39;s Todos&lt;/h1&gt;
    &lt;img
      src=&quot;https://i.imgur.com/yXOvdOSs.jpg&quot;
      alt=&quot;Hedy Lamarr&quot;
      class=&quot;photo&quot;
    &gt;
    &lt;ul&gt;
        &lt;li&gt;Invent new traffic lights
        &lt;li&gt;Rehearse a movie scene
        &lt;li&gt;Improve the spectrum technology
    &lt;/ul&gt;
  &lt;/&gt;
);

...</code></pre><h3 id="jsx-규칙2-모든-태그는-닫아주기">JSX 규칙2: 모든 태그는 닫아주기</h3>
<p>JSX애서는 태그를 명시적으로 닫아줘야한다. <code>&lt;Img&gt;</code>처럼 자체적으로 닫아주는 태그도 반드시 <code>&lt;Img/&gt;</code>로 <code>&lt;li&gt;</code> 같은 래핑 태그도 <code>&lt;li&gt;&lt;/li&gt;</code> 형태로 작성해서 닫아줘야 한다. </p>
<pre><code class="language-JavaScript">&lt;&gt;
  &lt;img
    src=&quot;https://i.imgur.com/yXOvdOSs.jpg&quot;
    alt=&quot;Hedy Lamarr&quot;
    class=&quot;photo&quot;
   /&gt;
  &lt;ul&gt;
    &lt;li&gt;Invent new traffic lights&lt;/li&gt;
    &lt;li&gt;Rehearse a movie scene&lt;/li&gt;
    &lt;li&gt;Improve the spectrum technology&lt;/li&gt;
  &lt;/ul&gt;
&lt;/&gt;
</code></pre>
<h3 id="jsx-규칙3-속성은-거의-카멜케이스로">JSX 규칙3: 속성은 거의~ 카멜케이스로</h3>
<p>JSX는 브라우저가 직접 읽는 HTML이 아니라 Babel 같은 트랜스파일러에 의해 JavaScript 코드로 변환되기  때문에 속성 (attribute)들이 JavaScript 객체의 키(key)로 들어가는 구조이다.</p>
<pre><code class="language-JavaScript">const element = &lt;div className=&quot;photo&quot; strokeWidth=&quot;3&quot;&gt;&lt;/div&gt;;

//내부적으로 아래와 같이 바뀜
const element = React.createElement(&quot;div&quot;, {className : &quot;photo&quot;, strokeWidth : &quot;3&quot;})</code></pre>
<p>JS 변수명(객체 키)에는 제약이 있다는 것이다. JavaScript에서 객체를 아래와 같이 써보면</p>
<pre><code>const obj = {
    stroke-width : 3,
    class: &quot;photo&quot;
}</code></pre><p>문제가 생긴다.</p>
<ol>
<li><code>-</code> (대시)는 변수명에 쓸 수 없다. 빼기 연산으로 인식하기 때문이다</li>
<li>예약어(class, for, default 등)는 변수명으로 쓸 수 없다.</li>
</ol>
<p>따라서</p>
<pre><code>const obj = {
    strokeWidth : 3,
    className: &quot;photo&quot;
}</code></pre><p>그럼 이제 코드를 바꿔보면</p>
<pre><code class="language-JavaScript">export default function TodoList(){ //JS 함수
    return (
      &lt;&gt; //JSX 시작
        &lt;h1&gt;Hedy Lamarr&#39;s Todos&lt;/h1&gt;
        &lt;img
          src=&quot;https://i.imgur.com/yXOvdOSs.jpg&quot;
          alt=&quot;Hedy Lamarr&quot;
          className=&quot;photo&quot;
        /&gt;
        &lt;ul&gt;
            &lt;li&gt;Invent new traffic lights&lt;/li&gt;
            &lt;li&gt;Rehearse a movie scene&lt;/li&gt;
            &lt;li&gt;Improve the spectrum technology&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/&gt;
    );
}
</code></pre>
<p>이제..렌더링으로</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프론트엔드 로드맵]]></title>
            <link>https://velog.io/@lazy_hong/%EB%A1%9C%EB%93%9C%EB%A7%B5</link>
            <guid>https://velog.io/@lazy_hong/%EB%A1%9C%EB%93%9C%EB%A7%B5</guid>
            <pubDate>Sun, 02 Nov 2025 10:54:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/68619c92-2b26-4970-a32d-4a877349f817/image.png" alt=""></p>
<p><a href="https://roadmap.sh/frontend">프론트엔드 로드맵</a>
<a href="https://github.com/kamranahmedse/developer-roadmap">https://github.com/kamranahmedse/developer-roadmap</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[이력서 작성 하면서..]]></title>
            <link>https://velog.io/@lazy_hong/%EC%9D%B4%EB%A0%A5%EC%84%9C-%EC%9E%91%EC%84%B1-%ED%95%98%EB%A9%B4%EC%84%9C</link>
            <guid>https://velog.io/@lazy_hong/%EC%9D%B4%EB%A0%A5%EC%84%9C-%EC%9E%91%EC%84%B1-%ED%95%98%EB%A9%B4%EC%84%9C</guid>
            <pubDate>Wed, 22 Oct 2025 02:51:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/e5c43427-d87d-44b6-a5fa-28b206bc3f8a/image.png" alt=""></p>
<p>지난일에 후회를 해봤다 다시 돌아갈 수 있는 것도 아니고
지금 최선을 다하면 된다 라고 생각은 하고 있다. (최선은 어디까지인가..?)
이력서나 포폴을 만들 때는 나만의 스토리가 존재해야 된다는 것을 확실하게 느꼈다.
지금 내 이력서는 강조하는 바가 존재하지만 맥락과 흐름이 없는 느낌..? 이랄까</p>
<p>나는 기술보다 경험을 먼저 고민하는 프론트엔드 개발자가 되고 싶다.
막연하게 전달받은 디자인을 구현하기보다는 사용자가 내가 만든 서비스에 좀 더 머물렀으면 좋겠다.</p>
<p>최근에 했던 팀 프로젝트를 하면서 팀장님께 피드백 아닌 피드백을 들었던 것은 내가 하고자 하는 기능들은 input 대비 output이 적어서 지금 하는 프로젝트 기간을 봤을 때 알맞지 않다는 것이였다. 그렇지만, 그런 작은 디테일들이 모여서 완성도가 높아진다는 건 인정하신다고 하셨다.</p>
<p>내가 만든 기능과 UI가 작을지라도 디테일이 모여서 사용자에게 좋은 경험을 줄 수 있는 일을 하고 싶다.</p>
<p>이력서를 노션으로 적고 있는데 적으면 적을수록 다를 보여줄 수 있는게 아닌 것 같아서 피그마로 바꿀까 고민도 하고 있다.
보편화된 이력서는 나를 보여주기 힘든 느낌이다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SSR이 CSR을 완전히 대체하는 것이 아니라, 상황에 따라 함께 사용하는 것이다.]]></title>
            <link>https://velog.io/@lazy_hong/SSR-CSR</link>
            <guid>https://velog.io/@lazy_hong/SSR-CSR</guid>
            <pubDate>Mon, 20 Oct 2025 08:33:04 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>“SSR doesn’t replace CSR; it complements it. Use the right tool for the right scenario.”</p>
</blockquote>
<p>렌더링 방식(CSR, SSR)에 대해서 말하기 전에 &#39;왜 렌더링 방식이 바뀐거지?&#39; 라는 의문 먼저 해결하고자 하니.. 페이지 구조(MPA, SPA)에 대해 모르면 안되는 거였다. 이래서 CSR,SSR을 검색하면 MPA와 SPA를 같이 설명하는 블로그가 있는 것이였다.</p>
<br/>
<br/>

<h2 id="mpa--ssr">MPA + SSR</h2>
<p>MPA는 SSR이다.</p>
<p>왜??</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/6ab496a0-1ea0-4ff5-8b66-a4fca4e8e170/image.png" alt=""></p>
<p>MPA는 서버 중심의 웹이다.
사용자가 /about 페이지를 요청하면 서버가 <strong>완성된 HTML을 생성</strong>하고 브라우저는 HTML을 받아 DOM으로 렌더링하는 것이다.</p>
<p>MPA는 페이지마다 HTML 파일이 있기때문에 이동할 때마다 새 HTML 요청 -&gt; 다시 DOM 전체 재생성으로 브라우저는 그저 &quot;그려주는 역할&quot;만 했고 렌더링의 주도권은 서버에게 있었다.</p>
<p>이때는 HTML을 그리는 주체가 서버, 브라우저의 JS는 단순히 &quot;보조 역할&quot;에 그쳤다고 한다.</p>
<h3 id="그래도-브라우저에서-js로-렌더링할-수-있는-거-아닌가">그래도 브라우저에서 JS로 렌더링할 수 있는 거 아닌가?</h3>
<p>⭐️ MPA 파일 구조를 사용할 때는 브라우저 성능이 낮아서 JS 실행이 느렸고 ES6 문법도 없었을 뿐더러 fetch,Promise,async/await 같은 비동기 통신 도구도 없었기때문에..</p>
<p>데이터를 가져와서 브라우저에서 조립하고 렌더링한다는 것 자체가 성능적으로 불가능하고 비효율적이다.</p>
<p>⭐️ MPA는 애초에 HTML을 <strong>서버에서 렌더링하는 구조</strong>다. <strong>서버가 이미 완성된 HTML</strong>을 줘버린다.</p>
<p><strong>서버가 이미 완성된 HTML을 브라우저한테 넘기는 것이므로 결론은 MPA는 SSR이다.</strong></p>
<br/>
<br/>

<h2 id="spa는-왜-나왔을까-부터">SPA는 왜 나왔을까? 부터</h2>
<p>크게 두 가지로 요약하자면</p>
<ol>
<li><p>우리가 알고 있는 전통적인 페이지 구조(MPA)는 다른 페이지로 이동할 때마다 서버로부터 HTML,CSS,JavaScript 등 전체 페이지 리소스를 새로 다운로드하고 렌더링을 해야하는데 이과정에서 페이지 깜빡임이 발생하고 불필요한 리소스 재다운로드가 반복되며 비효율적.</p>
</li>
<li><p>스마트폰 보급과 함께 모바일 웹 사용이 증가하면서, MPA 방식의 성능 문제가 모바일 환경에서 부담이되면서 빠른 반응 속도를 제공.</p>
</li>
</ol>
<p>결론적으론 웹앱이 복잡해지고 사용자 경험(UX)이 중요해지면서, 페이지 이동마다 새로고침하는 구조(MPA)는 너무 느려진 이유로 인해 Single Page Application이 탄생(?) 하였다는 것이다...</p>
<hr>
<p>이러한 배경들로 인해 SPA가 나왔고 비동기 통신 도구들도 나왔고 ES6, JS도 발전했으니 서버가 렌더링의 주최가 아닌 브라우저가 렌더링 주최인 CSR을 도전(?)!!</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/6a08f2c0-5b76-44bf-a8ee-b7cbd165e9cc/image.png" alt=""></p>
<br/>
<br/>

<h2 id="csr과-ssr">CSR과 SSR</h2>
<blockquote>
<p>간단하게 말하면 HTML 완성이 브라우저에서냐 서버에서냐의 차이..</p>
</blockquote>
<h3 id="csr-client-side-rendering">CSR (client-side rendering)</h3>
<p>..적어야해</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/c7e7e9b5-bfc8-47b8-b1df-bcaac94233d1/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/8937f902-eaf5-424d-8f05-79531ca3f289/image.png" alt=""></p>
<h2 id="spa--csr">SPA + CSR</h2>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/635f0c76-8c39-424d-8439-a36d282f7f54/image.png" alt=""></p>
<p>SPA(Single Page Application) + CSR 은 말 그대로 <strong>1)HTML 페이지가 한 개</strong>이다. 따라서 <strong>2)페이지 전환은 JS</strong>가 처리한다. <strong>3)모든 렌더링은 브라우저</strong>에서 일어난다.</p>
<p>SPA(1번 + 2번) +  CSR(3번) =&gt; React의 탄생이다.</p>
<p>처음에는 React에 맞춰서 이런 개념이 생긴 줄 알았으나.. 역방향이였다. 그래서 React가 하는 일은 컴포넌트를 JavaScript 객체로 만들고 이것을 브라우저의 DOM에 그리는것!</p>
<p>SPA에서 페이지 전환은 DOM 조작(교체)으로 한다. <strong>DOM 조작(교체)은 브라우저에서만</strong> 가능한다 == CSR이다.</p>
<h2 id="spa--csrssr">SPA + CSR/SSR</h2>
<p>언능 적자..</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/55555a6e-f5ca-43c2-8ecc-2d455d919180/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring AI : 찍먹]]></title>
            <link>https://velog.io/@lazy_hong/Spring-AI-%EC%B0%8D%EB%A8%B9</link>
            <guid>https://velog.io/@lazy_hong/Spring-AI-%EC%B0%8D%EB%A8%B9</guid>
            <pubDate>Mon, 20 Oct 2025 05:29:34 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/15b75bd4-d449-498b-a961-fb361acdc53b/image.png" alt=""></p>
<h2 id="builder-패턴">builder 패턴</h2>
<p>Builder() 패턴을 활용해서 객체를 생성한다.</p>
<pre><code>User user = User.builder()
//과정~
.id(1L)
.name(&quot;Rabbit&quot;)
.email(&quot;rabbit@gmail.com&quot;)
//~과정
.build()&#39; </code></pre><p>이렇게 했을때 좋은 점은 Builder 패턴은 객체 생성 과정과 결과를 분리하여 복잡한 객체를 단계적으로 생성할 수 있게 한다.</p>
<p>장점:</p>
<ul>
<li><p>생성자 오버로딩 없이 다양한 조합의 객체 생성 가능</p>
</li>
<li><p>가독성 향상 (필드명을 명시하면서 설정 가능)</p>
</li>
<li><p>불변 객체(immutable object) 생성에 유리</p>
</li>
</ul>
<h2 id="도대체-모델이-뭐냐">도대체 모델이 뭐냐</h2>
<blockquote>
<p>모델 = 데이터로부터 학습된 패턴(규칙)의 집합</p>
</blockquote>
<p>인공지능은 규칙이 필요하다. 전통적인 규칙 기반 시스템은 사람이 직접 규칙을 정의한다. 사람은 모든 경우의 수를 생각할 수 없기 때문에 이 시스템은 예외 상황에 취약해지고 확장성이 낮아질 수 밖에 없다.</p>
<p>그렇기 때문에 규칙을 데이터 분석에 의해 패턴을 학습함으로서 예외적인 상황이 들어와도 확률적으로 대응할 수 있다.</p>
<h2 id="llm">LLM</h2>
<ul>
<li><p>기반 아키텍처: Transformer
→ 인코더(Encoder) + 디코더(Decoder) 구조</p>
</li>
<li><p>핵심 개념: Attention (문맥을 고려한 단어 간 관계 학습)</p>
</li>
<li><p>학습 과정:</p>
</li>
</ul>
<p>토큰화(Tokenization): 문장을 최소 의미 단위(토큰)로 분해</p>
<p>벡터화(Vectorization): 각 토큰을 수치로 변환하여 모델이 이해 가능한 형태로</p>
<p>Transformer 학습: Attention 메커니즘으로 문맥적 관계 학습</p>
<p>사용 시 주의점:
프롬프트(prompt)를 명확하고 구체적으로 작성해야 원하는 결과를 얻을 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/83b04d01-b324-4033-88db-8a289cd58407/image.png" alt=""></p>
<p><a href="https://wikidocs.net/31379">위키독스-트랜스포머</a></p>
<hr>
<p>Restful API로 되어 있음
엔드포인트를 정확하게 자원의 경로를 알 수 있어야 한다,</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/fa9f4527-4660-4c43-ab3d-e7198b318059/image.png" alt=""></p>
<p>✅ 예시</p>
<p>POST <a href="https://api.openai.com/v1/chat/completions">https://api.openai.com/v1/chat/completions</a> 처럼 한 줄에 내용이 잘 들어가 있어야 한다.</p>
<ul>
<li>받을 때도 보낼 때도 json 형태</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CORS 개념과 동작 방식 ( preflight 요청이 필요한 이유는 ?)]]></title>
            <link>https://velog.io/@lazy_hong/CORS-%EA%B0%9C%EB%85%90%EA%B3%BC-%EB%8F%99%EC%9E%91-%EB%B0%A9%EC%8B%9D-preflight-%EC%9A%94%EC%B2%AD%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0%EB%8A%94</link>
            <guid>https://velog.io/@lazy_hong/CORS-%EA%B0%9C%EB%85%90%EA%B3%BC-%EB%8F%99%EC%9E%91-%EB%B0%A9%EC%8B%9D-preflight-%EC%9A%94%EC%B2%AD%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%9C-%EC%9D%B4%EC%9C%A0%EB%8A%94</guid>
            <pubDate>Wed, 15 Oct 2025 13:03:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/c15cb38c-0f19-493c-95d5-0b9caf7fb64a/image.png" alt=""></p>
<h2 id="🍋-비동일-출처라고-하면-내가-이해가-빠를텐데">🍋 비동일 출처라고 하면 (내가) 이해가 빠를텐데..</h2>
<p>동일 출처(same-origin)가 아닌 <em>다른 출처(도메인, 스킴 혹은 포트)로부터</em> 에 대한 정책이라면 비동일 출처라고 하는게 이해가 빠르지 않나? 라고 의문이든 나..</p>
<p>사실 의미는 통한다고 생각한다. <strong>다른 출처</strong>에 초점이 맞춰진다면 사실 none-same-origin 도.. 나쁘지 않겠지만, 이건 비동일 출처는 막는다! 라는 단순한 비교 표현일 뿐이라서.. <strong>서로 다른 출처가 상호작용</strong>에 초점을 둔다면 cross-origin이 더 맞는 말이다. (5분전의 나에게)</p>
<p>서로 다른 출처가 서로 공유하고 넘나드는 상황의 cross에 초점을 두자! 
가끔 이상한 것에 꽂혀서 알아볼 때가 있다 ㅎ</p>
<h3 id="🧐-그래서-동일-출처는-뭔데-어떤-것과-비교하는-건데">🧐 그래서 동일 출처는 뭔데? 어떤 것과 비교하는 건데?</h3>
<ul>
<li>출처 (origin)</li>
</ul>
<pre><code>origin = 프로토콜/스키마(protocal) + 도메인(hostname) + 포트 (port) : 명시된 경우</code></pre><ul>
<li>동일 출처 (same-origin)</li>
</ul>
<p>origin이 같은 경우 두 url은 동일한 출처를 가진다고 말할 수 있다. MDN 예시와 똑같이 들어보자면 
<a href="http://store.company.com/dir/page.html">http://store.company.com/dir/page.html</a></p>
<pre><code>http://store.company.com/dir2/other.html    동일 출처 + 경로만 다름
http://store.company.com/dir/inner/another.html    동일 출처 + 경로만 다름
https://store.company.com/page.html    실패    다른 프로토콜
http://store.company.com:81/dir/page.html    실패    다른 포트 (http:// 는 기본적으로 80 포트)
http://news.company.com/dir/page.html    실패    다른 호스트
</code></pre><ul>
<li>비교 대상</li>
</ul>
<p>브라우저는 요청을 보낸 페이지의 출처 origin과 요청을 받는 대상의 출처 origin을 비교한다.</p>
<pre><code>[현재 페이지]  https://rabbit.com/profile
[요청 대상]    https://rabbit.com/api/user
</code></pre><p>현재 문서의 origin : https + rabbit.com
요청 대상의 origin : https + rabbit.com</p>
<p>-&gt; 동일 출처(same-origin)이기 때문에 CORS 검사 안 함</p>
<pre><code>[현재 페이지]  https://rabbit.com/profile
[요청 대상]    https://api.rabbit.io/user</code></pre><p>현재 문서의 origin : https + rabbit.com
요청 대상의 origin : https + api.rabbit.io</p>
<p>-&gt; 교차 출처 cross origin
-&gt; CORS 검사 실행
-&gt; 서버가 허용 헤더를 주지 않으면 차단</p>
<h2 id="🍋-아니-그렇다고-모든-교차-출처-요청을-다-막는-건-아니래">🍋 아니 그렇다고 모든 교차 출처 요청을 다 막는 건 아니래</h2>
<p><a href="https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy#%EA%B5%90%EC%B0%A8_%EC%B6%9C%EC%B2%98_%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC_%EC%A0%91%EA%B7%BC">MDN이 동일 출처 정책에 대해서 말하고 있어요</a></p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/2df0cb97-b61e-4f28-a853-0111f195928f/image.png" alt=""></p>
<p>동일 출처 정책 (Same-Origin Policy) 는 요청의 종류에 따라 cross-origin에 대하여 허용 제한이 다르다.</p>
<p>브라우저는 요청의 <strong>목적</strong>과 <strong>방향</strong>에 따라 다르게 다루는데..
일단 크게 3가지만 보자. 현재 ㅣ <a href="https://rabbit.com">https://rabbit.com</a></p>
<p>✅ Cross-Origin Write
다른 출처로 데이터를 <strong>보내는 것은 대부분 허용</strong>된다.
예시로는 링크, 리다이렉트, 폼 제출 </p>
<pre><code class="language-html">&lt;form action=&quot;https://api.rabbit.io/login&quot; method=&quot;POST&quot;&gt;
  &lt;input name=&quot;id&quot; value=&quot;bunny&quot;&gt;
  &lt;input name=&quot;pw&quot; value=&quot;1234&quot;&gt;
&lt;/form&gt;

&lt;a href=&quot;https://other.com&quot;&gt;링크 이동&lt;/a&gt;

&lt;script&gt;window.location = &quot;https://other.com&quot;&lt;/script&gt;
</code></pre>
<p>✅ Cross-Origin Embed
다른 출처의 리소스를 내 페이지 안에 <strong>보이게는</strong> 가져올 수 있다 == 시각적으로 표시는 됨 == 삽입</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/a75825f9-25bf-410a-b050-e9251bcafbde/image.png" alt=""></p>
<p>🚫 Cross-Origin Read
다른 출처의 데이터를 <strong>읽는 것</strong>은 기본적으로 금지됨 -&gt; CORS 검사 수행</p>
<pre><code>fetch(&quot;https://api.other.com/user&quot;)</code></pre><p>단순히 데이터를 보내는(write) 용도만이 아니라 응답(response)를 읽는 목적도 동시에 갖기 때문에 cross-origin read의 예시에 있다.</p>
<h3 id="🧐-저는-표시embed와-읽기read의-차이를-모르겠네요">🧐 저는 표시(embed)와 읽기(read)의 차이를 모르겠네요..</h3>
<p>둘 다 교차 출처 리소스를 가져오지만, 누가 보느냐가 다르다.</p>
<p>embed는 주체가 브라우저, 목적은 사용자에게 보여주기
read는 주체가 자바스크립트, 목적은 코드로 데이터 사용</p>
<pre><code>&lt;!-- 표시(embed): 브라우저가 이미지를 그냥 보여줌 --&gt;
&lt;img src=&quot;https://api.rabbit.io/profile.png&quot;&gt;

&lt;!-- 읽기(read): 코드가 교차 출처 데이터를 직접 요청--&gt;
fetch(&quot;https://api.rabbit.io/profile.png&quot;)
  .then(res =&gt; res.blob()) </code></pre><h3 id="🧐-그렇다면-fetch-는-모두-cross-origin-read-일까요">🧐 그렇다면 fetch 는 모두 Cross-Origin Read 일까요?</h3>
<p>fetch는 읽기 목적이 포함된 API라 SOP 규제 대상이기는 한데,, fetch가 전송만 하고 응답을 읽지 않는 목적을 가진다면 CORS 검사를 수행할까? 라는 의문이 들었다.</p>
<pre><code class="language-javascript">// 응답을 안 읽음 → 사실상 단순 쓰기
fetch(&quot;https://api.rabbit.io/track&quot;, {
  method: &quot;POST&quot;,
  mode: &quot;no-cors&quot;,
  body: JSON.stringify({ event: &quot;click&quot; })
});
</code></pre>
<p><strong>mode: &quot;no-cors&quot;를 지정</strong>하면 브라우저는 “응답을 읽을 수 없는 opaque response”로 처리하고
단순히 요청만 보낸다.. 
위의 코드를 사용할 일이 얼마나 있을까? </p>
<p>그렇다면 CORS는 “교차 출처 읽기(read)” 요청일 때만 적용되고, 그중에서도 요청이 단순하면 바로 검사(Simple), 복잡하면 먼저 허락 요청(Preflight) 두 단계로 나뉜다고 봐야겠다.
이 배경을 가지고 다시 CORS 개념부터,,</p>
<h2 id="🍋-cors의-개념">🍋 CORS의 개념</h2>
<blockquote>
<p>교차 출처 리소스 공유(Cross-Origin Resource Sharing) 브라우저가 요청을 보낸 출처(origin)과 요청을 받는 출처(origin)이 다를때 자원을 로딩하는 것을 허용하도록 거버가 하가 해주는 HTTP 헤더 기반 메커니즘이다. </p>
</blockquote>
<p>cors를 사용하는 요청은 브라우저가 다른 origin의 데이터를 가져와 조작하거나 처리하는 요청 (즉, Read)이다</p>
<h3 id="✅-cors가-필요한-경우">✅ CORS가 필요한 경우</h3>
<ul>
<li>fetch() / XMLHttpRequest의 호출 =&gt; 항상 읽기 요청으로 간주</li>
<li>웹 폰트(CSS 내 @font-face에서 교차 도메인 폰트 사용 시)</li>
<li>WebGL 텍스처 </li>
<li>drawImage()를 사용해 캔버스에 그린 이미지/비디오 프레임</li>
</ul>
<h3 id="1-fetch--xmlhttprequest">1. fetch() / XMLHttpRequest</h3>
<p>이 경우가 Preflight가 필요할 때와 아닐때가 나누어진다.</p>
<p>브라우저는 교차 출처 요청을 보낼때 두 단계로 나누어서 판단하는데</p>
<p>(1) 이 요청이 안전한가? -&gt; preflight 보낼지 말지 결정</p>
<p>(2) 응답을 읽어도 되나? -&gt; CORS 헤더 검사</p>
<h4 id="단순-요청-simple-request">단순 요청 (simple request)</h4>
<p>CORS가 도입되기 전, 이미 HTML <code>&lt;form&gt;</code>은 오래전부터 어떤 사이트로든 데이터를 보낼 수 있었기 때문에 CORS 명세를 만들 때, 폼(form)처럼 안전한 패턴만 단순요청으로 인정했다.</p>
<p>다음 조건을 모두 만족해야 Prefligth 없는 단순 요청이다</p>
<ul>
<li><code>GET</code>, <code>HEAD</code>, <code>POST</code> 중 하나의 메서드</li>
<li>수동으로 설정 가능한 헤더 
  <code>Accept</code>, <code>Accept-Language</code>, <code>Content-Language</code>, <code>Content-Type</code></li>
<li>Content-Type 헤더에 지정한 허용된 타입/서브타입 조합
  <code>application/x-www-form-urlencoded</code>
  <code>multipart/form-data</code>
  <code>text/plain</code></li>
<li>XMLHttpRequest.upload 이벤트 리스터 없음</li>
<li>ReadableStream 사용 안 함</li>
</ul>
<p><strong>✅ 예시</strong>
client
    <code>origin</code> : <a href="https://rabbit.com">https://rabbit.com</a>
server
    <code>url</code> : <a href="https://api.rabbit.com/login">https://api.rabbit.com/login</a></p>
<pre><code class="language-javascript">fetch(&quot;https://api.rabbbit.com/login&quot;, {
  method: &quot;POST&quot;, //post
  headers: {
    &quot;Content-Type&quot;: &quot;application/x-www-form-urlencoded&quot;, //허용 타입
  },
  body: &quot;id=rabbit&amp;pw=1234&quot;,
});</code></pre>
<p><strong>🛰️ 브라우저 → 서버(request)</strong></p>
<pre><code class="language-json">POST /login HTTP/1.1 
Host: api.rabbit.com
Connection: keep-alive
Content-Length: 18
Pragma: no-cache
Cache-Control: no-cache
Accept: */*
Origin: https://rabbit.com
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Referer: https://rabbit.com/
Accept-Encoding: gzip, deflate, br

id=rabbit&amp;pw=1234</code></pre>
<p><code>Origin</code> : 요청이 발생한 출처
<code>Content-Type</code> : application/x-www-form-urlencoded 허용 타입
<code>요청 본문</code> : id=rabbit&amp;pw=1234</p>
<p><strong>🖥️ 서버 → 브라우저 : 응답(Response)</strong></p>
<pre><code class="language-json">HTTP/1.1 200 OK
Date: Thu, 17 Oct 2025 03:45:00 GMT
Server: nginx/1.24.0
Content-Type: application/json
Access-Control-Allow-Origin: https://rabbit.com
Vary: Origin
Content-Length: 48

{&quot;result&quot;:&quot;success&quot;,&quot;user&quot;:&quot;bunny&quot;,&quot;token&quot;:&quot;rb123xyz&quot;} //json 형태</code></pre>
<p><code>Access-Control-Allow-Origin</code> : CORS 핵심 허용 헤더로 브라우저가 이 값과 <code>Origin</code>을 비교한다</p>
<p><strong>🚫 만약 서버가 CORS 허용 헤더를 빼먹는다면</strong></p>
<pre><code class="language-http">
HTTP/1.1 200 OK
Content-Type: application/json

{&quot;result&quot;:&quot;success&quot;}
</code></pre>
<p>콘솔에는 </p>
<pre><code class="language-csharp">
Access to fetch at &#39;https://api.rabbit.com/login&#39; 
from origin &#39;https://rabbit.com&#39; 
has been blocked by CORS policy:
No &#39;Access-Control-Allow-Origin&#39; header is present on the requested resource.
</code></pre>
<h4 id="사전-요청-preflighted-requests">사전 요청 (Preflighted requests)</h4>
<blockquote>
<p>서버 데이터에 부수 효과(side effect)를 일으킬 수 있는 HTTP 요청 방법(특히 GET 이외의 HTTP 메서드 또는 특정 MIME 타입을 사용하는 POST)에 대해서, CORS 명세는 브라우저가 HTTP OPTIONS 메서드로 서버에서 지원하는 메서드들을 요구하는 요청을 &quot;사전 전달(프리플라이트)&quot;한 다음, 서버로부터 &quot;승인&quot;을 받은 후 실제 요청을 보내도록 지시합니다</p>
</blockquote>
<p><strong>✅ 예시</strong></p>
<pre><code>const fetchPromise = fetch(&quot;https://api.rabbit.com/doc&quot;, {
  method: &quot;POST&quot;,
  mode: &quot;cors&quot;,
  headers: {
    &quot;Content-Type&quot;: &quot;text/xml&quot;,
    &quot;X-PINGOTHER&quot;: &quot;pingpong&quot;,
  },
  body: &quot;&lt;person&gt;&lt;name&gt;Arun&lt;/name&gt;&lt;/person&gt;&quot;,
});

fetchPromise.then((response) =&gt; {
  console.log(response.status);
});</code></pre><p><a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Guides/CORS">MDN-CORS 설명</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Storybook install 부터 하라구...]]></title>
            <link>https://velog.io/@lazy_hong/Storybook-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@lazy_hong/Storybook-%EC%82%AC%EC%9A%A9-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Tue, 14 Oct 2025 05:22:42 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/922eeb0c-df0b-4078-9635-74054197a00b/image.png" alt=""></p>
<h2 id="🍋-install">🍋 install</h2>
<p>install 하기 전에 블로그 몇 개와 공식문서 그리고 한글 번역 튜토리얼을 찾아봤는데 다르다는 걸 느꼈다. </p>
<pre><code>yarn add global @storybook/cli
npx sb init
</code></pre><p>현재 공식문서에는 보이지 않는 방식이라 슬슬 혼동이 오는 나..
기존의 프로젝트에서 Storybook을 사용해서 리팩토링 하려는 방식과 새로 프로젝트 생성할 때부터 Storybook을 사용하는 방식이 다를까봐..</p>
<p>심지어 공식문서에 보이지 않는데 gpt가 <em>자꾸 공식문서에 나온</em> 이라고 언급하길래 찾아서 몇 번째 줄인지 알려줘! 라고 했는데 없다고 대답이 돌아왔다. 내 눈에만 안 보이는 줄..</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/1ce3224a-fbd3-4a68-8588-9335c7ecea72/image.png" alt=""></p>
<h3 id="결론">결론</h3>
<pre><code>1. Storybook를 깐 적 없는 프로젝트 (시작, 중간 상관없음)
npm create storybook@latest 

2-1. Storybook를 이미 있는 프로젝트에서 버전 업/마이그레이션할 때.
npx storybook@latest upgrade

2-2. 수동 마이그레이션
npm install --save-dev @storybook/{프레임워크}</code></pre><p><em><strong>🔥 업그레이드 명령은 레포 루트에서 실행해야 모든 스토리북 패키지/설정을 제대로 찾음</strong></em></p>
<p>2024 하반기부터 이렇게 바뀌었다고 한다.</p>
<p>Storybook 8 버전부터는 create-storybook 패키지로 통합되어, 새 프로젝트 초기화나 기존 프로젝트에 Storybook을 추가할 때 위와 같은 하나의 통일된 명령어로 실행하도록 개선됬다고 한다.</p>
<p>Storybook 7 이하는 create-storybook 패키지가 없었고, storybook <strong>CLI 자체</strong>가 <strong>init 명령을 제공</strong>했기 때문에 오래된 블로그 글이나 예제 코드에서는 아직도 이 버전의 명령을 볼 수 있다.</p>
<h2 id="🍋-뭐가-다르지">🍋 뭐가 다르지?</h2>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/bf7d5fef-186e-40ec-912c-14b4dab39813/image.png" alt=""></p>
<h3 id="📁-예전-구조-storybook-7-이하">📁 예전 구조 (Storybook 7 이하)</h3>
<pre><code>my-project/
├── package.json
├── node_modules/
│   ├── @storybook/react/
│   │   ├── dist/
│   │   └── ...
│   └── @storybook/cli/      ← CLI 명령어가 여기 포함되어 있음
│       ├── bin/
│       │   └── sb.js        ← npx sb init 실행 시 
│       └── generators/      ← 각 프레임워크별 설치 로직
├── .storybook/              ← init 실행 시 생성됨
│   ├── main.js
│   ├── preview.js
│   └── manager.js
└── src/
    └── *.stories.js
</code></pre><p>CLI(@storybook/cli)가 init이라는 명령어를 내장하고 있어서, 명령을 실행하면 Storybook을 자동으로 세팅해줬다.</p>
<pre><code>npx storybook@latest init

npx sb init //짧게</code></pre><p><strong>문제점</strong></p>
<p>React,Next,Vite 등 프레임워크가 다양해지면서 CLI 안에 모든 설정 로직을 넣기 힘들어지고 Node.js 생태계가 create-* 패턴(create-react-app, create-next-app, create-vite 등) 으로 표준화됨</p>
<p><strong><em>생성기(generator) 역할을 하는 별도 패키지로 분리</em></strong> 를 선택한 것이다.</p>
<h3 id="📁-현재-구조">📁 현재 구조</h3>
<p>CLI가 분리되어 독립 패키지(create-storybook)가 되었다.</p>
<pre><code>my-project/
├── package.json
├── node_modules/
│   ├── create-storybook/     ← 생성기 전용 패키지 (임시 설치)
│   │   ├── templates/        ← 프레임워크별 템플릿 코드
│   │   ├── detectFramework.js
│   │   ├── setupFiles.js
│   │   └── index.js          ← npm create storybook 실행 진입점
│   ├── @storybook/react/    
│   ├── @storybook/addons/
│   ├── @storybook/nextjs/
│   └── ...
├── .storybook/               ← 생성기로 만들어진 설정 폴더
│   ├── main.ts
│   ├── preview.ts
│   └── manager-head.html
└── src/
</code></pre><pre><code>node_modules/
│   ├── create-storybook/     ← 생성기 전용 패키지 (임시 설치)
│   │   ├── templates/        ← 프레임워크별 템플릿 코드
│   │   ├── detectFramework.js
│   │   ├── setupFiles.js
│   │   └── index.js  </code></pre><p>이부분은 임시 경로(npx/npm-create 캐시) 에 받아서 실행하고 끝나기 때문에 프로젝트 루트의 package.json이나 node_modules에 create-storybook이 상주하지 않고 바로 정리된다.</p>
<p>이런 흐름</p>
<ol>
<li>npm create storybook@latest  입력</li>
<li>npm이 임시 폴더에 create-storybook 설치</li>
<li>create-storybook/index.js 실행
├─ detectFramework()  → 프레임워크 감지
├─ copyTemplates()<br>├─ installPackages()<br>└─ npm script 등록</li>
<li>생성기 실행 완료 후 제거</li>
<li>프로젝트 안에는 Storybook 설정과 패키지만 남음</li>
</ol>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/7610c5c3-95fc-46b3-a5d1-cf95aff2df35/image.png" alt=""></p>
<p><a href="https://storybook.js.org/tutorials/intro-to-storybook/react/ko/get-started/">스토리북 공식문서 튜토리얼</a>
<a href="https://storybook.js.org/docs/get-started/frameworks/nextjs">스토리북 공식문서 Next.js</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[나 이런 것도 안 했나..?]]></title>
            <link>https://velog.io/@lazy_hong/%EB%82%98-%EC%9D%B4%EB%9F%B0-%EA%B2%83%EB%8F%84-%EC%95%88-%ED%96%88%EB%82%98</link>
            <guid>https://velog.io/@lazy_hong/%EB%82%98-%EC%9D%B4%EB%9F%B0-%EA%B2%83%EB%8F%84-%EC%95%88-%ED%96%88%EB%82%98</guid>
            <pubDate>Tue, 14 Oct 2025 05:08:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/5e78ec9f-62bf-4d5b-bc12-75446ba98c75/image.png" alt=""></p>
<p>여러 구직 사이트를 돌아다니다 보면 취업 외에 얻을 수 있는 것들이 많다는 것을 느낀다.
나 같은 경우는 어떤 일을 하고 싶다는 뚜련한 업종이 없었는데 구경(?)하다보니 나 이런 쪽에 일을 하고 싶었구나! 라는 흥미가 생기는 글들이 많다. 또한 내가 부족한 영역 그리고 기존 프로젝트에서 어떤 걸 더 발전시켜야 할지 알게 된다.</p>
<p>나는 사용 목적이나 목표를 모르면 머리에 아예 들어가지 않고 기억도 나지 않는 고지식한(?) 사람이라..</p>
<h2 id="🍋-왜-사용하는가">🍋 왜 사용하는가?</h2>
<h3 id="목적1--재사용-가능한-ui--매뉴얼">목적1 : 재사용 가능한 UI + 매뉴얼</h3>
<p>Storybook은 컴포넌트를 독립적으로 관리하고, props 조합별 상태를 한눈에 볼 수 있게 해준다고 한다. 덕분에 디자인 시스템이나 공통 UI를 만드는 프로젝트에서는 자연스럽게 개발 → 문서화 → 검증 → 공유의 흐름이 만들어진다고 한다.</p>
<p>최근 프로젝트에서는 디자이너가 따로 없어서 프론트엔드가 직접 디자인까지 맡았다.
처음부터 “공통 컴포넌트로 만들기 쉬운 구조로 디자인하자”는 의도로 진행했는데,
한 60% 정도는 의도한 대로 잘 돌아갔다는 느낌이었다.</p>
<p>그래서 이번에는 Storybook을 활용해 컴포넌트를 리팩토링하면서
처음에 세웠던 구조를 더 체계적으로 다듬어볼 계획이다. 디자인과 개발의 경계가 명확하지 않은 프로젝트일수록, 이런 도구가 얼마나 큰 도움이 되는지는 실감해볼 예정..</p>
<h3 id="목적2--디자이너와의-소통">목적2 : 디자이너와의 소통</h3>
<p>나의 얕은 경험 중에서도 기획/디자이너가 따로 존재했던 프로젝트가 있는데 정적인 디자인을 보고 유추를 해야하는 경우가 많았다. 
버튼 클릭하면 모달이 뜨는데 닫기 버튼이 없을 때 모달 바깥 영역을 클릭해야 닫히는지 아닌지부터 해서..드롭다운 메뉴가 hover로 열리는 건가 click으로 열리는 건가? 폼에서는 유효성 검사 실패 시 에러 메세지가 어디에 어떻게 어떤 식으로 뜨는거지? 스크롤 내렸을 때 어떤 요소에 동적인 기능을 넣어야 하지? 등등 피그마에 댓글 달기를 하고 확인하고 달고 확인하고.... 했던 적이 있다. </p>
<p>아무리 글로 세세히 전달해도 막상 서로 구현 했을 때 보여지는 모습이 다를 수 있으니 적어도 정적 디자인 보다는 행동·상태·맥락 공유가 가능한 살아있는 컴포넌트를 보여주는게 직접 보고 검증 받기 쉽다.</p>
<p>참고 아닌 보다는 필독.. : <a href="https://medium.com/@j_podracer/storybook%EC%9D%98-%EC%9C%A0%EC%9A%A9%ED%95%A8-8581ea618c32">Storybook의 유용함</a> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2024 획오쵝오]]></title>
            <link>https://velog.io/@lazy_hong/2024-%ED%9A%8D%EC%98%A4%EC%B5%9D%EC%98%A4</link>
            <guid>https://velog.io/@lazy_hong/2024-%ED%9A%8D%EC%98%A4%EC%B5%9D%EC%98%A4</guid>
            <pubDate>Fri, 10 Oct 2025 14:48:34 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/485b0597-c9dc-4f2b-9142-f7a49163ca0d/image.jpeg" alt=""></p>
<p>2024년 회고를 10월에 해보고자 한다..연말엔 그냥 미래를 생각할래요..
아카데미 끝나고 바로 할려고 했으나 연휴를 핑계로 미뤘다</p>
<p>취직한 친구에게 이런 저런 가벼운 질문을 하다가
이제 좀 써야겠다! 라는 마음이 들어서 ㅎ</p>
<p>아카데미를 들어왔을 때의 목표는 1년동안 놓아버린 개발공부와 나의 루틴을 찾자였다. 생활패턴이랑 기록만 얻어간다면 아카데미를 잘 보냈다고 생각하기로 했다</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/caf8c160-10dd-44e2-92a8-4749ab055981/image.png" alt=""></p>
<p>3학년때 엄청나게 바빴던(알바 2개, 해커톤 연속, 18학점 꽉꽉 전공으로 채운)
<img src="https://velog.velcdn.com/images/lazy_hong/post/9acda8c8-b5d2-4102-9f9f-fc967eb6e989/image.jpeg" alt="">
이후로 갑자기 쎄게 번아웃이 와서 1년은 알바만 하면서 지냈다.</p>
<p>개발을 본격적으로(?) 하기 시작한 완전 초창기에 다양한 사람을 만나게 되었는데 지금 생각하면 좋은 경험이였지만 그때 당시에 나를 번아웃으로 이끈 주범이기도 했다.</p>
<p>나는 운이 좋게도 대학생활 때 경험한 프로젝트 모두 기획, 디자인, 프론트, 백이 각각 있는 팀에서 진행하게 되었지만 정말 각기 다른 시선을 가지고 있다보니 소통에서 오는 마찰과 스트레스가 생각보다 컸다. </p>
<p>서로 다른 나라 언어 쓰고 대화하는데 번역기는 없는 기분이랄까? 이것은 프로젝트 결과에도 좋지 않은 영향을 미쳤고 이를 계기로 나는 개발 프로젝트에 참여하지 않았다. 나의 힘듦이 99/100 이였는데 1을 딱 더해버려서 100/100이 되어버렸다.</p>
<p>한.. 한달을 그냥 지내다보니 내가 잘 맞는지, 간절한 건지에 대해서 생각해 봤는데 나는 개발자를 계속 할 것 같기는 한데 개발 그 자체보다는 사람과 사람 사이에서의 대화, 방식, 언행 그리고 예상치 못 한 상황 등 이런 환경에서 오는 스트레스를 대처하는 방법을 몰라서 취업을 하더라도 즐기지 못 하는 사람이 될 것 같다는 생각이 들었다.</p>
<p>어떤 개발자가 되자 보다는 어떤 사람이 되자를 먼저 생각하기로 했다.</p>
<p>개발자라는 직업은 삶에 전부는 아니지 않나? 살아가는 수단일 뿐이지.. 그럼 인간으로서 나는 어떤 점이 부족한지에 대해서 생각했다. </p>
<ul>
<li>나는 불특정 다수를 만나는 것을 싫어한다 -&gt; 예측을 못 하기 때문이다.</li>
<li>나는 말을 먼저 걸기 두려워 한다 -&gt; 거절당할 수 있기 때문이다.</li>
</ul>
<p>그래서 나는.. 그냥 아픈 곳은 더 때려야한다라는 마음으로 가장 기피하고 가장 하기 싫은 영업직 알바를 아카데미 오기 전까지 약1년 했다. 예전에는 나한테 이런일이.. 했다면, 지금은.. ㅋㅋ
<img src="https://velog.velcdn.com/images/lazy_hong/post/929d35b3-a158-476a-a0ba-bfb732cba365/image.jpeg" alt=""></p>
<p>거절당하기 두려워하고 말 걸기 싫어하고 변수를 제일 싫어하는 나는.. 알바 이후로 외향인이냐. 이곳 저곳 말 잘 걸고 다닌다. 라는 말을 듣고 다니는 걸 보면 1년동안 열심히 살았네 싶기도 하다.</p>
<p>다시 번아웃의 파도에 빠지지 않기 위해 나는 규칙을 세웠는데</p>
<ul>
<li>on/off 확실하게 하기</li>
<li>일찍 자고 일찍 일어나기</li>
<li>일주일에 1번이라도 좋으니 운동하기</li>
<li>주말에는 장소를 바꿔서 개발하기</li>
<li>아무 계획 없이 나가보기</li>
</ul>
<p>잘 지켰고 앞으로도 잘 지킬 것이다. <del>다른사람들도 있나? 있으면 묻고 싶다</del>
<img src="https://velog.velcdn.com/images/lazy_hong/post/474402e7-ba7c-4db7-a7be-01bf935bf9a9/image.png" alt=""></p>
<p>직장인이 되서 겪을 바에는 3학년 대학생 때 미리 겪는게 났다. 적어도 대처법은 미리 알게 되었으니깐..</p>
<p><strong>대처법 : 내가 가장 하기 싫은 일을 하면 됨. 영업직 하세요</strong></p>
<p>그냥 일반적인 대화가 되는 것에 대해 감사하게 된다. </p>
<p>아카데미에서 정말 많은 걸 배웠고 좋은 사람들을 만났다. 배울 점들이 많은 또래들을 많이 봤다는 것도 정말 운이 좋았다. 많은 생각들을 하게 됬는데 난 그냥 개반인으로 살아야 될 것 같다. </p>
<p><strong>신 &gt; 반신반인 &gt; 개반인 == 나 &gt; 일반인</strong></p>
<p>신과 반신반인을 너무 많이 봐서,, 내가 취업이 될려나..? 라는 생각도 많이 하게 됬지만, 모든 사람은 다 각자의 역할이 있으니 괜찮다 하면서 마음을 잘 다독였다.</p>
<p>고등학생 때 입시가 엄청 큰 벽이였고 스트레스였고 우울했었는데 대학생이 되어보니 내 인생에서 그렇게 큰 일도 아니였다. 그 겪을 당시에는 엄청 난 것처럼 느껴지지만 지나고 보면 별 일 아닌 크고 작은 일들을 경험해 보니 그냥 즐기면 됬었는데 즐기지 못 해서 더 힘들지 않았나 싶다. 막판에는 미친척하고 즐겼던 적이 있었는데 그게 꽤 효과가 좋았다.</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/938c3561-b892-478a-b117-244bddb12e10/image.png" alt=""></p>
<p>그냥 이 나이대에 맞는 고민만 하고 있다면 행복한 것이라고 생각한다. 
사실.. 앞으로 얼마나 즐거울지 기대된다 ㅎ</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/952a9500-99a5-4d28-8ca7-ccaa55e93ef0/image.png" alt=""></p>
<p><em>비공개인 글들도 차차..정리하자..</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA : JDBC+ SQL]]></title>
            <link>https://velog.io/@lazy_hong/JAVA-JDBC-SQL</link>
            <guid>https://velog.io/@lazy_hong/JAVA-JDBC-SQL</guid>
            <pubDate>Wed, 30 Apr 2025 00:21:14 GMT</pubDate>
            <description><![CDATA[<img src="https://velog.velcdn.com/images/lazy_hong/post/867c7789-f267-4dee-bb80-bf50972299fb/image.png" width="80%"/>

<p><strong>DriverManager</strong> : Connection 객체 생성 
<strong>-&gt;</strong> <strong>Connection</strong> : Statement, PreparedStatement 구현 객체 생성, 트랜잭션 처리 및 DB 연결을 끊을 때 사용
<strong>-&gt;</strong> <strong>1) Statement</strong> : 매개변수 없이 직접 입력
<strong>-&gt;</strong>    <strong>2) PreparedStatement</strong> : 매개변수화된 SQL문 사용</p>
<p>실행 결과
INSERT , UPDATE , DELETE -&gt; <strong>executeUpdate()</strong> 정수(변경된 행의 개수)
SELECT -&gt; *<em>executeQuery() *</em>return 타입 : ResultSet</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTPS , HTTP 차이 대답하라구요..]]></title>
            <link>https://velog.io/@lazy_hong/HTTPS-vs-HTTP</link>
            <guid>https://velog.io/@lazy_hong/HTTPS-vs-HTTP</guid>
            <pubDate>Thu, 17 Apr 2025 03:10:32 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lazy_hong/post/6b3d2371-e57d-4985-b5e1-eaf182808b1e/image.png" alt=""></p>
<h2 id="http">HTTP</h2>
<p>HTTP(Hypertext Transfer Protocol)는 클라이언트와 서버 간 통신을 위한 통신 규칙 세트 또는 프로토콜이다. </p>
<p>사용자가 웹 사이트를 방문하면 사용자 브라우저가 웹 서버에 HTTP 요청을 전송하고 웹 서버는 HTTP 응답으로 응답한다.웹 서버와 사용자 브라우저는 데이터를 일반 텍스트로 교환한다. 간단히 말해 HTTP 프로토콜은 네트워크 통신을 작동하게 하는 기본 기술이다.</p>
<h2 id="https">HTTPS</h2>
<p>이름에서 알 수 있듯이 HTTPS(Hypertext Transfer Protocol Secure)는 HTTP의 확장 버전 또는 더 안전한 버전이다. HTTPS에서는 브라우저와 서버가 데이터를 전송하기 전에 안전하고 암호화된 연결을 설정한다.</p>
<h2 id="http-프로토콜은-어떻게-작동하">HTTP 프로토콜은 어떻게 작동하?</h2>
<p>HTTP는 OSI(Open Systems Interconnection) 네트워크 통신 모델의 애플리케이션 계층 프로토콜이다. HTTP는 여러 유형의 요청과 응답을 정의하는데 예를 들어, 웹 사이트의 일부 데이터를 보려는 경우 HTTP GET 요청을 전송하고 연락처 양식 작성과 같은 일부 정보를 전송하려는 경우 HTTP PUT 요청을 전송한다.</p>
<p>마찬가지로, 서버는 숫자 코드 및 데이터 양식으로 다양한 유형의 HTTP 응답을 전송한다.</p>
<pre><code>200 - OK(정상)
400 - Bad request(잘못된 요청)
404 - Resource not found(리소스를 찾을 수 없음)</code></pre><p>이러한 요청 및 응답 통신은 일반적으로 사용자에게 보이지 않는다. 브라우저와 웹 서버가 사용하는 통신 방식이므로 World Wide Web은 모든 사용자에게 일관되게 작동합니다.</p>
<h2 id="https-프로토콜은-어떻게-작동하나">HTTPS 프로토콜은 어떻게 작동하나?</h2>
<p>HTTP는 암호화되지 않은 데이터를 전송한다. 즉, 브라우저에서 전송된 정보를 제3자가 가로채고 읽을 수 있다.통신에 또 다른 보안 계층을 추가하기 위해 HTTPS로 확장된 것이다. </p>
<p>HTTPS는 HTTP 요청 및 응답을 SSL 및 TLS 기술에 결합한 것.</p>
<p>HTTPS 웹 사이트는 독립된 인증 기관(CA)에서 SSL/TLS 인증서를 획득해야 한다. 이러한 웹 사이트는 신뢰를 구축하기 위해 데이터를 교환하기 전에 브라우저와 인증서를 공유하는데 SSL 인증서는 암호화 정보도 포함하므로 서버와 웹 브라우저는 암호화된 데이터나 스크램블된 데이터를 교환할 수 있다.</p>
<pre><code>1. 사용자 브라우저의 주소 표시줄에 https:// URL 형식을 입력하여 HTTPS 웹 사이트를 방문합니다.
2. 브라우저는 서버의 SSL 인증서를 요청하여 사이트의 신뢰성을 검증하려고 시도합니다.
3. 서버는 퍼블릭 키가 포함된 SSL 인증서를 회신으로 전송합니다.
4. 웹 사이트의 SSL 인증서는 서버 아이덴티티를 증명합니다. 브라우저에서 인증되면, 브라우저가 퍼블릭 키를 사용하여 비밀 세션 키가 포함된 메시지를 암호화하고 전송합니다.
5. 웹 서버는 개인 키를 사용하여 메시지를 해독하고 세션 키를 검색합니다. 그런 다음, 세션 키를 암호화하고 브라우저에 승인 메시지를 전송합니다.
6. 이제 브라우저와 웹 서버 모두 동일한 세션 키를 사용하여 메시지를 안전하게 교환하도록 전환합니다.</code></pre><h2 id="https-설정-비용이-http보다-더-많이-드나">HTTPS 설정 비용이 HTTP보다 더 많이 드나?</h2>
<p>HTTPS를 사용하려면 서버에서 SSL/TLS 인증서를 획득하고 유지 관리해야 하는데 과거에는 대부분의 인증 기관이 인증서 등록 및 유지 관리에 대해 연간 요금을 청구했지만 이제는 더 이상 그렇지 않는다고 한다.</p>
<p>예를 들어, AWS에서는 AWS Certificate Manager(ACM)를 제공한다. ACM은 AWS 서비스 및 내부 연결 리소스와 함께 사용할 수 있는 퍼블릭 및 프라이빗 SSL/TLS 인증서를 프로비저닝, 관리 및 배포, 구매, 업로드 및 갱신하는 시간 소모적인 수동 프로세스를 대신 처리해준다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA : 네트워크 입출력]]></title>
            <link>https://velog.io/@lazy_hong/JAVA-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%9E%85%EC%B6%9C%EB%A0%A5</link>
            <guid>https://velog.io/@lazy_hong/JAVA-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%9E%85%EC%B6%9C%EB%A0%A5</guid>
            <pubDate>Wed, 16 Apr 2025 02:42:04 GMT</pubDate>
            <description><![CDATA[<h1 id="🍋-네트워크-기초">🍋 네트워크 기초</h1>
<p>LAN (local area network) 
WAN
ROUTER </p>
<h2 id="서버와-클라이언트">서버와 클라이언트</h2>
<p>서버란?
클라이언트란?</p>
<h2 id="ip주소">IP주소</h2>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/9f801368-dfc5-4488-81a0-7a327857e243/image.png" alt=""></p>
<h3 id="1-ip주소">1) IP주소</h3>
<blockquote>
<p>IP 주소는 아파트 호수라서 기기마다 구분이 가능함. 기기마다 다르고 아파트 호수 같은 것</p>
</blockquote>
<pre><code class="language-java">IP 주소: 192.168.10.20

네트워크 주소 : 192.168.10 // 어디까지가 같은 구역인지 나누는 기준 
호스트 주소: 20 </code></pre>
<p>✅ 네트워크 주소와 호스트 주소 구분 가능한 이유는? 
-&gt; <strong>서브넷 마스크</strong> 255.255.255.0 (이진수 11111111.11111111.11111111.00000000)와 IP주소의 <strong>AND 연산</strong> 때문이다</p>
<br/>

<h3 id="2-네트워크-주소">2) 네트워크 주소</h3>
<blockquote>
<p>네트워크 주소가 같다 == 같은 LAN에 속한다</p>
</blockquote>
<p>같은 네트워크(같은 LAN) 안에 있는 컴퓨터들끼리는 서로 직접 통신할 수 있지만, 다른 네트워크에 있는 컴퓨터와는 라우터나 게이트웨이를 통해서 통신한다
<br/></p>
<h3 id="3-서브넷-마스크">3) 서브넷 마스크</h3>
<blockquote>
<p>네트워크 주소와 호스트 주소를 구분해주기 위함</p>
</blockquote>
<p>IP주소와 서브넷 마스크를 AND 연산한 결과(둘다 1이면 1 아니면 0)로 네트워크 주소를 구분하기 때문이다</p>
<pre><code class="language-java">IP 주소: 192.168.10.20 (이진수로 11000000.10101000.00001010.00010100)
서브넷 마스크: 255.255.255.0 (이진수로 11111111.11111111.11111111.00000000)</code></pre>
<p>서브넷 마스크의 앞의 3바이트는 전부 다 1이여서 IP주소 앞 3바이트가 그대로 나온다. _사실상 IP주소에서 그냥 앞에 3바이트가 네트워크 주소라고 봐도됨
_</p>
<blockquote>
<p>🧑‍💻 예시 1: 서브넷 마스크가 255.255.255.0 
서브넷 마스크: <strong>255.255.255.0</strong>
네트워크 주소: 192.168.10.0</p>
</blockquote>
<p>⭕ 예시:
IP 1: 192.168.10.20
IP 2: 192.168.10.50</p>
<p><strong>두 IP는 같은 네트워크 (네트워크 주소는 192.168.10.0)</strong></p>
<blockquote>
<p>🧑‍💻 예시 2: 
서브넷 마스크: <strong>255.255.0.0</strong>
네트워크 주소: 192.168.0.0</p>
</blockquote>
<p>⭕ 예시:
IP 1: 192.168.10.20
IP 2: 192.168.200.50</p>
<p>*<em>192.168.10.20과 192.168.200.50이 같은 네트워크(192.168.0.0 네트워크) *</em></p>
<h3 id="4-기본-게이트-웨이">4) 기본 게이트 웨이</h3>
<p>: 기본 게이트 웨이의 IP는 로컬 네트워크의 네트워크 주소에 속해야 하낟
로컬 네트워크의 네트워크 주소가 192.168.0이면</p>
<p>IP 주소 범위는 <strong>192.168.10.1부터 192.168.10.254까지</strong> 사용 가능해.
192.168.10.0은 네트워크 주소이고, 192.168.10.255는 브로드캐스트 주소이기때문에 제외</p>
<p> 로컬 네트워크의 일부여야 패킷을 로컬 네트워크에서 외부 네트워크로 라우팅할 수 있어</p>
<h2 id="port-번호">Port 번호</h2>
<p>port = 항구
모든 프로그램은 각각 하나의 유일한 포트번호를 가지고 있다. 선점시 가용하지 못 한다.</p>
<h1 id="🍋-tcp-네트워킹">🍋 TCP 네트워킹</h1>
<blockquote>
<p><strong><em>Transmission Control Protocol</em></strong> : 수신여부 확인(안정적) , 느림</p>
</blockquote>
<p>1:1 통신</p>
<p>1️⃣ 상대방이 연결된 상태에서 데이터 주고받는다.
2️⃣ <strong>1)</strong> 클라이언트가 연결 요청하고 <strong>2)</strong> 서버가 연결 수락하면 통신 회선이 고정 (고정된 회선)
3️⃣ 순서대로 전달</p>
<p>=&gt; 안정적</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/b2f9293b-e98d-4904-a4ed-2a2fd664bbd7/image.png" alt=""></p>
<h2 id="tcp-서버--클라이언트">TCP 서버 / 클라이언트</h2>
<h3 id="tcp-서버">TCP 서버</h3>
<ol>
<li><p>ServerSocket 객체 생성</p>
<pre><code class="language-java">ServerSocket serverSocket = new ServerSocket();
``

</code></pre>
</li>
</ol>
<p>  1-1) 연결 요청 수락 위해서 accept() 메소드 실행
 2. 클라이언트 연결 요청으로 통신용 Socket 들어옴 return
 3. 서버종료** (반드시 serverSocket.close())**</p>
<h3 id="tcp-클라이언트">TCP 클라이언트</h3>
<ol>
<li>클라이언트에게 서버 요청 (객체 생성 시 생성자 매개값으로 서버IP주소와 port번호)<pre><code class="language-java">Socket socket = new Socket(&quot;IP&quot;, port번호);</code></pre>
</li>
<li>연결 끊고 싶으면 (socket.close())</li>
</ol>
<h1 id="🍋-udp-네트워킹">🍋 UDP 네트워킹</h1>
<blockquote>
<p><strong><em>User Datagram Protocol</em></strong> 수신여부 미확인(불안정적), 빠름</p>
</blockquote>
<p>1:다 통신</p>
<p>발신자가 알방적으로 데이터 보내는 방식으로 요청 및 수락 과정이 없다
고정회선이 아니라 여러 회선을 통해 데이터 전송되기 때문에 잘못된 회선으로 인해 데이터 손실이 발생</p>
<p>DatagramSocket 은 수/발신점
DatagramPacket 은 주고 받는 데이터</p>
<h2 id="udp서버">UDP서버</h2>
<p>UDP 서버는 요청 및 수락 과정이 없기때문에 클라이언트가 보낸 DatagramPacket을 항상 받을 준비를 해야 한다 =&gt; receive()</p>
<ol>
<li>DatagramSocket 생성 + 포트 바인딩<pre><code class="language-java">DatagramSocket socket = new DatagramSocket(9999);</code></pre>
</li>
<li>DatagramPacket 생성 (수신용 버퍼 포함)<pre><code class="language-java">DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);</code></pre>
</li>
<li>데이터 수신 (socket.receive)<pre><code class="language-java">// 3. 데이터 수신 (클라이언트가 보내올 때까지 대기)
socket.receive(receivePacket);</code></pre>
</li>
<li>데이터 처리</li>
</ol>
<h1 id="🍋-서버의-동시-요청-처리">🍋 서버의 동시 요청 처리</h1>
<p>다수의 클라이언트와 통신을 하면 먼저 연결한 클라이언트이 요청을 처리한 후 다음 클라이언트의 요청을 처리하도록 되어 잇다 == 먼저 열결한 클라이언트의 요청 처리 시간이 길어질수록 다음 클라이언트의 요청 처리 작업이 지연됨 =&gt; <strong>스레드풀 사용</strong></p>
<h2 id="스레드풀">스레드풀</h2>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/482f9c15-f536-42e7-8fa9-b76a99638287/image.png" alt="">
: 여러개의 스레드를 생성해 놓은 후 작업이 생기면 가져가서 사용 하고 다시 갔다놓고 사용하고...(재사용) 한정된 스레드로 많은 작업처리 가능</p>
<h1 id="🍋-json-데이터-형식">🍋 JSON 데이터 형식</h1>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/aec30789-cf74-433e-8b14-a214b54901e9/image.png" alt="">
<img src="https://velog.velcdn.com/images/lazy_hong/post/350c9314-ad2c-40d2-9f2e-ede0516bb486/image.png" alt=""></p>
<h2 id="표기법과-관련-클래스">표기법과 관련 클래스</h2>
<h2 id="표기법">표기법</h2>
<pre><code class="language-json">객체 표기 
{
  &quot;student&quot;:true,
  &quot;skill&quot;:[&quot;java&quot;,&quot;c&quot;,&quot;c++&quot;],
  &quot;name&quot;:&quot;한겨울&quot;,
  &quot;tel&quot;:{&quot;mobile&quot;:&quot;010-1234-1234&quot;,&quot;home&quot;:&quot;02-123-124&quot;},
  &quot;id&quot;:&quot;winter&quot;,
  &quot;age&quot;:25
}
배열 표기 []</code></pre>
<h2 id="관련-클래스">관련 클래스</h2>
<blockquote>
<p>JSONObject : 객체 표기를 생성하거나 파싱
JSONArray : JSON 배열 표기를 생성하거나 파싱</p>
</blockquote>
<p>💭 JSON에서 속성 순서는 중요하지 않고 줄바꿈 처리 안됨 =&gt; 네트워크 전송량 줄여줌</p>
<pre><code class="language-java">public static void main(String[] args) throws IOException {
        JSONObject root = new JSONObject();

        root.put(&quot;id&quot;, &quot;lazy&quot;);
        root.put(&quot;name&quot;, &quot;게으른&quot;);
        root.put(&quot;age&quot;, 25);
        root.put(&quot;student&quot;, true);

        JSONObject tel= new JSONObject();

        tel.put(&quot;home&quot;, &quot;02-123-124&quot;);
        tel.put(&quot;mobile&quot;, &quot;010-1234-1234&quot;);
        root.put(&quot;tel&quot;, tel);

        JSONArray skill = new JSONArray();
        skill.put(&quot;java&quot;);
        skill.put(&quot;c&quot;);
        skill.put(&quot;c++&quot;);

        root.put(&quot;skill&quot;, skill);

        /*String json = root.toString();
        System.out.println(json); */

        System.out.println(root);


    }

    //결과
    {&quot;student&quot;:true,&quot;skill&quot;:[&quot;java&quot;,&quot;c&quot;,&quot;c++&quot;],&quot;name&quot;:&quot;한겨울&quot;,&quot;tel&quot;:{&quot;mobile&quot;:&quot;010-1234-1234&quot;,&quot;home&quot;:&quot;02-123-124&quot;},&quot;id&quot;:&quot;winter&quot;,&quot;age&quot;:25}
</code></pre>
<br/>

<h2 id="json-파일-읽고-json-파싱">.json 파일 읽고 JSON 파싱</h2>
<h4 id="파일-읽어오기">파일 읽어오기</h4>
<pre><code>BufferedReader br = new BufferedReader(
    new FileReader(&quot;파일경로&quot;, Charset.forName(&quot;UTF-8&quot;)) 
);

String json = br.readLine(); //줄바꿈이 없어서 한줄만 읽어오면 된다.
br.close();</code></pre><h4 id="json-파싱">JSON 파싱</h4>
<pre><code>JSONObject root = new JSONObject(json); //중괄호는 객체, 대괄호는 배열로 알아서 나눠 줌 DB에 알아서 저장</code></pre><br/>

<h4 id="속성-정보-직접-보고-싶다면">속성 정보 직접 보고 싶다면</h4>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/67f944fc-02a2-4187-9d80-2024cee67f84/image.png" alt=""></p>
<br/>

<h1 id="🍋-네이버-api">🍋 네이버 API</h1>
<pre><code class="language-java">  JSONObject root = new JSONObject(responseBody);
  JSONArray items = root.getJSONArray(&quot;items&quot;);

//내코드
  for(int i = 0; i &lt; items.length(); i++) {
            System.out.print(&quot;title: &quot; + items.getJSONObject(i).getString(&quot;title&quot;) + &quot;  &quot;);
            System.out.print(&quot;link: &quot; + items.getJSONObject(i).getString(&quot;link&quot;));

            System.out.println();
        }

  for(int i = 0; i &lt; items.length(); i++) {
            JSONObject item = (JSONObject)items.get(i);
            System.out.print(&quot;title: &quot; + item.getString(&quot;title&quot;) + &quot;  &quot;);
            System.out.print(&quot;link: &quot; + item.getString(&quot;link&quot;));

            System.out.println();
        }</code></pre>
<h1 id="🍋-tcp-채팅-프로그램">🍋 TCP 채팅 프로그램</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA : 스트림 요소 처리, 파일 입출력]]></title>
            <link>https://velog.io/@lazy_hong/JAVA-%EC%8A%A4%ED%8A%B8%EB%A6%BC-%EC%9A%94%EC%86%8C-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@lazy_hong/JAVA-%EC%8A%A4%ED%8A%B8%EB%A6%BC-%EC%9A%94%EC%86%8C-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Tue, 15 Apr 2025 00:46:12 GMT</pubDate>
            <description><![CDATA[<h1 id="🍋-스트림이란">🍋 스트림이란</h1>
<blockquote>
<p>for문 iterator 대신 코드 간결</p>
</blockquote>
<p>배열이랑 컬렉션에만 사용되나? .. 아님
배열이나 컬렉션뿐 아니라, 값 자체, 빌더, 함수형 방식, 파일, 숫자 범위 등 다양한 방식으로</p>
<p>내부 반복자이(forEach와 같이 메소드에서 알아서 == 우리가 써주지 않아도 반복분 처리)므로 처리 속도가 빠르고 병렬 처리에 효율적</p>
<p>외부 반복자? : for, iterator 같이 <strong>반복의 주도권이 개발자에</strong>게</p>
<pre><code class="language-java">List&lt;String&gt; list = Arrays.asList(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;);

for (String s : list) {         // 향상된 for문 (외부 반복)
    System.out.println(s);
}
</code></pre>
<pre><code class="language-java">Iterator&lt;String&gt; it = list.iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}</code></pre>
<p>람다식과 함께 쓰기 때문에 간결</p>
<h2 id="인덱스를-이용하는-반복문에-스트림이-좋을까">인덱스를 이용하는 반복문에 스트림이 좋을까?</h2>
<h2 id="스트림-만들기">스트림 만들기</h2>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/7eea2496-a8a8-494c-95ac-0323deaa5343/image.png" alt=""></p>
<ul>
<li>배열 스트림 : Arrays.stream(배열) <pre><code class="language-java">int[] arr = new int[] {1,2,3};
IntStream intStream = Arrays.stream(arr);
</code></pre>
</li>
</ul>
<p>//arr없이 바로
IntStream intStream = Arrays.stream(new int[]{1,2,3});</p>
<pre><code>
```java
Integer[] arr = new Integer[] {1,2,3};
Stream&lt;Integer&gt; stream = Arrays.stream(arr);

//arr없이 바로
Stream&lt;Integer&gt; stream = Arrays.stream(new iInteger[]{1,2,3};</code></pre><p>Integer[]    Stream &lt;Integer&gt;    Arrays.stream(new Integer[]{...})
int[]    IntStream    Arrays.stream(new int[]{...})</p>
<ul>
<li>컬렉션 스트림 : .strean()</li>
</ul>
<p>🚫 제네릭&lt;&gt; 은 기본형이 안되기 때문에 IntStream이라고 따로 맀음</p>
<table>
<thead>
<tr>
<th>기본형</th>
<th>스트림 타입</th>
</tr>
</thead>
<tbody><tr>
<td>int</td>
<td>IntStream</td>
</tr>
<tr>
<td>long</td>
<td>LongStream</td>
</tr>
<tr>
<td>double</td>
<td>DoubleStream</td>
</tr>
</tbody></table>
<h1 id="🍋-중간처리-최종처리">🍋 중간처리, 최종처리</h1>
<p>스트림은 파이프처럼 계속 연결해서 사용 가능하다
== 스트림 파이프라인
🚫파이프라인 맨 끝에는 최종처리 라인이 있어야 한다.</p>
<h2 id="1-중간처리-filtering-mapping-sorting">1. 중간처리 (filtering, mapping, sorting,..)</h2>
<h3 id="mapping--요소변환">mapping : 요소변환</h3>
<p>boxed() 
<strong>mapToInt() : T -&gt; int</strong></p>
<h3 id="filtering">filtering</h3>
<h3 id="sorting">sorting</h3>
<h3 id="looping">looping</h3>
<h2 id="2-최종처리-collecting-matching--결과가-하나">2. 최종처리 (collecting, matching..) : 결과가 하나</h2>
<p><strong>forEach()</strong></p>
<h3 id="optional-클래스">Optional 클래스</h3>
<p>isPresent() : boolean</p>
<p>ifPresent(메소드 재정의해서 쓰면됨) : void
//null체크를 하지 않아도 되서 편한거다</p>
<h3 id="커스텀집계-reduace">커스텀집계 reduace()</h3>
<h2 id="리소스로부터-스트림-얻기">리소스로부터 스트림 얻기</h2>
<h4 id="기본형---참조자료형-arraysstream-이용">기본형 -&gt; 참조자료형 Arrays.stream() 이용</h4>
<pre><code class="language-java">int[] arr = {1, 2, 3, 4, 5};

// int[] → IntStream → Stream&lt;Integer&gt;
Stream&lt;Integer&gt; stream = Arrays.stream(arr).boxed();
</code></pre>
<h1 id="🍋-파일-입출력">🍋 파일 입출력</h1>
<blockquote>
<p>바이트 스트림
최상위 클래스는 InputStream, OutputStream
하위클래스들은 아래처럼
입력 : XxxInputStream
출력 : XxxOutputStream</p>
</blockquote>
<blockquote>
<p>텍스트 스트림 
최상위 클래스는 Reader Writer
입력: XXXReader
출력: XxxWriter</p>
</blockquote>
<h2 id="1-바이트-입출력-스트림">1. 바이트 입출력 스트림</h2>
<blockquote>
<p><strong>프로그램기준</strong> 들어오면 입력 스트림, 나가면 출력 스트림</p>
</blockquote>
<h3 id="바이트-출력--읽기">바이트 출력 / 읽기</h3>
<p>출력 : write(int b) int는 4바이트지만 끝 1바이트만 출력
write() -&gt; flush() -&gt; close()
입력 : read() : 1바이트를 읽고 int(4byte)로 리턴
read() -&gt; close()</p>
<h3 id="바이트-배열-출력--읽기">바이트 배열 출력 / 읽기</h3>
<p>출력 : write(byte[] b) 
입력 : read() </p>
<h2 id="2-문자-입출력-스트림">2. 문자 입출력 스트림</h2>
<h3 id="문자-출력--읽기">문자 출력 / 읽기</h3>
<h2 id="3-보조-스트림">3. 보조 스트림</h2>
<p>바이트 스트림을 문자스트림으로 변환해서 사용하려면 보조 스트림이 필요하다</p>
<h3 id="변환-스트림">변환 스트림</h3>
<blockquote>
<p>보조스트림 변수 = new 보조스트림(입출력스트림);</p>
</blockquote>
<p> 1) InputStream -&gt; Reader</p>
<p>2) OutputStream -&gt; Writer</p>
<h3 id="성능-향상-스트림">성능 향상 스트림</h3>
<p>메모리 버퍼를 제공하여 프로그램의 실행 성능을 향상시키는 보조 스트림</p>
<p>1) 바이트 스트림 : <strong>Buffered</strong>OuputStream <strong>Buffered</strong>InputStream
2) 문자 스트림 : <strong>Buffered</strong>Reader <strong>Buffered</strong>Writer</p>
<p>문자 입력 스트림 Reader에서 성능향상스트림을 사용하면 readLine() 메소드를 사용할 수 있다.</p>
<h3 id="기본-타입-스트림">기본 타입 스트림</h3>
<h3 id="프린트-스트림">프린트 스트림</h3>
<h2 id="4-file과-files-클래스">4. File과 Files 클래스</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA : 컬렉션 프레임워크(List, Set, Map), 람다식, 메소드 참조]]></title>
            <link>https://velog.io/@lazy_hong/JAVA-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACList-Set-Map-%EB%9E%8C%EB%8B%A4%EC%8B%9D-%EB%A9%94%EC%86%8C%EB%93%9C-%EC%B0%B8%EC%A1%B0</link>
            <guid>https://velog.io/@lazy_hong/JAVA-%EC%BB%AC%EB%A0%89%EC%85%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACList-Set-Map-%EB%9E%8C%EB%8B%A4%EC%8B%9D-%EB%A9%94%EC%86%8C%EB%93%9C-%EC%B0%B8%EC%A1%B0</guid>
            <pubDate>Fri, 11 Apr 2025 05:44:47 GMT</pubDate>
            <description><![CDATA[<h1 id="🍋-컬렉션-프레임워크">🍋 컬렉션 프레임워크</h1>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/27810ee5-db13-4dfa-b462-67acf5da0739/image.png" alt=""></p>
<ul>
<li>List와 Set은 Collection 인터페이스를  구현</li>
</ul>
<br/>

<h2 id="list">List</h2>
<blockquote>
<p>✅ 순서 있음 ==&gt; .get(i) 사용하여 인덱스로 접근가능
✅ 중복허용 </p>
</blockquote>
<p>❓ <em><strong>배열이랑 가장 유사한데 List를 사용하는 이유는?</strong></em></p>
<p>: 배열은 크기를 선언하면 바꾸지 못함 =&gt; 객체 새로 생성해야한다.
리스트는 동적 크기 추가가 용이 =&gt; add()로 끝나버림
추가, 삭제 , 정렬, 검색 가능하다는 점이 장점이다.</p>
<hr>
<h3 id="초기화">초기화</h3>
<pre><code class="language-java">
//1차원
List&lt;String&gt; list = new ArrayList&lt;&gt;();
list.add(&quot;&quot;);

//2차원
List&lt;List&lt;Integer&gt;&gt; = new ArrayList&lt;&gt;();
list.add(new ArrayList&lt;&gt;(...));

//배열
List&lt;int[]&gt; list = new ArrayList&lt;&gt;();
list.add(new int[]{});

//추가 add() 삭제 remove() 안됨
List&lt;String&gt; list = Arrays.asList(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;);
</code></pre>
<h3 id="메서드">메서드</h3>
<p>*<em>1) 객체 추가 *</em></p>
<blockquote>
</blockquote>
<p>add(E e) : 객체 맨끝 추가
add(int index, E e) : 객체를 해당 인덱스에 추가</p>
<p><strong>2) 객체 조회</strong></p>
<blockquote>
</blockquote>
<p>get(int index) : E 
containes(Object o) : boolean 주어진 객체가 있는지 없는지 여부
size() : int 전체 객체수 리턴</p>
<p><strong>3) 객체 삭제</strong></p>
<blockquote>
</blockquote>
<p>remove(int index) 인덱스에 저장된 객체를 삭제</p>
<br/>

<h3 id="출력하기">출력하기</h3>
<p><strong>1-1) 기본 리스트 출력</strong></p>
<p><em>📌  System.out.print(ln)</em></p>
<p>💭 내부적으로 재정의한 toString() 호출됨</p>
<pre><code class="language-java">//추가 삭제 예시를 드는게 아니라서 asList 씀
List&lt;String&gt; list = Arrays.asList(&quot;a&quot;,&quot;b&quot;,&quot;c&quot;); 
System.out.print(list); // [a,b,c]</code></pre>
<p>_📌 for _ </p>
<p> 💭 주로 한줄씩 출력하고 싶을 때</p>
<pre><code class="language-java">for(String string : list) {
    System.out.println(string);
}
//a
//b
//c</code></pre>
<p>_📌 forEach _</p>
<blockquote>
<p>forEach(Consumer&lt;? super String&gt;)</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/28ce8af8-1907-4658-b80a-efc92c7c094e/image.png" alt=""></p>
<p>: Consumer&lt;? super String&gt; -&gt;  String을 포함한 상위 타입 모두 허용
✅ Consumer<T> 란?
입력값은 받고, 반환값은 없는 <strong>함수를 표현</strong>할 때 쓰는 인터페이스
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}</p>
<p>? 꼭 forEach 쓸대 람다식을 써야하나? 노노</p>
<p>내가 했던... </p>
<pre><code>list.forEach(System.out.print(list));</code></pre><p>이건 함수의 호출 결과를 넣으려는 것이기 때문에 메서드 참조형태를 넣어야한다.
forEach(함수) 여야하는데
System.out.print -&gt; void
즉. forEach(void)이기때문에 안됨.
<img src="https://velog.velcdn.com/images/lazy_hong/post/d88a220c-fa53-4947-a717-fce8eca16792/image.png" alt=""></p>
<pre><code>list.forEach(System.out::print);
list.forEach((item) -&gt; System.outprin(item))</code></pre><p>_📌 for _ </p>
<p><strong>1-2) 2차원</strong>
2) 반복문 이용하여 출력하기
3) .forEach 사용하기
4) stream</p>
<h2 id="set">Set</h2>
<blockquote>
<p>◾ 순서 없음
◾ 중복허용 안 함
◾ add()</p>
</blockquote>
<p>🚫 Set은 List의 하위 클래스이고 List는 자식 클래스의 재정의된 메소드 사용이 가능하기 때문에 (List가 가지고 있는 메소드를 재정의 한것이기 때문에) 다양하게 사용가능하다.</p>
<h2 id="map">Map</h2>
<blockquote>
<p>◾ key - value 값으로 저장
 ◾ key 값은 겹치면 안됨
◾ put() , get()</p>
</blockquote>
<p><a href="https://developer-talk.tistory.com/745">https://developer-talk.tistory.com/745</a></p>
<h3 id="향상된-for문">향상된 for문</h3>
<h3 id="iterator-">iterator ()</h3>
<blockquote>
<p>컬렉션(List, Map, Set)을 순회할 수 있게 해주는 반복자 객체
즉, for문 while문 없이도 탐색 가능하게 함</p>
</blockquote>
<p>🔥 iterator을 사용하는 이유는 반복 도중에 삭제(remove) 가능하다</p>
<pre><code class="language-java">List&lt;E&gt; list = new Set&lt;&gt;(); 
list.iterator 사용이 가능하다.</code></pre>
<pre><code class="language-java">Set&lt;E&gt; set = new HashSet&lt;&gt;();
Iterator iter = set.Iterator();</code></pre>
<table>
<thead>
<tr>
<th>메소드명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>hasNext() : boolean</td>
<td>객체가 있으면 true, 없으면 false</td>
</tr>
<tr>
<td>next() : E</td>
<td>하나의 객체를 가져온다</td>
</tr>
<tr>
<td>remove(): void</td>
<td>next()로 가져온 객체를 Set컬렉션에서 제거한다</td>
</tr>
</tbody></table>
<br/>

<h3 id="객체를-가져오거나-제거-하는-방법">객체를 가져오거나 제거 하는 방법</h3>
<ol>
<li>객체가 존재하는지 확인</li>
<li>next()로 하나의 객체 가져오기<pre><code class="language-java">while(iterator.hasNext()){
 E e = iterator.next();
 //iterator.remove();
}</code></pre>
</li>
</ol>
<h2 id="comparable-comparator">Comparable, Comparator</h2>
<blockquote>
<p>모두 인터페이스 이기때문에 사용하고자 한다면 인터페이스 내에 선언된 메소드를 <strong>반드시</strong>구현 해야 한다</p>
</blockquote>
<h3 id="comparable">[Comparable]</h3>
<p>구현해야할 메소드는 compareTo(T o)</p>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/6db9d91a-94f8-43be-881c-e9948413ed87/image.png" alt=""></p>
<h3 id="comparator">[Comparator]</h3>
<p>구현해야할 메소드가 많지만 실질적으로 구현해야 하는 것은 comparator(T o1, T o2)</p>
<p><a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html#method.summary">https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html#method.summary</a></p>
<p><a href="https://st-lab.tistory.com/243">https://st-lab.tistory.com/243</a></p>
<h2 id="lifo--fifo">LIFO , FIFO</h2>
<h3 id="lifo--스택stack">LIFO : 스택(stack)</h3>
<pre><code class="language-java">Stack&lt;E&gt; stack = new Stack&lt;&gt;();</code></pre>
<p>push(E item): E 
pop() : E // 맨위 객체를 빼기</p>
<h3 id="fifo--큐queue">FIFO : 큐(Queue)</h3>
<pre><code class="language-java">Queue&lt;E&gt; queue = new LinkedList&lt;E&gt;();</code></pre>
<p>offer(E e): boolean
poll() : E</p>
<h1 id="🍋-람다표현식">🍋 람다표현식</h1>
<blockquote>
<p>(매개변수) -&gt; {실행문}</p>
</blockquote>
<h2 id="조건">조건</h2>
<p>추상메서드가 하나인 인터페이스만 가능</p>
<h2 id="생략">생략</h2>
<p>실행문 하나 일때 중괄호 생략
실행문이 return 하나일때 생략
매개변수가 하나일때 괄호 생략</p>
<p>✅ 메서드 참조 (::)
🎯 문법:</p>
<p>클래스이름::메서드이름
객체이름::메서드이름
예시들:
✔ 정적 메서드 참조</p>
<pre><code>Function&lt;String, Integer&gt; parse = Integer::parseInt;
// 원래는: (s) -&gt; Integer.parseInt(s)</code></pre><p>✔ 인스턴스 메서드 참조 (특정 객체)</p>
<pre><code>List&lt;String&gt; names = Arrays.asList(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;);
names.forEach(System.out::println);
// 원래는: (s) -&gt; System.out.println(s)</code></pre><p>✔ 인스턴스 메서드 참조 (임의 객체)</p>
<pre><code>List&lt;String&gt; names = Arrays.asList(&quot;Kim&quot;, &quot;Lee&quot;, &quot;Park&quot;);
names.sort(String::compareToIgnoreCase);
// 원래는: (a, b) -&gt; a.compareToIgnoreCase(b)</code></pre><p>✅ 생성자 참조
🎯 문법:</p>
<p>클래스이름::new
예시:
✔ 기본 생성자</p>
<p>Supplier&lt;List<String>&gt; supplier = ArrayList::new;
// 원래는: () -&gt; new ArrayList&lt;&gt;()
✔ 매개변수 있는 생성자</p>
<p>Function&lt;String, Person&gt; creator = Person::new;
// 원래는: (name) -&gt; new Person(name)</p>
<p>✅ 요약표 📌</p>
<p>유형    람다식    메서드/생성자 참조
정적 메서드    (x) -&gt; Class.method(x)    Class::method
인스턴스 메서드 (특정 객체)    (x) -&gt; obj.method(x)    obj::method
인스턴스 메서드 (임의 객체)    (x, y) -&gt; x.method(y)    Class::method
생성자    () -&gt; new Class()    Class::new</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JAVA : 제네릭(Generic)]]></title>
            <link>https://velog.io/@lazy_hong/JAVA-%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric</link>
            <guid>https://velog.io/@lazy_hong/JAVA-%EC%A0%9C%EB%84%A4%EB%A6%ADGeneric</guid>
            <pubDate>Thu, 10 Apr 2025 06:49:33 GMT</pubDate>
            <description><![CDATA[<h1 id="제네릭">제네릭</h1>
<blockquote>
<p>실행되는 곳레서 타입 강제 함 -&gt; 해당 타입으로 재정의 -&gt; 컴파일러 사전 체크 = 강제형변화 ㄴ불필요
기본 차입은 넣을 수 없다</p>
</blockquote>
<pre><code class="language-java">import java.util.ArrayList;
import java.util.List;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

public class GenericEx {

    public static void main(String[] args) {
        List list = new ArrayList();
        Order o = new Order();

        o.setNumber(12345);
        list.add(o);

        o.setNumber(12346);
        list.add(o);

        o.setNumber(12347);
        list.add(o);

        for(int i = 0; i &lt; list.size(); i++) {
            System.out.println(list.get(i));
        }

    }

}

@Getter
@Setter
@ToString
class Order{
    private int number = 0;
    private String date;
    private int price = 0;
}
</code></pre>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/c5f287fa-9768-4558-bfef-822296fa572d/image.png" alt=""></p>
<p>같은 o를 3번이나 넣었음</p>
<pre><code class="language-java">public static void main(String[] args) {
        List list = new ArrayList();
        Order o = new Order();

        o.setNumber(12345);
        list.add(o);

        o = new Order(); //새로운 객체
        o.setNumber(12346);
        list.add(o);

        o = new Order(); //새로운객체
        o.setNumber(12347);
        list.add(o);

        for(int i = 0; i &lt; list.size(); i++) {
            System.out.println(list.get(i)); //list.get(i)은 object타입 (최상위)
        }

    }</code></pre>
<p><img src="https://velog.velcdn.com/images/lazy_hong/post/84b297d7-edde-42ab-94ea-e413258004dc/image.png" alt=""></p>
<pre><code class="language-java">for (int i = 0; i &lt; list.size(); i++) {
            System.out.println(list.get(i).getNumber()); //Object.getNumer()인건데 부모가 자식클래스 메소드 사용?? 불가!! 그래서 오류가 남
        }

for (int i = 0; i &lt; list.size(); i++) {
            //System.out.println(((Order)list.get(i)).getNumber()); 형변환해주기 =&gt; 불편해지잖아~~ 그래서 제네릭 쓰는 거임
        }


</code></pre>
<p><strong>Object</strong> java.util.List.get(int index)</p>
<p>Returns the element at the specified position in this list.</p>
<p>The method getNumber() is undefined for the type <strong>Object</strong></p>
<pre><code class="language-java">List&lt;Order&gt; list = new ArrayList&lt;Order&gt;();  //강제형변환을 하지 않아서 좋음   
 for (int i = 0; i &lt; list.size(); i++) {
            //System.out.println(((Order)list.get(i)).getNumber());
            System.out.println(list.get(i).getNumber()); //강제 형변환 불필요
        }
</code></pre>
<p><strong>Order</strong> java.util.List.get(int index)</p>
]]></description>
        </item>
    </channel>
</rss>