<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>go_te.log</title>
        <link>https://velog.io/</link>
        <description>늘 배우는 자세로</description>
        <lastBuildDate>Fri, 26 Jul 2024 06:45:33 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>go_te.log</title>
            <url>https://velog.velcdn.com/images/go_te/profile/e89e319d-5ae4-4d73-bfc1-49c27fb299c4/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. go_te.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/go_te" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[에이블스쿨 - 빅프로젝트 후기]]></title>
            <link>https://velog.io/@go_te/%EC%97%90%EC%9D%B4%EB%B8%94%EC%8A%A4%EC%BF%A8-%EB%B9%85%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@go_te/%EC%97%90%EC%9D%B4%EB%B8%94%EC%8A%A4%EC%BF%A8-%EB%B9%85%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Fri, 26 Jul 2024 06:45:33 GMT</pubDate>
            <description><![CDATA[<h3 id="서론">서론</h3>
<p>블로그에 글을 안쓴지 4개월이 지났는데요....
제가 그렇다고 공부를 안한건 아닙니다. ㅎㅎ...</p>
<p>일단 제가 글을 올리는 구조가</p>
<ol>
<li>수업 들으면서 필기</li>
<li>수업 끝나고 자료랑 같이 수정 (18시 이후)</li>
<li>그러고 또 블로그에 쓸 수 있게 수정...
이런식으로 블로그에 몇번 쓰진 않았지만 수업 끝나고 밥먹은 다음에 또 정리하는게 너무 귀찮고 힘들더라구요... (나약해서 그렇습니다)</li>
</ol>
<p>여태 강의 들으면서 거의 정리는 해두었습니다.. (노션)</p>
<hr>
<h3 id="dokidoki-프로젝트">DOKIDOKI 프로젝트</h3>
<p>저희 팀은 주제 선정부터 애를 먹었습니다 ^-^ 확정은 2주차에 지어졌어요
처음에 <code>청소년을 위한 AI 심리 상담</code> &lt;&lt; 이걸로 밀고 가고있었는데, 경쟁사가 너무 완벽하게 존재..하더라구요. 2~3주만에 경쟁력있게 만들 수는 없겠다라고 판단하고 시원하게 밀었습니다.</p>
<p><code>AI 카페 재고 관리</code>로 갔다가 데이터를 구할수가 없어서 폐기...
돌고 돌아서 결국 2주차에 <code>외국인 노동자를 위한 법률 서비스</code>를 했습니다 호호... 다시 ERD를 짜고 뚝딱뚝딱 만들기 시작했습니다.</p>
<p>해당 깃 레포 주소는 <a href="https://github.com/GO-TE/bigproject-be">여기</a>에 남겨두겠습니다. (BE만)</p>
<p>처음해보는 팀프로젝트였기에 많이 배우려는 생각으로 임했지만, 아쉽게도 저희 팀에는 웹 개발(백엔드) 고인물이 안계셨습니다 !!!</p>
<p>그래서 제가 주도적으로 백엔드를 했습니다. 같이 백엔드 해주신 분께 미안하기도 하고 잘 따라 주셔서 감사했습니다.</p>
<ul>
<li><p>배운점</p>
<ol>
<li><p>FE와 협업하는 방법
API를 찍어내긴 했지만, 해당 API를 사용하기 위한 API 문서를 작성했습니다. 프론트에서 원하는 방향으로 최대한 만드려고 노력했습니다...</p>
</li>
<li><p>Git으로 협업하기
무지성 메인 푸쉬는 충돌을 야기한다... &lt;&lt; 진짜 귀찮았습니다
혼자만 써봤지 다른 사람이랑 프로젝트가 처음이라  그랬습니다...</p>
</li>
<li><p>전체적인 백엔드 구조
Djnago를 배울 때, Django로 풀스택 구현하는 방법으로 배워가지고, Front와 나누어서 BE가 할것만 생각하니 막막하긴 했습니다. 하지만 프론트하신 저희 조장님이 고수라 다행이였습니다. 
잘하진 못해 민폐가 되지 않았을까 걱정이 됩니다.
Mysql, GCP, Redis에 대한 사용법은 익힐 수 있어 좋았습니다...</p>
</li>
</ol>
</li>
<li><p>아쉬운점</p>
<ol>
<li><p>트러블 슈팅
저의 실력 이슈지만 기본 환경 세팅부터 애를 먹었습니다. Django ORM과 Mysql이 연동이 안되서 구글을 내핵까지 팠습니다...
API를 짜고 test코드와 계속 싸우고... 손에 익어서 다행이였습니다.</p>
</li>
<li><p>메타 인지
잘 한건지, 못한건지 파악을 못했습니다. 리팩토링 해야지 해놓고 안한건 못한게 맞는데, 전체적인 코드 로직이나 기술적인 완성도를 평가를 받을수가 없다고 생각했습니다.</p>
</li>
<li><p>좋은 코드 만들기
제가 코드 컨벤션 노션 페이지를 만들고 이것 저것 좋은 코드를 만드려고 노력은 해봤지만, 실상은 기능 구현하기 급급했습니다. 그래도 최대한 제 코드에 대해선 컨벤션은 지키고, 기능을 쪼개려고 노력했습니다...</p>
</li>
</ol>
</li>
<li><p>앞으로</p>
<ol>
<li><p>리팩토링
우테코 지원하며 배웠던 단위 쪼개기. 상수 따로 관리하기 등 리팩토링 할 예정입니다.</p>
</li>
<li><p>미구현 기능 구현
추후과제로 미뤘던 부분 (크롤링 자동화, Redis 더 활용하기, 소셜 로그인) 등을 구현해볼까 합니다. </p>
</li>
<li><p>Spring 배우기 (자바공화국)
여러 소프트웨어 기술 적용해보기</p>
</li>
</ol>
</li>
</ul>
<h3 id="여담">여담</h3>
<p>솔직히 Aivle school을 들으면서 저는 <code>AI/ML</code>보다는 <code>BE</code>에 관심이 더 있던 상황이였습니다.
그래서 웹 개발 배울 때가 제일 재밌더라구요 ㅋ.ㅋ</p>
<p>짧은 기간 내에 프로젝트를 만들수 있을 정도로만 배웠지 심도있게 배우진 못해서 앞으로의 방향성에 고민이 많습니다. <code>Django</code> 스택을 원하는 회사도 많지 않구요...</p>
<p>그래서 저는 Spring을 배울까합니다. 아주 멀고 긴 싸움이 되겠지만....
사실 지금 당장 취업이 되면 좋겠지만, 요즘 개발자 공급이 하도 많아서 저같은 사람이 경쟁력있다고 전혀 생각이 들진 않습니다.</p>
<p>이번 프로젝트 할 때도, 무지해서 좀 기술에 대해 심도있는 고민을 해보지도 못해봤습니다. 이건 좀 아쉽네요 예를들면, 인증을 처리하기 위해 JWT를 찾아보면서 해내긴 했는데 이에 대해 공부하고 고민한 흔적을 남기질 않아서 직접 정리하지 않는 이상 휘발성 메모리가 될 느낌이랄까</p>
<p>CS적인 부분도 학부생때 못들은 것도 있고, 까먹은 것도 있고... 공부할게 산더미같습니다.
Aivle에서 취업 상담도 해준다해서 이력서도 작성해보고, 좀 찾아보니까 신입한테는 플젝 기술 스택 찍먹보단 기본기와 올바르게 성장할 가능성을 더 본다고 하니 초점도 이쪽에 맞춰야 겠습니다.</p>
<p>두서없는 글만 쓰는 재주 부리느라 고생했고, 읽으신 분이 있으려나 싶겠지만 감사합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL - GIT]]></title>
            <link>https://velog.io/@go_te/TIL-GIT</link>
            <guid>https://velog.io/@go_te/TIL-GIT</guid>
            <pubDate>Thu, 22 Feb 2024 15:33:23 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가기-앞서">들어가기 앞서</h2>
<p>오늘 드디어 OT가 아닌 첫 수업이다.
Git 수업을 들었는데 생활코딩님이 강의를 해주셔서 내적 친밀감이 어느정도 있는지라 좀 반가웠다.
하지만 아쉬웠던건 CLI가 아닌 GUI로 git 실습을 해서 좀 아쉬웠다...</p>
<h2 id="그래도-배운건-있잖아-한잔해">그래도 배운건 있잖아 한잔해</h2>
<p>우테코를 하며 git에 대해 어느정도 사용법을 안다고 생각했다. 근데 로컬에서만 commit하고 협업은 해본적이 없는지라 협업 상황에서 대처법을 배울 수 있었다.<br></p>
<p>각설하고 배운점 정리하겠습니다. 참고로 모든 내용을 담기보단 제가 모르는 부분과 알려주고 싶은 부분 위주로 적었다고 생각하시면 좋겠습니다 헤헤</p>
<hr>
<h2 id="진짜-시작">진짜 시작</h2>
<p><img src="https://velog.velcdn.com/images/go_te/post/22d516c5-face-40ab-a9ce-dcac15497e1d/image.png" alt="리누스토르발스"></p>
<p>Git은 리누스 토르발스가 만들었다. 리누스는 이름에서 보이듯 Linux도 만들었다.
<del>무수히 많은 푸쉬요청이...</del></p>
<h3 id="git이-뭔데-그래서요">Git이 뭔데 그래서요</h3>
<p><em>Information manager from hell</em></p>
<p>컴퓨터 파일의 변경사항을 추적하고 여러 명의 사용자들 간에 해당 파일들의 작업을 조율하기 위한 스냅샷 스트림 기반의 분산 버전 관리 시스템이다</p>
<blockquote>
<p><strong>버전 관리 시스템 ? (version control system)</strong>
협업 프로젝트를 할 때, 너무 많은 복사본과 어떤 버전이 수정된 최신 버전인지 알기 어려웠던 적이 있을 것이다. 이외에도 많은 문제점을 보안하고 파일의 변화를 시간에 따라 버전별로 기록하고 특정 시점의 버전을 다시 불러올 수 있는 시스템이다.</p>
</blockquote>
<p>왜 쓰는지에 대해서는 조금만 생각해봐도 좋은 점이 차고 넘친다.
각 스냅샷의 차이를 알 수 있고 백업으로 쓸 수도 있고 협업하기도 좋고...</p>
<p><strong>들었던 강의에선 GUI를 이용하지만 나는 CLI로 해보겠다.</strong></p>
<p>깃이 어떻게 파일들을 저장하고 관리하는지 알아보자.</p>
<p>일단 repository 만드는 방법은 두개가 있다.</p>
<ol>
<li>작업하던 로컬 폴더에 git init - 깃허브에 레포 만들기 - 로컬이랑 리모트랑 연결</li>
<li>이미 있는 레포 git clone 하기</li>
</ol>
<h4 id="첫번째-방법">첫번째 방법</h4>
<pre><code class="language-shell">❯ pwd #현재 디렉토리 경로 확인
/Users/gote/workspace/aivle_school/GO-TE
❯
❯ git init
/Users/gote/workspace/aivle_school/GO-TE/.git 안의 빈 깃 저장소를 다시 초기화했습니다

❯ ls -al
total 8
drwxr-xr-x   5 gote  staff  160  2 21 13:45 .
drwxr-xr-x   3 gote  staff   96  2 21 13:41 ..
drwxr-xr-x  13 gote  staff  416  2 22 01:00 .git
drwxr-xr-x   8 gote  staff  256  2 21 13:47 .idea
-rw-r--r--   1 gote  staff   50  2 21 13:45 README.md</code></pre>
<p>짜잔 <code>.git</code>이 생겼다. <code>git init</code>을 작업중인 폴더에 생성해 깃허브 레포에 올릴 준비가 되었다. (깃허브에 repository 만드는 건 생략)</p>
<p><code>test.txt</code> 파일을 작업파일이라 가정하고 파일을 생성했다.<code>git status</code>로 변경 사항을 git이 캐치 했는지 보자.</p>
<pre><code class="language-shell">❯ git status
현재 브랜치 main
브랜치가 &#39;origin/main&#39;에 맞게 업데이트된 상태입니다.

추적하지 않는 파일:
  (커밋할 사항에 포함하려면 &quot;git add &lt;파일&gt;...&quot;을 사용하십시오)
    test.txt

커밋할 사항을 추가하지 않았지만 추적하지 않는 파일이 있습니다 (추적하려면 &quot;git
add&quot;를 사용하십시오)
❯ git status
현재 브랜치 main
브랜치가 &#39;origin/main&#39;에 맞게 업데이트된 상태입니다.

추적하지 않는 파일:
  (커밋할 사항에 포함하려면 &quot;git add &lt;파일&gt;...&quot;을 사용하십시오)
    test.txt

커밋할 사항을 추가하지 않았지만 추적하지 않는 파일이 있습니다 (추적하려면 &quot;git
add&quot;를 사용하십시오)</code></pre>
<p>바로 칼같이 잡아내는 모습이구연 이를 이제 <code>git add test.txt</code>로 <code>Staging area</code>에 추가하자.</p>
<blockquote>
<p>사실 working directory의 파일은 먼저 <strong>Untracked, Tracked</strong>의 상태를 지닌다.
    파일을 새로 만들 때 Untracked 상태가 되며 이는 git이 만들어진 파일에 대해 git이 신경 쓰지 않아도 되는 상태다. 
    이를 git이 관리하고 추적하기 위해서 Tracked로 만드려면 <code>git add [파일 명]</code>으로 Staging area에 추가해 git이 추적하도록 만드는 것이다.
또한, Staging Area에 추가 된 파일들은 <strong>Unmodified, Modified, Staged</strong> 상태로 분류된다.
<img src="https://velog.velcdn.com/images/go_te/post/12a4c9f0-2bdb-43c2-bf78-62583970dfee/image.png" alt=""></p>
</blockquote>
<pre><code class="language-shell">❯ git add test.txt
❯ git status
현재 브랜치 main
브랜치가 &#39;origin/main&#39;에 맞게 업데이트된 상태입니다.

커밋할 변경 사항:
  (use &quot;git restore --staged &lt;file&gt;...&quot; to unstage)
    새 파일:       test.txt</code></pre>
<p> commit으로 이 작업이 무엇을 의미하는지 커밋 메세지로 나타낸 뒤 원격 저장소에 push하면 끝</p>
<p>push 전</p>
<pre><code class="language-shell">❯ git status
현재 브랜치 main
브랜치가 &#39;origin/main&#39;보다 1개 커밋만큼 앞에 있습니다.
  (로컬에 있는 커밋을 제출하려면 &quot;git push&quot;를 사용하십시오)

커밋할 사항 없음, 작업 폴더 깨끗함</code></pre>
<p>push 후 </p>
<pre><code class="language-shell">❯ git status
현재 브랜치 main
브랜치가 &#39;origin/main&#39;보다 1개 커밋만큼 앞에 있습니다.
  (로컬에 있는 커밋을 제출하려면 &quot;git push&quot;를 사용하십시오)

커밋할 사항 없음, 작업 폴더 깨끗함
❯ git push origin
오브젝트 나열하는 중: 4, 완료.
오브젝트 개수 세는 중: 100% (4/4), 완료.
Delta compression using up to 10 threads
오브젝트 압축하는 중: 100% (2/2), 완료.
오브젝트 쓰는 중: 100% (3/3), 317 bytes | 317.00 KiB/s, 완료.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/GO-TE/GO-TE.git
   478bfa6..a7fae46  main -&gt; main</code></pre>
<h4 id="두번째-방법">두번째 방법</h4>
<pre><code class="language-shell">❯ ls
p1
❯ git clone https://github.com/GO-TE/GO-TE.git
&#39;GO-TE&#39;에 복제합니다...
remote: Enumerating objects: 13, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 13 (delta 2), reused 9 (delta 1), pack-reused 0
오브젝트를 받는 중: 100% (13/13), 4.99 KiB | 4.99 MiB/s, 완료.
델타를 알아내는 중: 100% (2/2), 완료.
❯ ls
GO-TE p1</code></pre>
<p>깃허브 repository 만들고 <code>git clone [깃허브 레포 주소.git]</code>을 입력하여 작업 폴더에 받아오면 된다.</p>
<p>그 후 상황은 첫번째 상황과 매우 유사하다.
새로 만든 파일은 git에 추척을 받지 않을 터이니 add - 파일이 수정이 되었다면 commit - push를 해주면 짜잔 새로운 버전이 탄생된다.</p>
<p>push한 뒤 로컬과 레포가 같은 버전인 모습을 볼 수 있다. 그림으로 볼까요?
<img src="https://velog.velcdn.com/images/go_te/post/e876234d-6511-41c4-8db9-a01dc5ed8794/image.png" alt="">
대략적인 git이 원격 저장소에 푸쉬하는 흐름은 이렇다.
프로젝트에서 작업한 파일을 git이 추적하도록 add - commit으로 버전의 스냅샷을 만든다 - push하여 원격 저장소에 업로드한다.</p>
<p>이로서 나는 git의 신이며 무적인 줄만 알았지만 실무에선 여러 사람들과 협업하여 원격 저장소에 올립니다.
프로젝트를 할 때, 누군가는 이미 최신 버전에서 push하고 누구는 이전 버전에서 수정하여 push를 시도하려고 할 수 있다.</p>
<hr>
<h3 id="git-협업-합시다">Git 협업 합시다</h3>
<p>엄준식 군과 제갈선우 군은 프로젝트를 같이 하기로 되었습니다 ! 
제갈선우 군은 많은 경험으로 밤새 미친 작업속도로 많은 커밋을 push했습니다.
엄준식 군은 그런 사실 조차 모른 채 탱자탱자 놀다가 갑자기 프로젝트 생각이 들어 대충 작업 후 <code>push</code>를 쏘아 올렸습니다.
되지않는 <code>push</code>에 &quot;어!&quot; 소리가 저절로 나오는 준식씨였습니다.</p>
<pre><code class="language-shell">❯ git push origin
 ! [rejected]        main -&gt; main (non-fast-forward)
error: 레퍼런스를 &#39;https://github.com/GO-TE/GO-TE.git&#39;에 푸시하는데 실패했습니다
힌트: 현재 브랜치의 끝이 리모트 브랜치보다 뒤에 있으므로 업데이트가
힌트: 거부되었습니다. 푸시하기 전에 (&#39;git pull ...&#39; 등 명령으로) 리모트
힌트: 변경 사항을 포함하십시오.
힌트: 자세한 정보는 &#39;git push --help&#39;의 &quot;Note about fast-forwards&#39; 부분을
힌트: 참고하십시오.</code></pre>
<p>보아하니 이전 커밋에서 작업을 하고 푸쉬를 하려니 되지않았지만 준식씨는 머리가 띵해졌습니다.</p>
<p>선우 군에게 도움을 요청하여 최신 커밋을 <code>fetch</code>하고 <code>merge</code>를 하면 된다는 소리를 들은 준식씨는 헐레벌떡 실행에 옮깁니다.</p>
<blockquote>
<p>선우씨 말대로 <code>git fetch</code> 후 <code>git merge ~</code>해도 되지만 둘 다 한번에 해주는 <code>git pull</code>이 있습니다. pull = fetch + merge</p>
</blockquote>
<pre><code class="language-shell">❯ git fetch
❯ git merge origin/main
자동 병합: test.txt
충돌 (내용): test.txt에 병합 충돌
자동 병합이 실패했습니다. 충돌을 바로잡고 결과물을 커밋하십시오.</code></pre>
<p>&quot;선우씨 말대로 했는데 왜...??????&quot;
눈치는 보이지만 선우 군에게 다시 도움을 청해봅니다.</p>
<p>고인물 선우씨는 준식씨에게 착하게 설명해줍니다.
conflict가 생긴거 같네요. 이럴 땐 <code>2 way merge</code>나 <code>3 way merge</code>를 해야해요.</p>
<p>제가 링크 드릴테니 한번 보시겠어요?</p>
<blockquote>
<ul>
<li>2 way merge : 공통된 부분만 merge하고 나머지는 사용자에게 책임을 넘기는 merge 방식</li>
</ul>
</blockquote>
<ul>
<li>3 way merge : 공통된 조상과 merge하려는 브랜치 2개와 비교한다<ol>
<li>세 버전이 같은 경우 : 그대로 merge</li>
<li>조상과 a와 같고 b가 업데이트 된 경우 : b로 merge</li>
<li>셋 다 다른 경우 : 사용자에게 책임을 넘긴다</li>
</ol>
</li>
</ul>
<p>오늘도 하나를 더 배워가는 준식씨였어요. 첫 커밋을 한 준식씨 입장에선 선우씨와 버전 차이가 너무 나니 <code>2 way merge</code>를 하기로 마음 먹었어요.</p>
<p>일단 선우 군과 겹치는 파일을 수정을 하고 commit을 다시 해봅니다.</p>
<pre><code class="language-shell">❯ git status
현재 브랜치 main
현재 브랜치와 &#39;origin/main&#39;이(가) 갈라졌습니다,
다른 커밋이 각각 1개와 1개 있습니다.
  (리모트의 브랜치를 현재 브랜치로 병합하려면 &quot;git pull&quot;을 사용하십시오)

병합하지 않은 경로가 있습니다.
  (충돌을 바로잡고 &quot;git commit&quot;을 실행하십시오)
  (병합을 중단하려면 &quot;git merge --abort&quot;를 사용하십시오)

병합하지 않은 경로:
  (해결했다고 표시하려면 &quot;git add &lt;파일&gt;...&quot;을 사용하십시오)
    양쪽에서 수정:  test.txt</code></pre>
<p><code>git status</code>를 입력하니 무엇이 문제인지 알려줍니다</p>
<pre><code class="language-shell">❯ git add test.txt
❯ git commit -m &quot;선우씨는 짱이야&quot;
[main 7293090] 선우씨는 짱이야
❯ git push origin
오브젝트 나열하는 중: 10, 완료.
오브젝트 개수 세는 중: 100% (10/10), 완료.
Delta compression using up to 10 threads
오브젝트 압축하는 중: 100% (4/4), 완료.
오브젝트 쓰는 중: 100% (6/6), 609 bytes | 609.00 KiB/s, 완료.
Total 6 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To https://github.com/GO-TE/GO-TE.git
   912778c..7293090  main -&gt; main</code></pre>
<p>다시 add - commit - push로 문제를 해결함으로 준식 군의 이야기는 마무리됩니다.</p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[제네릭 보세요오오!!!!!!!!!!!!!!]]></title>
            <link>https://velog.io/@go_te/%EC%A0%9C%EB%84%A4%EB%A6%AD-%EB%B3%B4%EC%84%B8%EC%9A%94%EC%98%A4%EC%98%A4</link>
            <guid>https://velog.io/@go_te/%EC%A0%9C%EB%84%A4%EB%A6%AD-%EB%B3%B4%EC%84%B8%EC%9A%94%EC%98%A4%EC%98%A4</guid>
            <pubDate>Mon, 04 Dec 2023 08:00:44 GMT</pubDate>
            <description><![CDATA[<center>
  ??? : 이렇게!!!!!!이러케!!!!!! 이럭계!!!!!!!!!</center>

<hr>
<h2 id="들어가기-전">들어가기 전</h2>
<p>제네릭… 이라고 생각했을 때, 그냥 아무 타입 넣고 싶을 떄 쓰는거 아니야? 라는 막연한 생각만이 있었다.
구현 과제 내줬을 때 제네릭을 떠올리며 썼던 적도 없고… 그냥 이미 만들어 진 것만 활용 할 줄 알았지, 직접 제네릭으로 구현해서 써본 적은 없었다.
유데미 자바 강의를 듣고 제가 이해 한 대로 쓰는 것이니, 틀린 부분 있으면 지적 환영 호감도 99 드리겠습니다.</p>
<hr>
<h2 id="제네릭">제네릭?</h2>
<blockquote>
<ul>
<li>자바에서 데이터 타입을 일반화 하는 것을 의미한다.</li>
</ul>
</blockquote>
<ul>
<li>제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시 미리 지정하는 방식이다.</li>
<li>런타임 환경에 아무런 영향이 없는 컴파일 시점의 전처리 기술이다.<blockquote>
</blockquote>
</li>
</ul>
<p>이것만 보고 제네릭을 이해했다면 그냥 천재하세요.</p>
<p>이해엔 코드가 딱이야… 이코딱</p>
<pre><code class="language-java">List&lt;Integer&gt; list = new ArrayList&lt;&gt;();</code></pre>
<p>저저 각괄호가 보이는가? 저게 제네릭이다 이말이야 (<code>&lt;&gt;</code> 를 다이아몬드라고 하더라)
저 괄호 안에 무엇을 넣어도 그에 맞는 ArrayList를 쓸 수 있지 않았나 ?
범용성 있게 데이터 타입에 구애받지 않고 쓸 수 있게 하는 것이 제네릭이다.</p>
<p>→ <code>&lt;&gt;</code> 를 가지는 클래스와 인터페이스를 말한다 ! 메소드도 가능</p>
<p>(<code>ArrayList</code>를  <code>List</code>로 한건 리스코프 치환 원칙때문에...)</p>
<h2 id="그래서-왜-씀-">그래서 왜 씀 ?</h2>
<p>코드를 보자</p>
<pre><code class="language-java">public class CustomList {
    ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();

    public void addElement(int element) {
        list.add(element);
    }
}</code></pre>
<p>나만의 List를 만들어보자. 인스턴스를 만든다면 원소는 int형만 만들수 있다. 아까도 말했 듯이 데이터 타입에 구애받지 않고 범용성 있도록 만들어준다.</p>
<pre><code class="language-java">public class CustomList&lt;T&gt; {
    ArrayList&lt;T&gt; list = new ArrayList&lt;&gt;();

    public void addElement(E element) {
        list.add(element);
    }
}</code></pre>
<p>제네릭을 활용하면 데이터 타입에 구애 받지 않을 수 있다.</p>
<p>두번째로 불필요한 타입 변환을 제거해준다.</p>
<p>이거슨 또 무슨말이나면</p>
<pre><code class="language-java">List list = new ArrayList();
list.add(&quot;hello&quot;);
String str = (String) list.get(0);</code></pre>
<p>제네릭을 사용하지 않으면 이렇게 귀찮게 해줘야 한다. 우리의 시간은 소중하니까 애용하자</p>
<p>마지막으로 컴파일때 알아서 강하게 타입 체크를 해준다.</p>
<p>컴파일 때 에러를 미리 다 잡아버려서, 실행중에 에러 <code>RuntimeException</code>을 방지해준다.
이렇게 잡아주면 디버깅할 때 편하다고 GPT가 그랬다.</p>
<p>정리</p>
<ol>
<li>인터페이스, 클래스, 메소드를 범용성 있게 만들어준다.</li>
<li>불필요한 타입 변환을 제거해준다.</li>
<li>컴파일 시 강한 타입 체크를 해준다.</li>
</ol>
<h2 id="와일드카드">와일드카드</h2>
<p>이건 또 뭐냐? 싶겠지만 라이브러리 좀 뜯어본 사람들이라면 많이 봤을 것이다.</p>
<pre><code class="language-java">public static double sum(List&lt;? extends Number&gt; list) {
    double sum = 0d;
    for (Number number : list) {
            sum += number.doubleValue();
    }
    return sum;
}</code></pre>
<p>매개변수를 보면 <code>List&lt;? extends Number&gt;</code> 에서 “?”가 와일드 카드다.
저게 머임 ??? 싶겠지만… 쉽게 말해서 제네릭에 올 수 있는 타입을 제한 하도록 쓰는거다.</p>
<p>코드를 대충 해석해보면
리스트를 받는다 → 리스트의 모든 원소들을 더한다 → 그 더한 값을 리턴한다.
근데 더할 수 있는건 상식적으로 숫자만 가능하다.
그러면 Number Class를 상속 받은 애들만 오도록 하는거다. String이나 char이 오면 더하지를 못하니까 !
와일드카드는 제네릭으로 올 수 있는 타입을 제한한다.</p>
<p>와일드 카드는 크게 두개로 볼 수 있다.</p>
<ul>
<li><p>상한 경계 와일드카드 (Upper Bounded Wildcard)</p>
<p>  와일드카드 타입에 <code>extends</code>를 사용해서 와일드카드 타입의 최상위 타입을 정의한다.</p>
<p>  위 예시로 든 코드가 상한 경계 와일드카드라고 볼 수 있겠다.</p>
</li>
<li><p>하한 경계 와일드카드 (Lower Bounded Wildcard)</p>
<p>  얘는 직감적으로 상한과 반대 관계라고 느낄 수 있겠다.
  <code>super</code>를 이용해 와일드카드 타입의 최하위 타입을 정의한다.</p>
<p>  요런식으로 말이지</p>
</li>
</ul>
<pre><code class="language-java">static void addNumbers(List&lt;? super Number&gt; numbers) {...}</code></pre>
<hr>
<h2 id="231229-추가"><em>231229 추가</em></h2>
<p>마무리에서 언급했듯이, 와일드카드가 이해 안되는 부분에 다뤄보겠다.</p>
<p>상한에서 get, 하한에서 set이 안되는 이유를 알아보기 전에 알아야 할 것이 있다.</p>
<h3 id="공변-불공변-covariant-invariant">공변, 불공변 (covariant, invariant)</h3>
<ul>
<li>공변 : A가 B의 하위 타입일 때, <code>T&lt;A&gt;</code>가 <code>T&lt;B&gt;</code>의 하위 타입이면, T는 공변
  쉽게 말하면 부모 클래스를 상속받은 하위 클래스가 부모 클래스로 선언 가능하면 공변</li>
<li>불공변 : A가 B의 하위 타입일 때, <code>T&lt;A&gt;</code>가 <code>T&lt;B&gt;</code>의 하위 타입이 아니면, T는 불공변
  쉽게 말하면 하위 클래스가 부모 클래스도 될 수 없고, 부모도 하위 클래스가 될 수 없으면 불공변</li>
</ul>
<p>갑자기 이걸 왜 알아야하냐고 물어본다면, 자바에서 배열은 공변으로 정했고, 제네릭은 불공변으로 하기로 했기 때문에 알아야한다.
이를 바탕으로 예제 코드를 보자.</p>
<pre><code class="language-java">public static void main(String[] args) {
  Integer[] integers = new Integer[] {1, 2, 3};
  printArray(integers);
}

void printArray(Object[] arr) {
    for (Object e : arr) {
    System.out.println(e);
    }
}</code></pre>
<p>위 코드는 배열에 따른 공변을 보여주기 위함이다. 정상적으로 잘 실행되며, Integet는 Obeject를 상속하고, 배열은 공변이므로 Integer를 넣어도 잘 실행된다.</p>
<pre><code class="language-java">public static void main(String[] args) {
    List&lt;Integer&gt; list = Arrays.asList(1, 2, 3);
    printCollection(list);
}

void printCollection(Collection&lt;Object&gt; c) {
    for (Object e : c) {
        System.out.println(e);
    }
}</code></pre>
<p>위 코드는 컴파일 에러가 발생한다. 이유는 제네릭은 불공변이기 때문이다.
그러면 어케함? 이라는 생각이 들텐데, 그래서 와일드카드를 배운 이유가 여기있다.</p>
<h3 id="어케하는데">어케하는데?</h3>
<p>직감적으로 위 코드를 보았을 때, 될 것 같지만 안되는 상황을 보며 불편함을 호소할 수 밖에 없다. 그래서 와일드카드가 있는거다. 요로케 사용하면 된다.</p>
<pre><code class="language-java">public static void main(String[] args) {
    List&lt;Integer&gt; list = Arrays.asList(1, 2, 3);
        printCollection(list);
}

void printCollection(Collection&lt;?&gt; c) {
    for (Object e : c) {
        System.out.println(e);
    }
}</code></pre>
<p>하지만 와일드카드는 모든 타입에 대해서가 아닌, 익명의 타입을 뜻한다. (unknown type)
이 부분을 코드로 보자</p>
<pre><code class="language-java">public static void main(String[] args) {
    Collection&lt;?&gt; c = new ArrayList&lt;String&gt;();
    c.add(new Object());</code></pre>
<p>위 코드를 보자. 컴파일 에러가 발생한다. 왜???????
일단 add를 해주려면 제네릭타입인, E 혹은 E의 자식을 매개변수로 줘야한다. 근데 와일드카드는 익명이므로 Number, Integer, 사용자 정의 클래스 등등 아무거나 다<del>~</del>넣을 수 있다. add로 넘겨주는 파라미터가 unknown 타입을 상속받은 클래스여야 하는데, 제한을 두지 않아 파라미터가 자식인지 뭔지 구분을 할 수가 없다.</p>
<p>근데 get은 가능하다. 왜냐면 값을 꺼낸 결과가 무엇이든 간에 확인이 필요하지도 않고, 적어도 Object를 상속받는다는 것을 보장가능하기 때문이다.</p>
<hr>
<h2 id="20250126-추가">20250126 추가</h2>
<h3 id="제네릭은-왜-불공변일까">제네릭은 왜 불공변일까?</h3>
<p>위 추가에서 언급했는데, 배열은 공변, 제네릭은 불공변이라고 했다.</p>
<p>결론부터 얘기하면, 제네릭이 생긴 이유에 대해 알아볼 필요가 있다.
초기에 자바는 제네릭이 없었음. 이 상황에서 배열을 불변하게 만드는 것은 다형성 프로그래밍을 할 수 없게 만드는 것이였다.
예를 들어 <code>Object[]</code> 배열을 비교하는 <code>Object.equals()</code> 함수를 작성할 때 불공변할 경우
배열을 비교할 때 Object 타입이 아닌 정확한 타입에 대한 equals() 메소드를 각각 클래스마다 작성해줬어야 할 것이다. (귀찮음)</p>
<p>이런 문제를 해결하기 위해 배열을 공변으로 처리했다.</p>
<p>하지만 공변함으로써 문제가 몇 개 있었는데, 자바에선 배열을 생성할 때, 각 타입을 마킹해서 처리한다.
무슨 뜻이냐면, 배열에 값을 저장할 때 마다 JVM은 런타임시 배열의 타입과 런타임시 값의 타입이 동일한지 확인해보는데, 둘이 타입이 다르다면 ArrayStoreExecption 예외를 발생한다.</p>
<p>위와 같이 공변의 경우 쓰기 시점에서 문제가 발생하고, 이 경우는 컴파일 시 오류 발견을 못하고 런타임에서만 발생하기에 매번 배열에 값을 넣을 때 마다 타입 체크가 이뤄지기에 성능 저하도 우려된다.</p>
<p>그래서 위 문제때문에 제네릭은 불공변하게 만들었다....</p>
<hr>
<h2 id="마무리">마무리</h2>
<p>당신도 이제 제네릭을 쓸 수 있게 되었다.</p>
<p>하지만 와일드카드는 내가 찾다 보니 이해가 좀 많이 안되는 부분이 있었다.
<del>(상한에서 set, 하한에서 get이 외않되?)</del>
<em>20231229추가</em>
조금씩 정리해서 다시 포스팅 하도록 그러도록 노력해보도록 하겠다.
생각보다 자바에 대해 모르는게 천지삐까리였다. 내일도 해야징 나 자신 화이팅!!!!!!!!!!!!!!!</p>
<blockquote>
<p>Reference
<a href="https://mangkyu.tistory.com/241">[Java] 제네릭과 와일드카드 타입에 대해 쉽고 완벽하게 이해하기(공변과 불공변, 상한 타입과 하한 타입) [MangKyu&#39;s Diary:티스토리]</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹의 동작 원리
]]></title>
            <link>https://velog.io/@go_te/%EC%9B%B9%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@go_te/%EC%9B%B9%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Fri, 01 Dec 2023 08:43:19 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가기-앞서">들어가기 앞서</h2>
<p>웹 백엔드가 하고싶어 ㅜ.ㅜ 라는 말을 맨날 달고 살면서, 웹에 대한 전반적인 지식도 없이 공부하고 있는 나를 발견하게 되어 웹에 대해 찾아보게 되었다.
모든건 기본 원리에서 나오는 것을 알면서도 마음만 급급한 나에게 첨가를 해보도록 하겠다.</p>
<p>언제나 그렇듯 틀린 부분은 지적 부탁드립니다 헤헤,,,</p>
<hr>
<h2 id="web">Web?</h2>
<p>인터넷에 연결된 컴퓨터를 통해 사람들이 정보를 공유할 수 있는 전 세계적인 정보 공간</p>
<p>흔히 우리는 브라우저로 홈페이지에 접속하여 여러 작업을 하기도 하고, 정보를 얻기도 한다 그에 따른 동작 방식을 알아보자</p>
<h2 id="동작-방식">동작 방식</h2>
<p><img src="https://velog.velcdn.com/images/go_te/post/2cb44b33-2d3a-42c0-85d3-5a1dfff22633/image.png" alt=""></p>
<blockquote>
<p>클라이언트가 서버에 요청을 보내면 서버는 해당 요청에 대해 응답한다</p>
</blockquote>
<ul>
<li><p>웹 클라이언트 (Web Client) <br></p>
<p>  사용자가 웹에 접근하는 프로그램 크롬이나 사파리 같이 웹 브라우저를 일컫는다. 클라이언트는 사용자로부터 받은 URL을 DNS가 네트워크를 찾아갈 수 있는 IP로 변환해 준다. 그 IP로 HTTP 형태로 서버에게 요청한다.<br></p>
</li>
<li><p>웹 서버 (Web Server)<br></p>
<p>  웹페이지를 저장하는 프로그램으로 클라이언트로부터 HTTP 요청을 받아 HTML 문서와 같은 웹 페이지를 반환한다. 대표적으로 Apache가 있다.<br></p>
<p>  → 요청에 따라 처리하는 또 다른 컴퓨터<br></p>
</li>
<li><p>WAS (Web Application Server)<br></p>
<p>  서버가 모든 사용자의 요청에 따라 로직을 전부 수행한다면, 과부하가 일어날 가능성이 높다. 따라서 사용자 컴퓨터나 장치에 어플리케이션을 수행해주는 미들웨어로서, 주로 동적 서버 컨텐츠를 수행하는 것으로 웹 서버와 구별된다.<br></p>
<p>  → 주로 DB 서버와 같이 수행되며, 서버 단독으로 처리할 수 없는 여러 작업을 수행한다. 대표적으로 Tomcat이 있다.<br></p>
</li>
<li><p>DB (Data Base)<br></p>
<p>  말 그대로 데이터 저장소. 웹 어플리케이션의 필요한 정보들을 저장한다.<br></p>
</li>
</ul>
<h2 id="http">HTTP?</h2>
<p>Hyper Text Transfer Protocol의 약자로 웹 서버 간 데이터를 주고 받기 위한 인터넷 프로토콜이다. 이로 다양한 리소스들을 전송할 수 있다.</p>
<blockquote>
<p>Protocol : 상호 간 약속한 규칙 → 특정 기기 간 데이터를 주고받기 위해 정의</p>
</blockquote>
<ul>
<li><p>특징</p>
<p>  Client/Server 모델을 따른다</p>
<p>  : 서로 관계를 맺고 있는 컴퓨터 프로그램이 클라이언트와 서버 두 역할로 구분 된다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/go_te/post/75490b37-a60b-45d6-8df4-ecca2a1769e1/image.png" alt="클라이언트 - 서버"></p>
<h2 id="http-message">HTTP Message</h2>
<p>클라이언트와 서버 간 요청하고 응답하는 과정에서 보내는 메세지.</p>
<p>클라이언트 : Request Message</p>
<p>서버 : Response Message</p>
<h3 id="--response-message">- Response Message</h3>
<p><img src="https://velog.velcdn.com/images/go_te/post/d65b1a3f-17d0-4d43-991c-3482dc27b755/image.png" alt="요청 메세지 구조"></p>
<ol>
<li>요청 라인</li>
</ol>
<p>클라이언트가 무엇을 어떻게 처리하고자 하는 정보가 담겨 있다.</p>
<ul>
<li><p>메소드 (Method)</p>
<p>  처리하고자 하는 방식이다. 다음과 같은 종류가 있다.</p>
<ul>
<li>GET : 존재하는 자원에 대한 요청</li>
<li>POST : 새로운 자원을 생성</li>
<li>PUT : 존재하는 자원에 대한 변경</li>
<li>DELETE : 존재하는 자원에 대한 삭제</li>
</ul>
</li>
<li><p>경로 (URL)</p>
<p>  처리하는 작업에 대한 대상을 말한다. 완전한 형식, 상대적인 형식 등 메서드 유형에 따라 다양한 포맷이 있다.</p>
<p>  ex) <a href="http://www.google.com/">www.google.com</a>, index.html …</p>
</li>
</ul>
<ul>
<li><p>프로토콜 버전</p>
<p>  HTTP 프로토콜의 버전을 표시한다. 요즘은 2.0을 주로 쓴다 카더라</p>
</li>
</ul>
<ol start="2">
<li>헤더</li>
</ol>
<p>서버에 대한 추가 정보를 전달한다. 호스트 정보, 사용자 정보, 브라우저 정보, 페이지 정보 등 을 전달한다.</p>
<ol start="3">
<li>공백 라인</li>
</ol>
<p>헤더와 본문을 구별하는 용도로 진짜 말 그대로 공백인 라인이다.</p>
<ol start="4">
<li>본문</li>
</ol>
<p>메소드에 따라 필수 요소가 될수도 있고 안될 수도 있는 요소다</p>
<p>POST나 PUT처럼 자원을 추가 및 변경할 때 그 정보를 본문에 쓰는 반면</p>
<p>GET같은 경우는 딱히 필요하지가 않다 !</p>
<h3 id="--response-message-1">- Response Message</h3>
<p><img src="https://velog.velcdn.com/images/go_te/post/aa610488-d8c7-4c6e-bc14-76ffcf410b43/image.png" alt="응답 메세지 구조"></p>
<ol>
<li><p>응답 라인</p>
<ul>
<li><p>프로토콜 버전</p>
<p>  요청메세지와 동일하게 프로토콜 버전을 담는다.</p>
</li>
<li><p>상태 코드</p>
<p>  클라이언트 요청에 대한 성공 여부를 코드로 나타낸 것</p>
<p>  404 Not Found를 본적이 있는가? 404가 상태 코드다 </p>
</li>
<li><p>상태 메세지</p>
<p>  위 코드에 대한 짧은 설명을 나타낸것 !</p>
</li>
</ul>
</li>
<li><p>응답 헤더</p>
<p> 요청 메세지와 마찬가지로 주로 전달할 리소스 타입, 압축된 방식 표현, 메세지가 만들어진 날짜와 시간을 담고 있다.</p>
</li>
<li><p>공백 라인</p>
<p> 이것도 마찬가지로 본문과 헤더를 구분하는 용도</p>
</li>
<li><p>본문</p>
<p> 요청에 따른 리소스가 포함되어있다.</p>
<p> 예를들어 html 리소스를 받는다면 html 파일 요소들을 받아온다.</p>
<p>  &lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;….</p>
<p> 영상 리소스라면 그에 맞는 포맷으로 리소스가 담겨있다.</p>
</li>
</ol>
<hr>
<h2 id="마무리">마무리</h2>
<p>웹에 대해 찍먹해보았다. 다음은 더 자세한 내용으로 돌아오겠다.</p>
<blockquote>
<p>Reference
<a href="https://swimjiy.github.io/2019-11-03-How-Web-Works">[Web] 그림으로 알아보는 웹 - 1편 웹의 동작 원리</a>
<a href="https://swimjiy.github.io/2020-04-04-web-http">[Web] 그림으로 알아보는 웹 - 2편 HTTP</a></p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>