<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dxxh_e.log</title>
        <link>https://velog.io/</link>
        <description>열심히 살아야지</description>
        <lastBuildDate>Sun, 03 Aug 2025 13:49:13 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dxxh_e.log</title>
            <url>https://velog.velcdn.com/images/dxxh_e/profile/eaaf7655-65f7-46a1-a66a-bf313f1080e1/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dxxh_e.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dxxh_e" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[부스트캠프 10기 챌린지] 3주차 종합 회고]]></title>
            <link>https://velog.io/@dxxh_e/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-10%EA%B8%B0-%EC%B1%8C%EB%A6%B0%EC%A7%80-3%EC%A3%BC%EC%B0%A8-%EC%A2%85%ED%95%A9-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@dxxh_e/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-10%EA%B8%B0-%EC%B1%8C%EB%A6%B0%EC%A7%80-3%EC%A3%BC%EC%B0%A8-%EC%A2%85%ED%95%A9-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 03 Aug 2025 13:49:13 GMT</pubDate>
            <description><![CDATA[<p><del><em>일단 해보자</em></del></p>
<h2 id="들어가기">들어가기</h2>
<p>정신을 차려보니 부스트캠프 챌린지 과정 중 <code>3주 차</code>를 마무리하고 마지막 <code>4주 차</code>를 앞두고 있습니다. 돌이켜보면 지난주는 <code>1~2주 차</code>를 겪고 스스로 설정한 학습 방식을 본격적으로 다듬어보고 적용했던 뜻깊은 시간이었습니다. 1주 차의 <strong>학습 위주의 방식</strong>, 2주 차의 <strong>구현 위주의 방식</strong>을 거쳐 <strong><code>학습-설계-구현-기록</code>이라는 나만의 프로세스</strong>를 작은 단위의 작업에 적용해 문제를 해결해 보고자 시도했습니다.</p>
<p>비록 어떤 기준으로 작업을 나누고 적용할 지 감이 안 잡혔지만, <code>Just do it</code>의 마음가짐으로 <strong>일단 도전하자</strong>라는 마음가짐으로 3주 차를 보낸 것 같습니다.</p>
<p>그 결과 개념을 학습하고 작은 작업 단위로 설계 후 코드로 구현하며 자신이 진행한 학습을 검증하는 과정은 스스로 이해를 더욱 탄탄하게 만드는 기회가 된 것 같습니다. 머릿속에만 떠다녔던 개념이 실제 코드로 표현되는 순간 정말 <strong>짜릿한(?)</strong> 성취감을 느꼈습니다.</p>
<p>이 과정이야말로 부스트캠프가 지향하는 <code>Learning by Challenge</code>일까? 라는 생각도 들었습니다.</p>
<p>이번 회고는 이러한 경험을 통해 <strong><code>스스로 유지하고 싶은 것(Keep)</code></strong>, <strong><code>부족한 점(Problem)</code></strong>, <strong><code>앞으로 시도하고 싶은 것(Try)</code></strong>을 KPT 기법으로 정리하고자 합니다.</p>
<hr>
<h3 id="keep---앞으로-유지하기">Keep - 앞으로 유지하기</h3>
<p>3주 차에는 나만의 학습과 구현의 균형을 맞추기 위한 방법으로, <code>학습-설계-구현-기록</code> 사이클을 학습 방식에 도입해 보았습니다. 처음에는 시간이 많이 소요되고 진행 속도가 정말 느렸습니다. 그러다 보니 첫날에는 스스로 설정한 목표의 반절도 달성하지 못한 것 같습니다. 하지만, 2~3일이 지난 후 <strong>문제 해결 과정에서 학습한 지식과 경험이 더 깊게 남는다는 것을 체감</strong>했습니다. 스스로 깨닫고 이해한 지식이 점점 생기니 자연스럽게 동료와의 소통도 더욱 적극적으로 하게 되었습니다.</p>
<p>피어 세션과 슬랙에서 서로 의견을 나누며 동료들의 접근 방법을 참고하고, 스스로 해결한 방식을 공유하면서 동료들이 <em><code>도움이 많이 되었다.</code></em>, <em><code>나도 이 방법을 사용해 보고 싶다.</code></em>와 같은 긍정적인 피드백을 많이 남겨주셨습니다. 그 결과 <code>사소하더라도 동료들에게 도움이 되는 사람</code>이 되고 싶다는 마음이 강해졌고, 앞으로도 적극적으로 소통하며 서로의 성장에 도움을 주는 캠퍼가 되고 싶다고 생각하게 되었습니다.</p>
<p>또, 3주 차 동안 문제에 접근할 때 단순히 빨리 해결하는 것보다 <strong>이 문제에서 내가 얻고자 하는 것은 뭘까?</strong>라는 질문을 반복하며 목표를 명확히 하는 습관을 가지고자 노력했습니다. 그러다 보니 주어진 시간 안에 완성하는 것보다 문제를 통해 장기적으로 무엇을 얻을 수 있을지, 어떤 성장을 이뤄낼 수 있는지를 우선순위로 판단하게 된 것 같습니다.</p>
<p>이러한 <strong>목표 중심의 문제 접근 방식</strong>은 앞으로도 꾸준히 유지하고 싶습니다.</p>
<blockquote>
<p><em>이때, 개발자는 <strong>제한된 시간 내에 과업을 완수하는 역량</strong>이 필수라는 점을 잘 알고 있습니다. 
하지만 챌린지 과정만큼은, 단기적인 성과보다 장기적인 <code>성장</code>과 본질적인 <code>이해</code>에 집중하고 싶었습니다.</em></p>
</blockquote>
<hr>
<h3 id="problem---앞으로-개선하기">Problem - 앞으로 개선하기</h3>
<p>이번 주를 되돌아보면 당연히 아쉬운 부분도 존재했습니다. 특히, CS 지식을 <strong>실제 코드 구현으로 연결하는 데 어려움</strong>을 정말 많이 겪었습니다... 학부 시절의 이론 중심 공부 방식이 <code>습관화</code>되어 있어 현실적인 구현 단계에서 방향을 잡는 데 어려움이 있었습니다.</p>
<p>돌이켜보면 단순히 이론을 <strong>아는 것</strong>이 아닌, 개념을 <strong>어떻게</strong> 코드에 녹여내고 구현으로 연결할지에 대한 연습이 부족한 게 아닐까...? 싶습니다.</p>
<p>또 하나는 여전히 문제를 접했을 때 겁을 먹거나 매우 크게 보는 경향이 있는 것 같습니다. <em>(<del>와.. 이걸 어떻게 접근해야 하지?</del>)</em>
해결해야 하는 요구사항이 늘어났을 때 작업을 작은 단위로 <code>빠르게</code> 나누는 데 어려움을 느끼고, <strong>나무도 안 보고 숲을 봐버리는 것처럼</strong> 처음부터 전체를 조망하려 하다 보니 압박감을 크게 느낀 것 같습니다.</p>
<p>이러한 접근 방식은 오히려 작업 속도를 매우 느리게 하고 방향성을 흐리게 만든다는 것을 체감한 것 같습니다. 앞으로는 작업의 초기 단계부터 가급적 <strong>더 작고 구체적인 작업 단위</strong>로 나누고, <strong>명확한 목표를 정의</strong>하는 습관을 기르고 싶습니다.</p>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/3a79660d-6b1c-4744-a9c1-79efbfc7d1ed/image.png" alt=""></p>
<p><em><del>숲을 보기 전, 반드시 나무부터 보자. 위 사진처럼 나무가 아닐(?) 수 있다.</del></em></p>
<hr>
<h3 id="try---다음-주에-시도할-것">Try - 다음 주에 시도할 것</h3>
<p>마지막 4주 차에는 <strong>CS 지식을 실제 코드에 적극적으로 녹여내는 연습을 더 많이 시도해 보고자 합니다.</strong> <del>(이게 제일 어려운 거 같은데..)</del></p>
<p>이론적으로 익힌 개념들을 아주 작은 예제라도 꾸준히 구현해 보며 실제 이론과 구현 능력을 연결해 보고 싶습니다. 또한 문제를 처음부터 <strong>작고 명확한 단위로 나누어</strong> 압박감을 최소화하고, 효율적으로 문제에 접근하는 방법을 적극적으로 탐색하고 싶습니다.</p>
<p>더불어 동료와의 의견 교환을 더욱 적극적으로 나누고 싶습니다. 단순한 질문과 답변이 아닌, <strong>저는 이렇게 접근해 봤습니다! 다른 분들은 어떻게 생각하시나요?</strong>와 같은 구체적인 의견 공유를 더욱 많이, 적극적으로 진행해 서로에게 더 큰 도움이 되는 경험을 쌓고 싶습니다.</p>
<hr>
<h2 id="빠져나오기">빠져나오기</h2>
<p>3주 차를 돌아보면... 무엇보다도 <strong>스스로 가장 잘 맞는 학습 방법</strong>을 고민하고 실제로 적용해 보았다는 점이 가장 뿌듯하게 남는 것 같습니다.</p>
<p>속도가 느리더라도 문제를 작은 단위로 나누고, 차근차근 목표를 달성해 나가는 과정에서 깊이 있는 학습을 시도할 수 있었습니다.</p>
<p>이건 정말 큰 자산이 될 것 같습니다..ㅎㅎ</p>
<p>2주 차 회고를 마무리하며 다짐했던 것처럼 이번 3주 차 회고를 마치며 드는 마음 역시 같습니다.</p>
<p><strong>남들보다 속도가 느려도, 뒤돌아봤을 때 제가 걸어간 길이 자랑스러웠으면 좋겠습니다 :)</strong></p>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/5a90577e-e057-4c31-a256-a3eb461b780f/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[부스트캠프 10기 챌린지] 1~2주차 종합 회고]]></title>
            <link>https://velog.io/@dxxh_e/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-10%EA%B8%B0-%EC%B1%8C%EB%A6%B0%EC%A7%80-2%EC%A3%BC%EC%B0%A8-%EC%A2%85%ED%95%A9-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@dxxh_e/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-10%EA%B8%B0-%EC%B1%8C%EB%A6%B0%EC%A7%80-2%EC%A3%BC%EC%B0%A8-%EC%A2%85%ED%95%A9-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 27 Jul 2025 15:39:11 GMT</pubDate>
            <description><![CDATA[<p><del><em>챌린지란 원래 자기 생각대로 되지 않는 법이란다</em></del></p>
<h2 id="들어가기">들어가기</h2>
<p>어느덧 부스트캠프 챌린지 과정의 절반이 지나갔습니다. 정신없이 달려온 2주 동안, 어떻게 하면 스스로에게 가장 잘 맞는 학습 방법을 찾을 수 있을지 다양한 시도를 해본 것 같습니다.</p>
<p>처음 챌린지 과정을 시작했을 때 솔직히 말해서 정말.. 아주 약간 자신감에 차 있던 것 같습니다. 베이직 과정에서 잘 적응했던 터라 이번에도 잘 해낼 수 있을 것이라 생각했던 것 같습니다. 하지만 실제 챌린지 과정은 완전히 다른 현실을 보여줬습니다.</p>
<h2 id="더-들어가보기">더 들어가보기</h2>
<h3 id="1주차-학습-위주로-달리기">1주차: 학습 위주로 달리기</h3>
<p>첫 주는 제 자신에게 <code>학습</code>이 가장 중요하다고 생각해서 <code>학습</code> 중심으로 접근했습니다. 그러나 과제의 난이도가 높아지자 <em>모르는 건 완벽히 학습해야 한다.</em>라는 강박 때문에 제대로 문제 풀이조차 하지 못한 날도 있었습니다. 학습도 구현도 어중간하게 되어버린 날도 찾아왔던 것 같습니다.</p>
<p>그러다 같은 팀원이 제출한 결과물을 읽거나, 동료들과의 질문을 주고받을 때 자신감이 정말 크게 떨어졌습니다. 다른 동료의 성취를 볼 때마다 <code>난 할 수 있을까?</code> 라는 생각까지 들었고 끝까지 무리하다가 결국 주말에 몸살증세까지 나는 경험을 했습니다...ㅎㅎ <del>한 15시간 숙면하니 괜찮아졌지만..</del></p>
<p>그때 상황을 돌이켜보면 맞는 비유인지는 모르겠지만 <code>더닝-크루거 효과</code>가 떠올랐습니다.</p>
<img src="https://velog.velcdn.com/images/dxxh_e/post/adb921af-bad5-4c80-93a6-d9bece45b920/image.png" width="100%" height="100%">

<p>아무것도 몰랐던 베이직 때의 자신감과 마음가짐이 챌린지 과정에서 현실을 마주하고 좌절되기 시작했고, 자꾸만 스스로를 과소평가하게 됐습니다. 하지만, 1주차 회고를 작성하면서 다른 동료들의 회고를 읽고 라디오를 들으며 나와 비슷한 고민을 하는 동료들이 많다는 것을 깨달았습니다. 이때 혼자가 아니라는 위안을 얻은 것 같습니다.</p>
<p>그때 문득, JK님의 말씀이 떠올랐습니다.</p>
<blockquote>
<p><em>모두가 같은 시작점에 있어도, 쌓아온 경험은 다르다.</em></p>
</blockquote>
<p>이 말은 제 스스로를 조금이나마 더 자유롭게 만든 것 같습니다.</p>
<h3 id="2주차-구현-중심으로-바꿔보기">2주차: 구현 중심으로 바꿔보기</h3>
<p>2주차에는 구현을 우선순위에 두고 학습 방식을 바꿔봤습니다.
그러다가 역시.. 호되게 혼났습니다..ㅋㅋ</p>
<img src="https://velog.velcdn.com/images/dxxh_e/post/618daab0-6e21-43f3-b5e0-2be36d5c54c7/image.jpg" width="100%" height="100%">

<p><del><em>제발 정신 차려</em></del></p>
<p>1주차보다 더욱 방대하고 난이도가 높은 문제가 출제되기 시작했습니다. 구현을 시도하려고 해도 어디서부터 시작해야 할지 막막했고, 설계를 먼저 하려 해도 방향을 잡지 못한 채 멈춰버리는 순간이 많았습니다.</p>
<p>결국 다시 학습에 집중한 뒤, 반이라도 구현해보거나 아주 작게 나눠서 천천히 설계와 구현을 시도하는 방식으로 접근했습니다. </p>
<p>또 매일 문제를 마무리할 때마다 <code>내가 이 문제를 풀면서 얻을 수 있는 건 충분히 얻었나?</code>, <code>이대로 제출해도 후회가 없을까?</code>, <code>동료들에게 나만의 해결 과정을 충분히 설명할 수 있을까?</code>라는 질문을 스스로에게 끊임없이 던졌습니다.</p>
<p>1주차에 너무 한계까지 몸을 혹사했던 경험 덕분에 2주차엔 <code>챌린지는 장거리 싸움이다.</code>라고 마음을 먹은 뒤 다음 날 지장이 없도록 아무리 늦어도 새벽 3시에는 모든 작업을 멈추고 휴식을 취하기로 목표를 세웠습니다. 그리고 이번 주말에 끝까지 구현하지 못했던 문제들을 일부라도 구현해보고 싶어 다시 시도했는데, 신기하게도 더 잘 풀리는 것을 느꼈습니다.</p>
<p>이때, 휴식의 중요성이 얼마나 큰지 몸소 느꼈습니다.</p>
<p>그러나 2주차 역시 아쉬움이 너무 크게 남는 것 같습니다. 구현 중심으로 접근하려 했으나 개인적으로 느끼는 난이도와 분량의 압박감 때문에 여전히 <code>학습</code>에 더 집중했던 것 같고, 1주차보다는 나아졌지만, 여전히 부족하다는 느낌을 지울 수는 없었습니다.</p>
<p>원인을 나름대로 분석한 결과, 학부 때 공부한 CS 지식에 대한 자신감이 없어진 것이 한몫한 것 같습니다. 오직 시험과 자격증을 위한 이론 중심의 공부를 하다 보니, 막상 현실에서 제대로 구현하려고 하면 방향성을 잡지 못하고 있었습니다. </p>
<p>하지만 챌린지에서 직접 구현하고 학습하는 방식은 <code>이론적인 학습</code>과 달리 너무 재미있고 기억에 남는 것 같습니다. 이 부분은 지금 회고를 작성하는 시점에서 다시 돌이켜보면.. <code>챌린지 과정에서 가장 큰 성장을 경험한 지점이지 않을까?</code> 싶습니다.</p>
<p>결과적으로 2주차를 지내며 <code>막연한 불안</code>보다 매일 작은 단위라도 꾸준히 시도하며 나아가는 것이 더 중요하다는 걸 알게 된 것 같습니다.</p>
<h2 id="나가기">나가기</h2>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/b615a9ce-5bbb-4897-a4a1-e52ec1a359af/image.jpg" alt=""></p>
<p>2주차를 마무리하는 시점에서 <code>학습 중심 접근</code>과 <code>구현 중심 접근</code>을 모두 경험하고 나니 가장 중요한 것은 <code>나 자신에게 맞는</code> <code>학습</code>과 <code>구현</code>사이의 밸런스를 찾는 것이라고 느껴집니다.</p>
<p>이제 3주차부터는 문제의 크기나 난이도와 상관없이 <code>아주 작게 나눠서</code>, 자전거 페달을 밟듯이 작은 단위의 사이클을 반복해보고 싶습니다.</p>
<p>이쯤되니, 챌린지 과정에서 얻고 싶은 것이 매우 뚜렷해졌습니다. CS 지식을 단순히 안다고 착각하는 게 아니라 CS에 <strong>익숙해지는 것</strong>, <strong>Swift 구현 능력을 조금이라도 더 키우는 것</strong>, 그리고 <strong>동료들과의 소통과 더불어, 나만의 개발 철학을 찾아가는 것</strong>입니다.</p>
<p>당장 다음 과정인 <code>멤버십</code>에 대한 고민은 나중의 일이라고 생각합니다. 현재 제 자신에게 주어진 과정을 후회 없이 마치고, 스스로 만족스러운 경험을 쌓는 것이 더 중요하다는 깨달음을 얻은 것 같습니다.</p>
<p><strong>남들보다 속도가 느려도, 뒤돌아봤을 때 제가 걸어간 길이 자랑스러웠으면 좋겠습니다.</strong></p>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/0a7f6f1f-9351-459b-b290-ab05d9b5614b/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AI 시대, 개발자 지망생으로 살아남는다는 것]]></title>
            <link>https://velog.io/@dxxh_e/AI-%EC%8B%9C%EB%8C%80-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%A7%80%EB%A7%9D%EC%83%9D%EC%9C%BC%EB%A1%9C-%EC%82%B4%EC%95%84%EB%82%A8%EB%8A%94%EB%8B%A4%EB%8A%94-%EA%B2%83</link>
            <guid>https://velog.io/@dxxh_e/AI-%EC%8B%9C%EB%8C%80-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%A7%80%EB%A7%9D%EC%83%9D%EC%9C%BC%EB%A1%9C-%EC%82%B4%EC%95%84%EB%82%A8%EB%8A%94%EB%8B%A4%EB%8A%94-%EA%B2%83</guid>
            <pubDate>Sat, 21 Jun 2025 06:44:02 GMT</pubDate>
            <description><![CDATA[<h2 id="1-우린-어떤-시대에서-살아가는가">1. 우린 어떤 시대에서 살아가는가?</h2>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/b3516920-07cd-4f1a-8864-2e1523735123/image.png" alt=""></p>
<p>개발이라는 걸 정말 좋아했던 것 같다.학창 시절, 선배가 검은 화면에 타자를 와구와구 입력하는 모습을 동경하던 시절이 있었다. </p>
<p>개발이라는 게 궁금했다. 프론트엔드, 백엔드, 서버, 데이터베이스, 닥치는 대로 다 다뤄보고 싶었다.</p>
<p>모든 걸 잘하진 않지만, <strong>“지금 이 기능은 이런 기술로 구현하는 게 좋겠다”</strong> 정도의 감은 생겼다.</p>
<p>혼자서라도 방향을 잡고, 부딪치며 배우는 게 즐거웠다.</p>
<p>그런데, 어느 순간 생성형 AI가 출시되었다.</p>
<p>ChatGPT, Cursor, Claude, 그리고 바이브 코딩이라는 새로운 개발 패러다임까지.</p>
<p>AI가 코드를 “대신” 짜주는 시대가 실제로 도래했다.</p>
<p>요즘은 어떤 콘텐츠를 보든 이런 말이 넘쳐난다.</p>
<blockquote>
<p>“AI가 개발자를 대체할 것이다.”</p>
</blockquote>
<blockquote>
<p>“더 이상 신입 개발자는 필요 없다.”</p>
</blockquote>
<p>하루에 1~2번씩 이런 자극적인 문장을 마주한다.</p>
<p>그런데, 이게 단순한 자극이 아니라 <strong>현실적인 변화</strong>라는 것이 팩트이다.</p>
<p>사람인의 통계에 따르면,</p>
<p><strong>2025년 1분기 기준으로 신입 개발자 구인 공고는 작년 대비 18.9% 감소했다.</strong></p>
<p>반면, <strong>경력직 비중은 전체 공고의 56%로 증가</strong>했다.</p>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/dcecf81d-3300-4850-b688-95a096266f93/image.png" alt=""></p>
<p>이건 단순한 채용 트렌드가 아니다.</p>
<p><strong>기업들이 “AI를 활용할 수 있는 경력직”을 선호한다는 방증</strong>이다.</p>
<p>게다가, 거시경제마저 얼어붙고 있다.</p>
<p>채용 시장 자체가 위축되니 나 같은 신입에게 돌아올 기회는 더욱 적어진다.</p>
<p>문득, 나 자신에게 묻게 된다.</p>
<p><strong>“정말로, 신입 개발자에게 더 이상 자리는 없는 걸까?”</strong></p>
<p><strong>“나는 이 변화 속에서 살아남을 수 있을까?”</strong></p>
<p><strong>“앞으로도 계속, 개발자로 성장할 수 있을까?”</strong></p>
<p>생각해보면, 오히려 이런 변화는 위기가 아니라 <strong>기회</strong>가 되지 않을까?
라는 생각이 들었다.
그렇다면 나는, 이 AI 시대에 어떤 관점과 태도로 걸어가야 할까?</p>
<hr>
<h2 id="2-단순-개발자보다-문제-해결자로">2. 단순 개발자보다 &#39;문제 해결자&#39;로</h2>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/375bc60f-67c5-4301-8f3c-0fc3cec08548/image.png" alt=""></p>
<p>최근 네이버 부스트캠프 웹・모바일 10기에 지원하고자 하며 관련 글들을 읽다가,</p>
<p><strong>‘네이버 커넥트재단이 생각하는 AI 시대의 개발자’</strong>라는 아티클을 접하게 되었다.</p>
<p>그 글에서 특히 인상 깊었던 한 문장이 있다.</p>
<blockquote>
<p>“인공지능이 똑똑해지고, 개발 업무가 자동화될수록</p>
</blockquote>
<blockquote>
<p>개발자라는 사람이 해야 하는 일의 본질은 더 선명하게 드러난다.”</p>
</blockquote>
<p>이 문장을 읽고 곰곰이 생각해봤다.</p>
<p>우리는 ChatGPT나 Claude 같은 AI 도구를 언제 사용하는가?</p>
<blockquote>
<p>“이 코드 리팩토링해줘”
“이 뷰 하단에 새로운 컴포넌트를 추가해줘”
“이 코드, 어디가 잘못된 거야?”</p>
</blockquote>
<p>이런 질문들은 결국</p>
<p><em>“문제를 내가 정의해줬을 때, 정답을 빠르게 제시해주는 도구”</em>를 사용하는 것이다.</p>
<p>즉, <strong>AI는 문제 해결 능력이 뛰어난 것이 아니라, 문제 정의 이후의 최적 경로를 계산해주는 도구</strong>다.</p>
<p><strong>소프트웨어 개발은 코딩을 넘어 현실의 문제를 해결하는 일이다.</strong></p>
<p>개발자의 진짜 과업은 단순한 코드 작성이 아닌,</p>
<blockquote>
<p>복잡한 현실을 관찰하고 문제를 정의하며
해결 전략을 설계하고
사람과 AI가 함께 움직일 수 있는 해결 프로세스를 주도하는 것이다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/3d9232f0-d6a7-4db8-839a-35650c4e49a7/image.png" alt=""></p>
<p>돌이켜보면, 나 역시 프로젝트를 진행하며 AI 도구를 많이 사용했다.</p>
<p>문제가 생겼을 때 GPT에게 물어보고, Claude로 리팩토링을 시도했다.</p>
<p>하지만 문득 이런 질문들이 떠올랐다:</p>
<ul>
<li><strong>AI가 제시한 결과를, 나는 정말 ‘검증’할 수 있었나?</strong></li>
<li><strong>그 코드가 내 프로젝트에 적합한지 ‘판단’할 수 있는 역량이 있었나?</strong></li>
<li><strong>그 답을 그대로 ‘적용’하면서도, 왜 그런 답이 나왔는지 이해하고 있었나?</strong></li>
</ul>
<p>아직 부족하다고 느낀다.</p>
<p>그래서 더더욱 느낀다.</p>
<p><strong>AI 시대의 진짜 경쟁력은, “코드를 잘 짜는 사람”이 아니라, “문제를 잘 정의하고 해결할 수 있는 사람”이라는 것.</strong></p>
<hr>
<p>앞서 말했듯, AI는 스스로 문제를 찾지 못한다.</p>
<p>그건 인간의 역할이다.</p>
<p>맥락을 이해하고, 문제가 무엇인지 명확히 정의하고,</p>
<p>그에 맞는 해결 전략을 설계할 수 있어야 진짜 개발자다.</p>
<p>그게 바로 AI 시대에 인간 개발자가 가져야 할 <strong>차별점</strong>이며,</p>
<p>앞으로 더 키워야 할 <strong>핵심 역량</strong>이라고 믿는다.</p>
<p>AI 시대가 왔다고 해서, 위축되고 자신감을 잃을 필요는 없다.</p>
<p>오히려 AI는, <strong>함께 일할 수 있는 동료이자 멘토</strong>처럼 활용할 수 있다면,</p>
<p>우리는 <strong>AI가 없던 시대보다 훨씬 빠르고 깊게 성장할 수 있다.</strong></p>
<p>이 변화는 위기가 아니라, <strong>기회</strong>라고 생각한다.</p>
<hr>
<h2 id="3-이-글을-쓰는-이유">3. 이 글을 쓰는 이유</h2>
<p>어느덧 대학 졸업 시즌이 다가오고, </p>
<p>취업이라는 현실이 눈앞에 놓인 지금, </p>
<p>정말 많은 생각이 든다.</p>
<p>주변 동기들이나 지인들을 보면 개발자의 꿈을 포기하거나,
“어차피 인공지능이 우리의 일자리를 빼앗을 거야”라는 비관적인 이야기를 하곤 한다.</p>
<p>하루에도 몇 번씩, AI가 개발자를 대체한다는 자극적인 문장을 마주하다 보면
나 스스로도 자신감이 조금씩 사라지는 것 같은 기분이 든다.</p>
<p>하지만, 나는 개발이 좋다.</p>
<p>이 글은 그런 고민을 하고 있는 나와 같은 사람들,
그리고 같은 길을 걷고 있는 동기들이 읽어주었으면 하는 마음으로 포스팅을 했다.
그리고 동시에, 앞으로도 해낼 수 있다는 스스로의 다짐을 다시 한 번 새기고 싶었다.</p>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/1cded263-1ef1-4237-8dad-7ce8dbc9561f/image.png" alt=""></p>
<p>우리 모두는 같은 길을 걷는 동료다.
모두가 원하는 꿈을 이룰 때까지, 화이팅!</p>
<p>아래 글은 &quot;네이버 커넥트재단&quot;의 포스팅이다.
정말 많은 영감을 얻게 해줘서 공유하고 싶다는 생각이 들었다.</p>
<p><a href="https://blog.naver.com/boostcamp_official/223834097896">네이버 커넥트재단이 생각하는 AI 시대의 개발자</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UIKit] UITableView에 대해]]></title>
            <link>https://velog.io/@dxxh_e/UIKit-UITableView%EC%97%90-%EB%8C%80%ED%95%B4</link>
            <guid>https://velog.io/@dxxh_e/UIKit-UITableView%EC%97%90-%EB%8C%80%ED%95%B4</guid>
            <pubDate>Sat, 22 Mar 2025 04:18:12 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dxxh_e/post/118a9e4c-b3ce-47c1-aa85-f40aee2dfefd/image.png" alt=""></p>
<h2 id="1-iboutlet-란">1. <code>@IBOutlet</code> 란?</h2>
<ul>
<li><p>스토리보드와 코드를 연결해주는 코드 라인</p>
<ul>
<li><p>스토리보드에서 TableView를 하나 만든 뒤 실제 코드와 연결할 때 사용한다.</p>
<p>  → 스토리보드에서 만든 UI 컴포넌트를 코드에서 접근하기 위한 연결선</p>
<p>  → 그래야 <code>myTableView.backgroundColor = .green</code> 와 같이 데이터를 변경할 수 있다.</p>
</li>
</ul>
</li>
</ul>
<p>💡비유하자면 콘센트 선을 연결하는 것과 같다. 연결을 안하면 아무리 전기를 보내도 불이 안켜지는 것과 같다.</p>
<pre><code class="language-swift">@IBOutlet weak var myTableView: UITableView!</code></pre>
<h2 id="2-uitableviewdelegate-uitableviewdatasource-의-역할">2. <code>UITableViewDelegate</code>, <code>UITableViewDataSource</code> 의 역할</h2>
<h3 id="✅-uitableviewdelegate">✅ <code>UITableViewDelegate</code></h3>
<ul>
<li><p>TableView에서 ‘어떻게 동작할건가?’ 를 말한다.</p>
<p>  → 즉, 셀을 눌렀을 때 무엇을 할 것인지, 높이는 어떻게 할 것인지 등을 말한다.</p>
</li>
</ul>
<h3 id="✅-uitableviewdatasource">✅ <code>UITableViewDataSource</code></h3>
<ul>
<li><p>TableView에서 ‘무엇을 넣을 건가?’ 를 담당한다.</p>
<p>  → 즉, 셀을 몇 개 만들건가? 어떤 글을 쓸 거냐? 등을 말한다.</p>
</li>
</ul>
<pre><code class="language-swift">myTableView.delegate = self
myTableView.dataSource = self</code></pre>
<p>→ <code>self</code> 는 현재 <code>MyTableViewController</code> 가 <code>delegate</code> 와 <code>dataSource</code> 역할을 수행한다는 의미다.</p>
<h2 id="📎-2-1-delegate-란">📎 2-1. <code>delegate</code> 란?</h2>
<ul>
<li>테이블뷰의 동작, 이벤트 처리 담당 → 클릭했을 때 어떤 이벤트가 발생할까?</li>
<li><strong>대리자라는 뜻이며 말 그대로 어떤 객체가 해야 하는 일을 다른 객체에게 <code>위임</code> 하는 구조이다.</strong></li>
</ul>
<h3 id="🔎-swift--uikit에서-어떻게-활용할까">🔎 Swift / UIKit에서 어떻게 활용할까?</h3>
<ul>
<li><p>UIKit에서 이벤트(클릭, 스크롤 등)가 발생했을 때 <em>”이거 어떻게 처리할까?”</em> 라고 위임받은 객체에게 묻는다.</p>
</li>
<li><p>테이블뷰에서 셀이 클릭되면 <code>delegate</code> 메서드가 호출된다.</p>
<pre><code class="language-swift">  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)</code></pre>
</li>
</ul>
<h2 id="📎-2-2-datasource-란">📎 2-2. <code>dataSource</code> 란?</h2>
<ul>
<li>테이블뷰에 들어갈 데이터를 제공 → 몇 개의 셀을 그릴까? 각 셀에 무엇을 보여줄까?</li>
<li><strong>데이터 제공자라는 뜻 그대로 <code>이 뷰에 들어갈 데이터는 이걸로 채워줘</code> 라고 알려주는 역할이다.</strong></li>
</ul>
<h3 id="🔎-swift--uikit에서-어떻게-활용할까-1">🔎 Swift / UIKit에서 어떻게 활용할까?</h3>
<ul>
<li><p>테이블뷰가 화면에 뿌릴 데이터가 필요할 때 <code>DataSource</code> 에게 묻는다.</p>
<pre><code class="language-swift">  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int</code></pre>
</li>
</ul>
<hr>
<h2 id="3-uitableviewdatasource-채택-시-필수-구현-메서드">3. <code>UITableViewDataSource</code> 채택 시 필수 구현 메서드</h2>
<h3 id="📌-numberofrowsinsection">📌 <code>numberOfRowsInSection</code></h3>
<pre><code class="language-swift">func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int</code></pre>
<ul>
<li><p>목적 : TableView의 아이템(리스트 혹은 섹션)의 개수를 표현하기 위함.</p>
<p>  → TableView가 “몇 줄 만들까요?” 라는 의미</p>
</li>
<li><p>파라미터</p>
<ul>
<li><code>tableView</code> : 현재 데이터를 요청하는 <strong>테이블 뷰 객체</strong></li>
<li><code>section</code> : 섹션 번호 (기본은 0, 섹션이 여러 개 일때 구분하기 위한 용도)</li>
</ul>
</li>
</ul>
<h3 id="📌-cellforrowat">📌 <code>cellForRowAt</code></h3>
<pre><code class="language-swift">func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
 -&gt; UITableViewCell</code></pre>
<ul>
<li>목적 : 테이블뷰 각 셀에 어떤 데이터를 넣을 건지 설정하기 위함.</li>
<li>리턴값 : <code>UITableViewCell</code> → 화면에 보여줄 셀</li>
<li>파라미터<ul>
<li><code>tableView</code> : 현재 데이터를 요청하는 <strong>테이블 뷰 객체</strong></li>
<li><code>indexPath</code> : 섹션 번호 + 줄 번호 정보 (<code>indexPath.section</code>, <code>indexPath.row</code>)</li>
</ul>
</li>
</ul>
<p>💡 포인트 : <code>indexPath.row</code> 를 이용해 <code>cellData</code> 배열에서 데이터를 꺼내오는 것!</p>
<pre><code class="language-swift">let cell = tableView.dequeueReusbleCell(withIdentifier: &quot;myCell&quot;, for: indexPath)
cell.textLabel?.text = cellData[indexPath.row]
return cell</code></pre>
<p>→ <code>dequeueReusbleCell</code> : 재사용 가능한 셀을 가져오기. (메모리의 효율성 증가)</p>
<hr>
<h2 id="4-uitableviewdelegate-를-채택할-때-필수-구현은-아닌-메서드">4. <code>UITableViewDelegate</code> 를 채택할 때 필수 구현은 아닌 메서드</h2>
<h3 id="📌-didselectrowat">📌 <code>didSelectRowAt</code></h3>
<ul>
<li>필수 구현 메서드는 아니다.</li>
<li>특정 셀을 클릭했을 때 동작을 정의하는 메서드이다.</li>
</ul>
<pre><code class="language-swift">func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)</code></pre>
<hr>
<h2 id="5-tableview의-전체-구조-이해data-flow">5. TableView의 전체 구조 이해(Data Flow)</h2>
<ol>
<li><code>viewDidLoad()</code> 에서 <code>delegate</code>, <code>dataSource</code> 를 연결한다.</li>
<li>테이블뷰가 화면에 나타날 준비를 진행한다. → 이때 <code>dataSource</code> 호출</li>
<li><code>numberOfRowsInSection()</code> 호출 → 테이블뷰에 몇 줄을 그릴거야?</li>
<li><code>cellForRowAt()</code> → 각 줄에 뭘 그릴거야?</li>
<li>(선택) 셀을 누르면 <code>delegate</code> 메서드 실행</li>
</ol>
<hr>
<h2 id="💡-6-핵심-용어-정리">💡 6. 핵심 용어 정리</h2>
<table>
<thead>
<tr>
<th>용어</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>@IBOutlet</td>
<td>스토리보드 ↔ 코드 연결</td>
</tr>
<tr>
<td>delegate</td>
<td>테이블뷰 이벤트 처리자 (행동)</td>
</tr>
<tr>
<td>dataSource</td>
<td>테이블뷰 데이터 제공자 (데이터)</td>
</tr>
<tr>
<td>indexPath.row</td>
<td>현재 셀의 줄 번호</td>
</tr>
<tr>
<td>indexPath.section</td>
<td>현재 셀의 섹션 번호</td>
</tr>
<tr>
<td>dequeueReusableCell</td>
<td>재사용 셀 꺼내기 (메모리 관리)</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UIKit] View와 ViewController]]></title>
            <link>https://velog.io/@dxxh_e/UIKit-View%EC%99%80-ViewController</link>
            <guid>https://velog.io/@dxxh_e/UIKit-View%EC%99%80-ViewController</guid>
            <pubDate>Sat, 22 Mar 2025 04:16:02 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dxxh_e/post/18e096c7-1e76-4533-aa7e-6b9821a0735a/image.png" alt=""></p>
<h1 id="1-viewuiview란">1. View(UIView)란?</h1>
<ul>
<li>iOS 화면에서 눈에 보이는 모든 UI 요소는 <code>UIView</code>이다.</li>
<li>버튼, 라벨, 이미지, 스크롤뷰 모든 것이 전부 <code>UIView</code> 의 자식이다.</li>
<li>화면에 그리기, 터치 이벤트 받기, 애니메이션 등 모든 역할을 담당한다.</li>
</ul>
<blockquote>
<p>🍎 Apple UIKit 공식 설명
*&quot;A view represents a rectangular area on the screen and is responsible for drawing and handling events in that area.”*
→ 뷰는 ‘사각형 영역’이며, 화면에 그림을 그리거나 이벤트를 처리한다.</p>
</blockquote>
<hr>
<h1 id="2-viewcontrolleruiviewcontroller란">2. ViewController(UIViewController)란?</h1>
<ul>
<li>UIViewController는 말 그대로 View를 관리하는 컨트롤러 역할을 수행한다.</li>
<li>화면 전환, 데이터 전달, 뷰의 생명주기 관리 등을 <code>ViewController</code> 가 수행한다.</li>
<li>예를 들어 화면에 <code>TableView</code> 를 띄우면 TableView는 <code>View</code>, 이를 관리하는 것이 <code>ViewController</code> 이다.</li>
</ul>
<blockquote>
<p>🍎 Apple 공식 설명
*&quot;UIViewController is a base class for view controllers, which manage a set of views and coordinate the flow of information between your app’s data model and your views.”*
→ ViewController는 View를 관리하고, 모델과 View 사이의 데이터 흐름까지 조율하는 역할을 수행한다.</p>
</blockquote>
<h2 id="2-1-viewcontroller가-하는-일">2-1. ViewController가 하는 일</h2>
<table>
<thead>
<tr>
<th>역할</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>뷰 관리</strong></td>
<td>화면에 올라가는 View들을 만들고 관리 (addSubview 등)</td>
</tr>
<tr>
<td><strong>데이터와 뷰 연결 (MVC의 C 역할)</strong></td>
<td>Model(데이터) → View로 전달해서 화면에 보여주고, View에서 발생한 액션 → Model로 전달</td>
</tr>
<tr>
<td><strong>화면 전환 관리</strong></td>
<td><code>present</code>, <code>dismiss</code>, <code>navigation push/pop</code> 등을 담당</td>
</tr>
<tr>
<td><strong>메모리 관리</strong></td>
<td>메모리 부족할 때 뷰 내리고 다시 불러오는 작업 (<code>didReceiveMemoryWarning</code>)</td>
</tr>
<tr>
<td><strong>사용자 인터랙션 처리</strong></td>
<td>버튼 클릭, 스와이프 같은 이벤트 처리</td>
</tr>
</tbody></table>
<h2 id="2-2-⭐-uiviewcontroller의-생명주기lifecycle">2-2. ⭐ UIViewController의 생명주기(LifeCycle)</h2>
<p>→ iOS에서 화면(View)이 어떻게 만들어지고 사라지는지 순서대로 정리한다.</p>
<table>
<thead>
<tr>
<th>메서드</th>
<th>언제 호출되는가?</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td><code>init()</code></td>
<td>뷰컨이 만들어질 때 (코드로 생성하면 여기부터 시작)</td>
<td>변수 초기화</td>
</tr>
<tr>
<td><code>loadView()</code></td>
<td>시스템이 View 만들 때</td>
<td>직접 커스텀 View 만들고 싶을 때 override</td>
</tr>
<tr>
<td>⭐<code>viewDidLoad()</code></td>
<td>View가 메모리에 올라왔을 때 (딱 한 번)</td>
<td>UI 초기 설정, 데이터 바인딩</td>
</tr>
<tr>
<td>⭐<code>viewWillAppear()</code></td>
<td>화면에 보이기 직전</td>
<td>화면에 맞게 데이터 새로고침</td>
</tr>
<tr>
<td>⭐<code>viewDidAppear()</code></td>
<td>화면 완전히 보일 때</td>
<td>애니메이션 시작, API 호출 등</td>
</tr>
<tr>
<td><code>viewWillDisappear()</code></td>
<td>다른 화면으로 넘어가기 직전</td>
<td>저장해야 할 거 처리</td>
</tr>
<tr>
<td><code>viewDidDisappear()</code></td>
<td>화면에서 완전히 사라졌을 때</td>
<td>타이머 멈추기, 리소스 정리</td>
</tr>
<tr>
<td>⭐<code>deinit()</code></td>
<td>메모리에서 완전 해제될 때</td>
<td>메모리 정리, 관찰자 해제</td>
</tr>
<tr>
<td>- ⭐ <code>viewDidLoad()</code> 는 딱 1번만 호출된다. (초기 세팅용)</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- ⭐ <code>viewWillAppear()</code> , <code>viewDidAppear()</code> 는 화면이 그려질 때 마다 호출된다.</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- ⭐ API 호출, 화면 그리기 타이밍 등 ViewController에서 조절한다.</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- ⭐ <code>deinit()</code> 를 잡지 않으면 메모리 누수(retain cycle)이 생겨 앱이 죽을 수 있다.</td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h3 id="2-2-1-기본-uiviewcontroller-생명주기-코드-예시">2-2-1. 기본 UIViewController 생명주기 코드 예시</h3>
<pre><code class="language-go">import UIKit

class MyViewController: UIViewController {

    // 뷰컨 생성될 때 (코드로 만들면 여기부터 시작)
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        print(&quot;👉 init() 호출&quot;)
    }

    // 스토리보드용 필수
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        print(&quot;👉 init(coder:) 호출&quot;)
    }

    // 커스텀 View 제작 시
    override func loadView() {
        super.loadView()
        print(&quot;👉 loadView() 호출&quot;)
    }

    // 뷰가 메모리에 올라오면 딱 한 번 호출
    override func viewDidLoad() {
        super.viewDidLoad()
        print(&quot;👉 viewDidLoad() 호출&quot;)
        view.backgroundColor = .white
    }

    // 화면 뜨기 직전에 매번 호출
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        print(&quot;👉 viewWillAppear() 호출&quot;)
    }

    // 화면 완전히 뜨면 호출
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        print(&quot;👉 viewDidAppear() 호출&quot;)
    }

    // 화면 사라지기 직전
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        print(&quot;👉 viewWillDisappear() 호출&quot;)
    }

    // 화면 완전히 사라진 후
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        print(&quot;👉 viewDidDisappear() 호출&quot;)
    }

    // 메모리 해제 직전 (deinit)
    deinit {
        print(&quot;👉 deinit() 호출 - 메모리에서 사라짐&quot;)
    }
}
</code></pre>
<h2 id="2-3-uiviewcontroller의-생명주기-순서">2-3. UIViewController의 생명주기 순서</h2>
<p>→ 2-2-1.에서 작성한 예시 코드를 실행했을 때 아래와 같이 콘솔에 출력된다.</p>
<ul>
<li>💡 이를 통해서 생명주기의 흐름을 파악한다.</li>
</ul>
<pre><code class="language-swift">👉 init() 호출
👉 loadView() 호출
👉 viewDidLoad() 호출
👉 viewWillAppear() 호출
👉 viewDidAppear() 호출

(화면 전환해서 사라지면 아래가 호출)
👉 viewWillDisappear() 호출
👉 viewDidDisappear() 호출
👉 deinit() 호출 - 메모리에서 사라짐</code></pre>
<hr>
<h1 id="✅-요약">✅ 요약</h1>
<ul>
<li>View와 ViewController의 정의</li>
</ul>
<table>
<thead>
<tr>
<th>역할</th>
<th>View (UIView)</th>
<th>ViewController (UIViewController)</th>
</tr>
</thead>
<tbody><tr>
<td>정의</td>
<td>화면에 보이는 요소</td>
<td>UI 관리하는 관리자</td>
</tr>
<tr>
<td>하는 일</td>
<td>그림 그리고 터치 받음</td>
<td>화면 전환, 데이터 전달, 생명주기 관리</td>
</tr>
<tr>
<td>공식 문서에서 정의하는 것</td>
<td>&quot;그리기와 이벤트 처리&quot;</td>
<td>&quot;View 관리하고 데이터 모델 연결&quot;</td>
</tr>
<tr>
<td>- ViewController의 생명주기의 주요 메서드 요약</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- <code>viewDidLoad()</code> → 화면에 그려질 때 최초 1회만 호출</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- <code>viewWillAppear()</code> , <code>viewDidAppear()</code> → 화면이 그려질 때 마다 호출</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- <code>viewWillDisappear()</code> , <code>viewDidDisappear()</code> → 화면에서 사라질 때 마다 호출</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- <code>deinit()</code> → 메모리에서 완전히 해제될 때 호출</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- 💡 만약, 실행이 안된다면 메모리 누수를 의심해야한다.</td>
<td></td>
<td></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[🤔 애플 생태계의 UI 아키텍처 원리를 알아보자.]]></title>
            <link>https://velog.io/@dxxh_e/%EC%95%A0%ED%94%8C-%EC%83%9D%ED%83%9C%EA%B3%84%EC%9D%98-UI-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%9B%90%EB%A6%AC%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dxxh_e/%EC%95%A0%ED%94%8C-%EC%83%9D%ED%83%9C%EA%B3%84%EC%9D%98-UI-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98-%EC%9B%90%EB%A6%AC%EB%A5%BC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sun, 16 Mar 2025 11:23:10 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dxxh_e/post/74675d22-2418-4fa8-ae8f-def76016f487/image.png" alt=""></p>
<p><del>공부할게 산더미</del></p>
<h1 id="🔎-애플-생태계의-ui-아키텍처-원리">🔎 애플 생태계의 UI 아키텍처 원리</h1>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/b2eae04d-523f-4cdc-b700-d5610805779e/image.png" alt=""></p>
<p>애플의 <strong><code>UI 개발 환경</code> 은 <code>Cocoa Framework 계층</code> 위에서 동작하며, 각 운영체제(iOS, macOS, watchOS, tvOS)에 따라 다른 UI 프레임워크를 사용한다.</strong></p>
<hr>
<h2 id="💡-cocoa--cocoa-touch">💡 Cocoa &amp; Cocoa Touch</h2>
<p>애플의 UI는 <code>Cocoa 및 Cocoa Touch Framework</code> 를 기반으로 동작한다. 이는 운영체제(OS)와 애플리케이션(Application) 사이의 다리 역할을 하는 핵심 프레임워크이다.</p>
<table>
<thead>
<tr>
<th>프레임워크</th>
<th>사용 OS</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Cocoa</strong></td>
<td>macOS</td>
<td>macOS 애플리케이션 개발을 위한 프레임워크 (Foundation + AppKit)</td>
</tr>
<tr>
<td><strong>Cocoa Touch</strong></td>
<td>iOS / iPadOS / watchOS / tvOS</td>
<td>iOS 앱 개발을 위한 프레임워크 (Foundation + UIKit)</td>
</tr>
<tr>
<td>- <code>Cocoa</code> : macOS 애플리케이션 개발을 위한 기본 프레임워크</td>
<td></td>
<td></td>
</tr>
</tbody></table>
<pre><code>→ `Foundation` + `AppKit`</code></pre><ul>
<li><p><code>Cocoa Touch</code> : iOS 애플리케이션 개발을 위한 프레임워크</p>
<p>  → <code>Foundation</code> + <code>UIKit</code></p>
</li>
</ul>
<p>즉 iOS에서 UI를 개발할 때 UIKit를 사용하여 UIKit는 Cocoa Touch 위에서 동작한다.</p>
<hr>
<h1 id="🤔-ios와-macos의-ui-프레임워크">🤔 iOS와 macOS의 UI 프레임워크</h1>
<p>애플은 각 운영체제마다 UI 프레임워크를 따로 제공하지만 전체적으로 <strong>비슷한 구조를 가지고 있다.</strong></p>
<table>
<thead>
<tr>
<th>기기</th>
<th>UI 프레임워크</th>
</tr>
</thead>
<tbody><tr>
<td><strong>iPhone / iPad</strong></td>
<td>UIKit (Cocoa Touch 기반)</td>
</tr>
<tr>
<td><strong>Mac</strong></td>
<td>AppKit (Cocoa 기반)</td>
</tr>
<tr>
<td><strong>Apple Watch</strong></td>
<td>WatchKit</td>
</tr>
<tr>
<td><strong>Apple TV</strong></td>
<td>UIKit</td>
</tr>
<tr>
<td><strong>모든 플랫폼</strong></td>
<td>SwiftUI (iOS, macOS, watchOS, tvOS 공통)</td>
</tr>
</tbody></table>
<p><strong>✅ <code>UIKit</code> → iOS에서 UI를 구성하는 핵심 프레임워크</strong></p>
<p><strong>✅ <code>AppKot</code> → macOS에서 UI를 구성하는 핵심 프레임워크</strong></p>
<p><strong>✅ <code>SwiftUI</code> → 모든 애플 플랫폼에서 공통적으로 사용할 수 있는 UI 프레임워크</strong></p>
<hr>
<h1 id="📌-uikit와-appkit의-역할">📌 UIKit와 AppKit의 역할?</h1>
<p>UIKit와 AppKit는 각각 iOS와 macOS에서 UI를 개발하는 전통적인 방식이다.</p>
<p><code>SwiftUI</code> 가 등장하기 전까지는 이 두개의 프레임워크가 애플 생태계의 UI를 담당했다.</p>
<h2 id="✅-uikit-ios--ipados">✅ UIKit (iOS &amp; iPadOS)</h2>
<ul>
<li><p>iOS와 iPadOS에서 UI를 구성하는 핵심 프레임워크</p>
</li>
<li><p><strong>뷰 컨트롤러(<code>UIViewController</code>)</strong> 기반으로 동작</p>
</li>
<li><p>스토리보드(Storyboard) 또는 코드 기반 UI 개발 가능</p>
</li>
<li><p>코드 예시</p>
<pre><code class="language-swift">  class ViewController: UIViewController {
      override func viewDidLoad() {
          super.viewDidLoad()

          let button = UIButton(type: .system)
          button.setTitle(&quot;클릭하세요&quot;, for: .normal)
          button.frame = CGRect(x: 50, y: 150, width: 200, height: 50)
          button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)

          view.addSubview(button)
      }

      @objc func buttonTapped() {
          print(&quot;버튼이 눌렸습니다!&quot;)
      }
  }
</code></pre>
</li>
</ul>
<p>👉 <code>UIViewController</code> 기반으로 UI를 직접 생성하는 <strong>명령형(Imperative UI) 방식</strong>이다.</p>
<hr>
<h2 id="✅-appkit-macos">✅ AppKit (macOS)</h2>
<ul>
<li><p>macOS 애플리케이션에서 UI를 구성하는 프레임워크</p>
</li>
<li><p><strong>윈도우 기반(<code>NSWindow</code>)</strong>으로 동작</p>
</li>
<li><p>UIKit과는 다르게 macOS의 전통적인 UI 패턴을 따름</p>
</li>
<li><p>코드 예시</p>
<pre><code class="language-swift">  import Cocoa

  class ViewController: NSViewController {
      override func viewDidLoad() {
          super.viewDidLoad()

          let button = NSButton(title: &quot;클릭하세요&quot;, target: self, action: #selector(buttonTapped))
          button.frame = NSRect(x: 50, y: 150, width: 200, height: 50)

          view.addSubview(button)
      }

      @objc func buttonTapped() {
          print(&quot;버튼이 눌렸습니다!&quot;)
      }
  }
</code></pre>
</li>
</ul>
<p>👉 AppKit에서는 <code>NSButton</code> 을 사용하고 macOS의 UI 구조에 맞게 동작한다.</p>
<p>👉 UIKit과 비슷하지만 <strong>윈도우 기반(NSWindow)이라는 점이 다르다!</strong></p>
<hr>
<h1 id="📌-애플-생태계-통합-ui-프레임워크-swiftui">📌 애플 생태계 통합 UI 프레임워크 SwiftUI</h1>
<p>UIKit와 AppKit는 서로 다르기 때문에 같은 애플 앱이라도 플랫폼마다 UI를 따로 개발해야 하는 소요가 발생이 되어 애플은 이를 해결하기 위해 SwiftUI를 도입했다.</p>
<h2 id="🎁-swiftui의-특징">🎁 SwiftUI의 특징</h2>
<ul>
<li><p><strong>모든 애플 플랫폼(iOS, macOS, watchOS, tvOS)에서 사용할 수 있는 공통 UI 프레임워크</strong></p>
</li>
<li><p>선언형(Declarative UI) 방식 사용</p>
</li>
<li><p>코드가 간결하고 유지보수 용이</p>
</li>
<li><p>하지만 💡 <strong>모든 UIKit 기능을 대체할 수 없다! (</strong>UIKit &amp; AppKit과 함께 사용됨)</p>
</li>
<li><p>코드 예시</p>
<pre><code class="language-go">  import SwiftUI

  struct ContentView: View {
      var body: some View {
          Button(&quot;클릭하세요&quot;) {
              print(&quot;버튼이 눌렸습니다!&quot;)
          }
          .padding()
      }
  }
</code></pre>
</li>
</ul>
<p>👉 <strong>UIKit과 AppKit 없이 하나의 코드로 iOS/macOS UI를 개발 할 수 있다.</strong></p>
<p>👉 UI가 상태(State)에 따라 자동 업데이트된다.</p>
<hr>
<h1 id="👊-uikit-vs-appkit-vs-swiftui-비교">👊 UIKit vs AppKit vs SwiftUI 비교</h1>
<table>
<thead>
<tr>
<th></th>
<th><strong>UIKit</strong> (iOS/iPadOS)</th>
<th><strong>AppKit</strong> (macOS)</th>
<th><strong>SwiftUI</strong> (공통)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>개발 대상</strong></td>
<td>iOS, iPadOS</td>
<td>macOS</td>
<td>iOS, macOS, watchOS, tvOS</td>
</tr>
<tr>
<td><strong>프레임워크 기반</strong></td>
<td>Cocoa Touch</td>
<td>Cocoa</td>
<td>UIKit + AppKit을 통합</td>
</tr>
<tr>
<td><strong>UI 방식</strong></td>
<td>명령형 (Imperative)</td>
<td>명령형 (Imperative)</td>
<td>선언형 (Declarative)</td>
</tr>
<tr>
<td><strong>지원 기기</strong></td>
<td>iPhone, iPad</td>
<td>Mac</td>
<td>iPhone, iPad, Mac, Watch, TV</td>
</tr>
<tr>
<td><strong>코드 스타일</strong></td>
<td><code>UIViewController</code> 사용</td>
<td><code>NSViewController</code> 사용</td>
<td><code>View</code> 구조체 사용</td>
</tr>
<tr>
<td><strong>기업 사용</strong></td>
<td>대부분의 iOS 앱에서 사용</td>
<td>대부분의 macOS 앱에서 사용</td>
<td>새로운 프로젝트에서 점진적 도입</td>
</tr>
<tr>
<td><strong>장점</strong></td>
<td>더 세밀한 UI 컨트롤 가능</td>
<td>macOS 전용 UI 기능 제공</td>
<td>코드가 간결하고 유지보수 쉬움</td>
</tr>
<tr>
<td><strong>단점</strong></td>
<td>코드가 많아질 수 있음</td>
<td>UIKit과 UI 구조가 다름</td>
<td>일부 UIKit 기능 미지원</td>
</tr>
</tbody></table>
<hr>
<h1 id="🤧-한눈에-정리하기">🤧 한눈에 정리하기</h1>
<ol>
<li><strong>Cocoa Touch (iOS)와 Cocoa (macOS)가 애플 UI 프레임워크의 기반</strong></li>
<li><strong>UIKit은 iOS &amp; iPadOS에서 UI를 담당, AppKit은 macOS에서 UI를 담당</strong></li>
<li><strong>SwiftUI는 모든 애플 기기에서 UI를 개발할 수 있는 공통 프레임워크</strong></li>
<li><strong>UIKit과 AppKit이 완전히 사라지진 않으며 SwiftUI와 함께 사용</strong></li>
</ol>
<hr>
<p><del>다른 계층은 나중에 공부해야지..</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[iOS에서 UI 개발의 두 가지 접근 방식을 알아보자.]]></title>
            <link>https://velog.io/@dxxh_e/iOS%EC%97%90%EC%84%9C-UI-%EA%B0%9C%EB%B0%9C%EC%9D%98-%EB%91%90-%EA%B0%80%EC%A7%80-%EC%A0%91%EA%B7%BC-%EB%B0%A9%EC%8B%9D%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@dxxh_e/iOS%EC%97%90%EC%84%9C-UI-%EA%B0%9C%EB%B0%9C%EC%9D%98-%EB%91%90-%EA%B0%80%EC%A7%80-%EC%A0%91%EA%B7%BC-%EB%B0%A9%EC%8B%9D%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Sun, 16 Mar 2025 10:58:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dxxh_e/post/97bb8619-0e89-4253-8863-6ac78dfc829d/image.png" alt=""></p>
<hr>
<h1 id="💻-ios-ui-개발의-두-가지-접근-방식--swiftui와-uikit">💻 iOS UI 개발의 두 가지 접근 방식 : SwiftUI와 UIKit</h1>
<p>iOS 애플리케이션을 개발할 때, 화면을 구성하는 방법은 크게 <code>UIKit</code> 와 <code>SwiftUI</code> 가 존재한다.</p>
<p>해당 방식들은 각각 <code>iOS UI</code> 개발의 접근 방식을 다르게 제공한다.</p>
<p>이러한 요소들을 이해하기 전, <strong>iOS의 기반이 되는 프레임워크인 <code>Cocoa Touch Framework</code> 에 대해 살펴봐야한다.</strong></p>
<hr>
<h2 id="☕-cocoa-touch-framework-란">☕ Cocoa Touch Framework 란?</h2>
<ul>
<li><p><code>Cocoa Touch</code> 는 iOS 애플리케이션 개발을 위한 기본 프레임워크</p>
<p>  → 해당 프레임워크는 <code>UIKit</code> , <code>Foundation</code> 등의 핵심 프레임워크를 포함하며 iOS 앱이 하드웨어(iPhone, iPad)에서 실행될 수 있도록 지원한다. </p>
</li>
</ul>
<h3 id="📎-cocoa-touch의-주요-구성-요소">📎 Cocoa Touch의 주요 구성 요소</h3>
<table>
<thead>
<tr>
<th>구성 요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>UIKit</strong></td>
<td>iOS UI 개발을 담당하는 프레임워크 (뷰, 버튼, 애니메이션 등)</td>
</tr>
<tr>
<td><strong>Foundation</strong></td>
<td>데이터 관리, 날짜, 파일 입출력, 네트워킹 등의 기능 제공</td>
</tr>
<tr>
<td><strong>Core Animation</strong></td>
<td>부드러운 애니메이션과 그래픽 렌더링 처리</td>
</tr>
<tr>
<td><strong>Core Graphics</strong></td>
<td>2D 그래픽을 처리하는 저수준 그래픽 API</td>
</tr>
<tr>
<td><strong>Core Data</strong></td>
<td>데이터 저장 및 관리 (로컬 데이터베이스)</td>
</tr>
<tr>
<td><strong>AVFoundation</strong></td>
<td>오디오, 비디오 재생 및 편집 기능</td>
</tr>
</tbody></table>
<p>위 표를 토대로 <code>UIKit</code> , <code>SwiftUI</code> 는 <code>Cocoa Touch</code> 프레임워크 안에서 동작하는 UI 프레임워크라고 볼 수 있다.</p>
<p><strong><em>⚡ 하지만 UIKit와 SwiftUI는 완전히 다른 방식으로 UI를 구현한다.</em></strong></p>
<hr>
<h2 id="💡ios-ui-개발의-전통적인-방식인-uikit">💡iOS UI 개발의 전통적인 방식인 <code>UIKit</code></h2>
<p>UIKit은 iOS 2부터 사용된 전통적인 UI 프레임워크이며, 현재 iOS 개발을 할 때 가장 많이 사용되는 방식이다.</p>
<p>현재도 대부분의 앱이 UIKit를 기반으로 만들어졌으며, 유지보수 역시 UIKit를 중심으로 진행된다.</p>
<h3 id="📌-uikit의-주요-특징">📌 UIKit의 주요 특징</h3>
<ol>
<li><p>명령형 프로그래밍(Imperative UI) 방식이다.</p>
<p> →  개발자가 직접 UI 요소를 생성하고 업데이트할 때마다 코드를 실행해야 한다.</p>
</li>
<li><p>UIViewController 기반 구조다.</p>
<p> → 앱의 화면을 <code>UIViewController</code> 가 관리하며, UI 요소들은 <code>UIView</code> 기반으로 구성된다.</p>
</li>
<li><p>스토리보드(Storyboard)와 코드 방식 지원</p>
<p> → UIKit는 <code>스토리보드를 이용한 GUI 방식</code>과 <code>코드 베이스 방식</code> 2가지로 UI를 구성할 수 있다.</p>
</li>
<li><p>대부분의 기업에서 사용 중이다.</p>
<p> → 현재까지도 대부분의 iOS 앱이 UIKit를 기반으로 개발되고 있다.</p>
</li>
</ol>
<h3 id="📌-uikit의-ui-개발-방식">📌 UIKit의 UI 개발 방식</h3>
<p>UIKit는 2가지 방법으로 UI를 개발한다.</p>
<ol>
<li><p><strong>StoryBoard (GUI 방식)</strong></p>
<ul>
<li>Xcode에서 GUI로 화면을 구성할 수 있다. (= Android Studio와 유사하다.)</li>
<li>초보자가 UI를 쉽게 만들 수 있지만 협업 및 유지보수가 어렵다.</li>
</ul>
</li>
<li><p>⭐ <strong>코드 기반 UI</strong></p>
<ul>
<li><p><code>UIView</code> 와 <code>Auto Layout</code> 을 직접 코드로 작성하여 UI를 구성한다.</p>
</li>
<li><p>스토리보드보다 유연하고 협업 시 <code>Git 충돌</code> 이 상대적으로 적어 실무에서 선호된다.</p>
</li>
<li><p><em>코드 베이스 방식 예시 (버튼 추가)</em></p>
<ul>
<li>🤜 <code>UIButton</code> 을 직접 만들고 이벤트를 연결하는 <code>명령형 방식</code></li>
</ul>
<pre><code class="language-swift">class ViewController: UIViewController {
  override func viewDidLoad() {
      super.viewDidLoad()

      let button = UIButton(type: .system)
      button.setTitle(&quot;클릭하세요&quot;, for: .normal)
      button.frame = CGRect(x: 50, y: 150, width: 200, height: 50)
      button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)

      view.addSubView(button)
  }

  @objc func buttonTapped() {
      print(&quot;버튼이 눌렸습니다.&quot;)
  }
}</code></pre>
</li>
</ul>
</li>
</ol>
<hr>
<h2 id="🧨-선언형-ui의-swiftui">🧨 선언형 UI의 <code>SwiftUI</code></h2>
<p>SwiftUI는 iOS 13부터 도입된 새로운 UI 프레임워크이다.</p>
<p>⭐ UIKit와는 다르게 <code>선언형(Declarative UI)</code> 방식을 사용한다.</p>
<p>이는 코드가 매우 간결하고 직관적이지만 <strong>아직 모든 UIKit 기능을 대체하지 못하고 있다.</strong></p>
<h2 id="📌-swiftui의-주요-특징">📌 SwiftUI의 주요 특징</h2>
<ol>
<li><p>선언현 프로그래밍(Declarative UI) 방식이다.</p>
<p> → UI를 코드에서 직접 그리는게 아닌 <code>UI가 어떤 모습이어야 하는지</code> 를 선언하는 형식이다.</p>
</li>
<li><p>UIKit와 AppKit를 대체하는 새로운 방식이다.</p>
<p> → SwiftUI는 iOS, macOS, watchOS, tvOS 에서 공통적으로 사용할 수 있는 UI 프레임워크이다.</p>
</li>
<li><p>코드가 간결하고 유지보수가 쉽다.</p>
<p> → 기존 UIKit보다 훨씬 적은 코드로 UI를 만들 수 있다.</p>
</li>
<li><p>⭐ iOS 13 이상에서만 사용 가능하다.</p>
<p> → iOS 12 이하를 지원해야 하는 앱에서는 SwiftUI를 단독으로 사용할 수 없다.</p>
</li>
</ol>
<h2 id="📎-swiftui의-ui-개발-방식">📎 SwiftUI의 UI 개발 방식</h2>
<p>SwiftUI는 스토리보드 없이 모든 UI를 <code>코드로 작성한다.</code></p>
<h3 id="swiftui-코드-예시-버튼-추가">SwiftUI 코드 예시 (버튼 추가)</h3>
<pre><code class="language-swift">import SwiftUI

struct ContentView: View {
    var body: some View {
        Button(&quot;클릭하세요&quot;) {
            print(&quot;버튼이 눌렸어요&quot;)
        }
        .padding()
    }
}</code></pre>
<p>→ UIKit와 달리 <code>Button</code> 을 선언하면 자동으로 표시된다.</p>
<p>→ ⭐ UI 변경이 자동으로 반영되므로 <code>addSubView()</code> 와 같은 함수의 사용이 필요 없다.</p>
<hr>
<h1 id="👊-uikit와-swiftui-비교">👊 UIKit와 SwiftUI 비교</h1>
<table>
<thead>
<tr>
<th></th>
<th><strong>UIKit</strong></th>
<th><strong>SwiftUI</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>UI 구성 방식</strong></td>
<td><code>UIViewController</code> + <code>UIView</code></td>
<td><code>View</code> 구조체 기반</td>
</tr>
<tr>
<td><strong>프로그래밍 방식</strong></td>
<td>명령형 (Imperative)</td>
<td>선언형 (Declarative)</td>
</tr>
<tr>
<td><strong>파일 관리</strong></td>
<td><code>Storyboard</code>, <code>.xib</code>, <code>.swift</code> 파일 분리됨</td>
<td>모든 UI가 <code>.swift</code> 파일에서 정의됨</td>
</tr>
<tr>
<td><strong>호환성</strong></td>
<td>iOS 2 이상 지원</td>
<td>iOS 13 이상 지원</td>
</tr>
<tr>
<td><strong>기업 사용</strong></td>
<td>대부분 UIKit 기반</td>
<td>SwiftUI는 일부 화면에서 사용됨</td>
</tr>
<tr>
<td><strong>장점</strong></td>
<td>더 세밀한 UI 컨트롤 가능</td>
<td>코드가 간결하고 유지보수 용이</td>
</tr>
<tr>
<td><strong>단점</strong></td>
<td>코드가 많아질 수 있음</td>
<td>성숙도가 낮고 일부 기능 부족</td>
</tr>
</tbody></table>
<hr>
<h1 id="🧑🚀-요약">🧑‍🚀 요약!</h1>
<blockquote>
<ol>
<li>Cocoa Touch Framework는 iOS 개발의 기본이며, UIKit과 SwiftUI는 그 위에서 동작하는 UI 프레임워크이다.</li>
<li>UIKit은 기존의 명령형 방식 UI 프레임워크이며, 현재 대부분의 앱에서 사용된다.</li>
<li>SwiftUI는 선언형 방식의 새로운 UI 프레임워크지만, 아직 UIKit을 완전히 대체하지 못한다.</li>
</ol>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 예외처리]]></title>
            <link>https://velog.io/@dxxh_e/Swift-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@dxxh_e/Swift-%EC%98%88%EC%99%B8%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Sun, 09 Mar 2025 05:07:12 GMT</pubDate>
            <description><![CDATA[<hr>
<h1 id="swift의-예외처리는-어떻게-이루어질까">Swift의 예외처리는 어떻게 이루어질까?</h1>
<pre><code class="language-swift">struct Diff: View {

    @State var inputNumber = &quot;&quot;
    @State var resultNumber: Float = 0

    var body: some View {
        VStack{
            TextField(&quot;나눌 숫자를 입력하세요&quot;, text: $inputNumber)
            Text(&quot;나눈 결과는 다음과 같습니다. \(resultNumber)&quot;)
            Button{
                do { // 일단 아래의 코드를 실행하고
                    try resultNumber = devideTen(with: (Float(inputNumber) ?? 1.0))
                } catch DivideError.diviedByZero{ // 오류 발생시 특정 오류 캐치 (미리 정의한 에러)
                    print(&quot;0으로 나누었어요&quot;)
                    resultNumber = 0
                } catch { // 그 외의 오류
                    print(&quot;알수 없는 오류가 발생되었어요&quot;)
                }
            }label: {
                Text(&quot;나누기&quot;)
            }
        }
    }

    // throws를 명시한 함수 -&gt; 문제가 발생할 가능성이 있는 함수임을 명시
    func devideTen(with inputNumber: Float) throws -&gt; Float {
        var result: Float = 0
        if inputNumber == 0 {
            // error (오류 발생시 예외 던지기
            throw DivideError.diviedByZero
        }else{
            result = 10 / inputNumber
        }

        return result
    }
}

// 에러(예외)는 직접 정의할 수 있다.
enum DivideError: Error {
    case diviedByZero
}</code></pre>
<ul>
<li><p>스위프트의 기본적인 예외 처리 시스템은 주로 아래의 키워드를 사용하여 오류를 처리한다.</p>
<ul>
<li><p><code>throw</code>, <code>try</code>, <code>catch</code></p>
</li>
<li><p>기본적인 구문은 다른 언어와 달리 아래와 같은 형식을 사용한다.</p>
<ul>
<li><code>try-catch</code> 가 아닌 <code>do-catch</code> 형식을 사용한다.</li>
</ul>
</li>
<li><p>스위프트는 <code>try</code> 키워드를 다양하게 사용할 수 있다.</p>
<ul>
<li><p><code>try</code> : 오류를 던질 수 있는 함수(<code>throws</code>가 명시된 함수)를 호출할 때 사용한다.</p>
<p>  → 이 경우 반드시 <code>do-catch</code> 구문으로 처리하거나 <code>try?</code> 혹은 <code>try!</code> 으로 처리해야한다.</p>
</li>
<li><p><code>try?</code> : 만약, 함수에서 오류가 발생하면 <code>nil</code>을 반환한다. <code>do-catch</code> 구문을 정의할 필요 없이 간단하게 오류를 무시하고 <code>nil</code>을 반환시킬 수 있다.</p>
<pre><code class="language-swift">  let result = try? divide(10, 0) // 오류가 발생하면 nil이 반환</code></pre>
</li>
<li><p><code>try!</code> : 함수 호출이 오류 없이 <strong>반드시</strong> 성공한다고 확신할 때 사용한다.</p>
<p>  → 만약, 오류가 발생하면 앱이 크래시된다. 💣</p>
<pre><code class="language-swift">  let result = try! divide(10, 2) // 오류가 발생하지 않는다고 가정</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p>스위프트는 <code>throws</code> 를 활용하여 오류를 던질 수 있는 함수(오류가 발생할 가능성이 있는 함수)를 정의한다.</p>
</li>
</ul>
<pre><code class="language-swift">    // throws를 명시한 함수 -&gt; 문제가 발생할 가능성이 있는 함수임을 명시
    func devideTen(with inputNumber: Float) throws -&gt; Float {
        var result: Float = 0
        if inputNumber == 0 {
            // error (오류 발생시 예외 던지기
            throw DivideError.diviedByZero
        }else{
            result = 10 / inputNumber
        }

        return result
    }</code></pre>
<ul>
<li>스위프트는 <code>do-catch</code> 를 활용하여 <code>do</code> 블록 내에서 오류가 발생할 수 있는 코드를 실행하고, <code>catch</code> 블록에서 이를 처리한다.</li>
</ul>
<pre><code class="language-swift">            Button{
                do { // 일단 아래의 코드를 실행하고
                    try resultNumber = devideTen(with: (Float(inputNumber) ?? 1.0))
                } catch DivideError.diviedByZero{ // 오류 발생시 특정 오류 캐치 (미리 정의한 에러)
                    print(&quot;0으로 나누었어요&quot;)
                    resultNumber = 0
                } catch { // 그 외의 오류
                    print(&quot;알수 없는 오류가 발생되었어요&quot;)
                }
            }label: {
                Text(&quot;나누기&quot;)
            }</code></pre>
<ul>
<li><p>스위프트는 <code>Error</code> 프로토콜을 <code>채택(Adopt)</code>한 <strong>열거형을 통해 개발자가 직접 오류를 정의할 수 있다.</strong></p>
<ul>
<li><p>정의된 오류는 자신이 만든 함수나 메서드에 던져 처리할 수 있다.</p>
<p>→ 즉, 기본 제공되는 예외들을 사용하지 않고도 개발자가 필요에 따라 오류를 정의하고 처리할 수 있다!</p>
<pre><code class="language-swift">enum MyError: Error {
  case divisionByZero
  case invalidInput
}

// MyError 열거형은 Error 프로토콜을 &quot;채택&quot; 한다.</code></pre>
</li>
<li><p>프로토콜 채택과 클래스 상속은 엄연히 다른 개념이니 유의하자.</p>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 프로토콜]]></title>
            <link>https://velog.io/@dxxh_e/Swift-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</link>
            <guid>https://velog.io/@dxxh_e/Swift-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</guid>
            <pubDate>Sun, 09 Mar 2025 05:05:37 GMT</pubDate>
            <description><![CDATA[<h1 id="7-프로토콜protocol">7. 프로토콜(Protocol)</h1>
<ul>
<li>Swift의 프로토콜은 인터페이스(Interface) 역할을 수행하며 특정 기능에 대한 청사진(Blueprint)을 정의한다.</li>
<li>프로토콜을 <code>채택(Adopt)</code> 한 타입(구조체, 클래스, 열거형)은 해당 프로토콜에서 요구하는 속성과 메서드를 <strong>반드시 구현해야 한다.</strong></li>
<li>프로토콜의 핵심 개념 3가지<ul>
<li>규약 정의 : 프로토콜은 특정 메서드, 속성, 연산자 등을 정의한다.</li>
<li>구현 강제 : 프로토콜을 채택한 타입은 반드시 규악을 준수해야 한다.</li>
<li>다형성 지원 : 하나의 프로토콜로 여러 타입을 동일하게 다룰 수 있다.</li>
</ul>
</li>
<li>프로토콜의 특징</li>
</ul>
<pre><code>| **특징** | **설명** |
| --- | --- |
| **메서드 요구** | 특정 메서드를 요구할 수 있음 |
| **속성 요구** | 특정 속성(프로퍼티)을 요구할 수 있음 |
| **다중 채택 가능** | 하나의 타입이 여러 프로토콜을 동시에 채택 가능 |
| **확장(Extension)** | 프로토콜에 기본 구현 제공 가능 |</code></pre><ul>
<li>프로토콜 정의 및 채택(사용법)</li>
</ul>
<pre><code class="language-swift">protocol Driveable {
    func speedDown(with speed: Int) -&gt; Int
}
// Driveable -&gt; 프로토콜 이름
//speedDown(with:) -&gt; 프로토콜이 요구하는 메소드 시그니처

// 원하는 타입(구조체, 클래스, 열거형)에서 프로토콜 채택
// 구조체
struct KIA: Driveable {
    func speedDown(with speed: Int) -&gt; Int {
        print(&quot;속도가 줄어듭니다.&quot;)
        return speed - 5
    }
}

// KIA 구조체가 Driveable 프로토콜을 채택(Adopt)
// speedDown(with:) 메서드를 필수로 구현.</code></pre>
<h2 id="7-1-프로토콜을-활용한-다형성polymorphism">7-1. 프로토콜을 활용한 다형성(Polymorphism)</h2>
<ul>
<li><p>프로토콜을 사용하면 <strong>서로 다른 타입을 하나의 프로토콜 타입으로 묶어 처리할 수 있다.</strong></p>
</li>
<li><p>아래의 예시는 <code>cars</code> 배열에 <code>Driveable</code> 프로토콜을 채택한 모든 타입을 담을 수 있다는 것을 보여준다.</p>
<p>  → 다형성을 통해 코드의 유연성과 확장성 증가!</p>
<pre><code class="language-swift">  let cars: [Driveable] = [KIA(), Hyundai()]

  // cars 배열에 Driveable 프로토콜을 채택한 서로 다른 구조체 저장
  cars.first?.speedDown(with: 100)
  cars.randomElement()?.speedDown(with: 100)</code></pre>
</li>
</ul>
<h2 id="72-프로토콜-확장protocol-extension">7.2 프로토콜 확장(Protocol Extension)</h2>
<ul>
<li>객체지향의 오버라이드(Overried)와 같은 개념이다.</li>
<li>정의된 프로토콜에 추가적인 메소드 구현을 진행할 수 있다.</li>
</ul>
<pre><code class="language-swift">protocol Driveable {
    func speedDown(with speed: Int) -&gt; Int
}

extension Driveable {
    func stop() {
        print(&quot;차량이 멈춥니다.&quot;)
    }
}

let cars: [Driveable] = [KIA(), Hyundai()]
cars.first?.stop() // 차량이 멈춥니다.</code></pre>
<hr>
<h1 id="tip-swiftui의-identifiable-프로토콜">Tip. SwiftUI의 Identifiable 프로토콜</h1>
<ul>
<li>SwiftUI의 <code>ForEach</code> 는 각 항목을 <strong>고유하게 구분하기 위하여 Identifiable 프로토콜을 요구한다.</strong><ul>
<li>컬렉션의 각 항목을 식별하여 <strong>뷰가 효율적으로 업데이트 되도록 하는 역할을 수행한다.</strong></li>
<li>💡 <code>React</code> 에서 반복되는 컴포넌트의 <code>Key</code> 가 고유한 식별자로 사용되는 것과 같은 기능이다.</li>
</ul>
</li>
<li>SwiftUI에서 Identifiable 프로토콜의 역할은 아래와 같다.<ol>
<li>각 항목에 <strong>고유한 식별자(id)를 제공한다.</strong></li>
<li>SwiftUI의 <code>ForEach</code> 가 항목을 추적하고 변경 사항을 감지할 수 있도록 돕는다.</li>
<li><strong>리렌더링을 최적화하여 항목치 추가,삭제,변경될 때 정확히 어떤 항목이 수정되었는지 빠르게 파악한다.</strong></li>
</ol>
</li>
<li>Identifiable 프로토콜의 정의</li>
</ul>
<pre><code class="language-swift">protocol Identifiable {
    associatedtype ID: Hashable // Hashable을 준수해야한다. (UUID, Int, String 등)
    var id: ID { get } // 필수 구현 요소. 해당 값은 고유해야 한다.
}</code></pre>
<ul>
<li>커스텀 프로토콜과 Identifiable 프로토콜을 채택한 코드의 예시</li>
</ul>
<pre><code class="language-swift">import SwiftUI

// Driveable 프로토콜을 채택하고 Identifiable도 채택
protocol Driveable: Identifiable {
    func speedDown(with speed: Int) -&gt; Int
}

struct KIA: Driveable {
    let id = UUID() // 고유 식별자
    func speedDown(with speed: Int) -&gt; Int {
        print(&quot;속도가 줄어듭니다.&quot;)
        return speed - 5
    }
}

struct Hyundai: Driveable {
    let id = UUID() // 고유 식별자
    func speedDown(with speed: Int) -&gt; Int {
        print(&quot;속도가 더욱 줄어듭니다.&quot;)
        return speed - 10
    }
}

struct CarListView: View {
    let cars: [Driveable] = [KIA(), Hyundai()]

    var body: some View {
        VStack {
            ForEach(cars) { car in
                Text(&quot;차량 감속 테스트 중&quot;)
            }
        }
    }
}

#Preview {
    CarListView()
}

/*
    1. KIA, Hyundai 구조체는 Driveable과 Identifiable 프로토콜을 동시에 채택한다.
    2. 각 구조체 인스턴스에 id를 UUID()로 할당하여 인스턴스가 고유한 식별자를 가지도록 유도
    3. ForEach는 각 인스턴스를 고유하게 식별하게 된다.
*/</code></pre>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 옵셔널과 옵셔널 체이닝, 바인딩]]></title>
            <link>https://velog.io/@dxxh_e/Swift-%EC%98%B5%EC%85%94%EB%84%90%EA%B3%BC-%EC%98%B5%EC%85%94%EB%84%90-%EC%B2%B4%EC%9D%B4%EB%8B%9D-%EB%B0%94%EC%9D%B8%EB%94%A9</link>
            <guid>https://velog.io/@dxxh_e/Swift-%EC%98%B5%EC%85%94%EB%84%90%EA%B3%BC-%EC%98%B5%EC%85%94%EB%84%90-%EC%B2%B4%EC%9D%B4%EB%8B%9D-%EB%B0%94%EC%9D%B8%EB%94%A9</guid>
            <pubDate>Sun, 09 Mar 2025 05:04:25 GMT</pubDate>
            <description><![CDATA[<h1 id="5-옵셔널">5. 옵셔널</h1>
<ul>
<li>있을 수도 있고 없을 수도 있는 값</li>
<li>원하는 타입 뒤에 <code>?</code> 을 붙여서 만든다.</li>
<li><strong>⭐ 만약 값이 있다면 본래의 값이 그대로 있으며 없으면 <code>nil</code> 이 존재한다.</strong><ul>
<li>즉, <code>nil</code> == <code>null</code></li>
<li>아래 사진을 예시로 보면, 왼쪽 휴지심은 0이 존재한다. (즉, 변할 여지가 있다.)</li>
<li><strong>오른쪽은 변할 여지가 없이 휴지심이고 뭐고 아예 없다. 즉 <code>nil</code> 이다.</strong></li>
<li>“” → 빈 문자열(좌측)</li>
<li>nil → 값 자체가 없음(우측)</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/66f17ebc-8c45-4acb-873e-64571e61c692/image.png" alt=""></p>
<pre><code class="language-swift">let name: String = &quot;DaeHyeon&quot;
let petName: String? = &quot;&quot;

// 중요!
let name: String = &quot;&quot; // 빈 문자열(&quot;&quot;)이 존재하는 상태.
// 값은 있지만 그 값은 &quot;아무것도 없는 빈 문자열&quot;이 존재하는 상태.
// 즉, nil이 아니다.

let name: String? = &quot;&quot; // 옵셔널 String이기 때문에 nil을 가질 수 있다.
// 하지만 여전히 빈 문자열(&quot;&quot;)이 존재하기에 nil이 아닌 &quot;아무것도 없는 빈 문자열&quot;이 존재한다.

let name: String? = nil // 옵셔널 String
// nil. 값이 없는 상태
</code></pre>
<ul>
<li><p><code>String</code> 은 “String” 타입, <code>String?</code> 은 “옵셔널 String” 타입이다.</p>
<p>  → 이 둘은 명확히 다르다.</p>
</li>
</ul>
<hr>
<h1 id="⭐6-옵셔널-바인딩-체이닝">⭐6. 옵셔널 바인딩, 체이닝</h1>
<ul>
<li><p>옵셔널은 “없는” 값을 표현하고 싶은게 아닌, <strong>안전함을 추구하기 위해 만들어진 기능</strong></p>
<ul>
<li><p>만약, 어떠한 값에 접근하려 했는데 존재하지 않는다면 → 크래쉬 발생</p>
</li>
<li><p>예시(아래와 같은 상황에 사용되는 개념이 <code>바인딩</code> , <code>체이닝</code> 이다.</p>
<pre><code class="language-swift">let fruits = [&quot;Apple&quot;, &quot;Banana&quot;]
let myFavorite = fruits[3] // 오류가 발생되어 서비스가 죽어버리는 상황 발샐</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="6-1-옵셔널-바인딩">6-1. 옵셔널 바인딩</h2>
<ul>
<li><p>옵셔널 안의 값을 <code>꺼내는 작업</code></p>
</li>
<li><p>키워드 : <code>if let</code></p>
</li>
<li><p>💡 <strong>옵셔널 안에 값이 있는지 없는지 확인하는 작업을 말한다.</strong></p>
<ul>
<li><p>아래의 예시는 <strong>“옵셔널 안에 값이 있다면 사용한다는 의미이다.”</strong></p>
<pre><code class="language-swift">let petName: String? = &quot;coco&quot;

// if와 let을 하나의 키워드로 바라보자.
if let name = petName { // if let : 옵셔널 바인딩을 위한 변수, name : 할당할 변수
  print(name) // 옵셔널 변수 petName에서 할당된 name은 더이상 옵셔널 변수가 아닌, 일반 변수
}</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="6-2-옵셔널-체이닝">6-2. 옵셔널 체이닝</h2>
<pre><code class="language-swift">struct People {
    let hobby: Hobby?
}

struct Hobby {
    let level: Int?
}</code></pre>
<ul>
<li><p>위 예시에서 <code>level</code> 을 사용하기 위해선 People에 값이 있는지 없는지 확인한 뒤(바인딩) 다시 Hobby에 값이 있는지 없는지 확인해야한다.</p>
<p>  → 즉, 옵셔널 바인딩을 여러번 해야한다. (if let 안에.. if let..)</p>
<ul>
<li>💡 위와 같은 상황을 방지하고자 있는 개념이 <code>옵셔널 체이닝</code> 이다.</li>
</ul>
</li>
<li><p>⭐ <strong>만약, 연결(체인)된 옵셔널 타입 중 하나라도 <code>nil</code> 이면 <code>nil</code> 이다.</strong></p>
<ul>
<li><code>petName?.age.level</code></li>
</ul>
</li>
</ul>
<pre><code class="language-swift">if let name = petName?.age.level{
    print(name)
}

// petName은 &quot;옵셔널&quot; 이지만 age와 level은 옵셔널인지 아닌지 모르며, 값이 있는지 없는지 모른다.
// 따라서 모든 옵셔널 타입이 &quot;존재&quot;한다면 옵셔널 바인딩이 수행
// 단 하나라도 `nil`이라면 옵셔널 바인딩 수행 X</code></pre>
<h2 id="6-3-옵셔널-바인딩--체이닝-종합-예시">6-3. 옵셔널 바인딩 &amp; 체이닝 종합 예시</h2>
<pre><code class="language-swift">import SwiftUI

struct Diff: View {

    // 사람이 존재할 수도 있으며, MBTI가 존재할 수도 있다. (다중 옵셔널 예시)
    var human1: People? = People(name: &quot;daehyeon&quot;, mbti: MBTI(name: &quot;ENFJ&quot;))
    var human2 = People(name: &quot;bami&quot;, petName: &quot;coco&quot;)
    var human3 = People(name: &quot;berry&quot;, petName: &quot;mong&quot;)

    var body: some View {
        VStack{

            // 옵셔널 체이닝 예시
            if let human1MbtiName = human1?.mbti?.name{
                Text(human1MbtiName)
            }else{
                Text(&quot;No MBTI name!&quot;)
            }

            // 과도한 바인딩 예시 (옵셔널 체이닝을 사용해야하는 이유)
//            if let human1 = human1{
//                if let mbti = human1.mbti{
//                    if let name = mbti.name{
//                        
//                    }
//                }
//            }

            // 옵셔널 바인딩 예시
//            if let petName = human1.petName{ // 값이 존재한다면 petName에 옵셔널에 존재하는 값 할당
//                Text(&quot;이름은 \(human1.name), 반려동물 이름은 \(petName)입니다.&quot;)
//            }else{ // 만약, petName이 nil이라면
//                Text(&quot;이름은 \(human1.name), 반려동물은 키우지 않아요.&quot;)
//            }

            // 옵셔널 바인딩
            if let petName = human2.petName{
                Text(&quot;이름은 \(human2.name), 반려동물 이름은 \(petName)입니다.&quot;)
            }else{ // 만약, petName이 nil이라면
                Text(&quot;이름은 \(human2.name), 반려동물은 키우지 않아요.&quot;)
            }

            // 옵셔널 바인딩
            if let petName = human3.petName{
                Text(&quot;이름은 \(human3.name), 반려동물 이름은 \(petName)입니다.&quot;)
            }else{ // 만약, petName이 nil이라면
                Text(&quot;이름은 \(human3.name), 반려동물은 키우지 않아요.&quot;)
            }
        }
    }
}

struct People{
    let name: String
    var petName: String?
    var mbti: MBTI?
}

struct MBTI {
    let name: String?
}</code></pre>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 구조체부터 스위치까지]]></title>
            <link>https://velog.io/@dxxh_e/Swift-%EB%AC%B8%EB%B2%95-%EA%B5%AC%EC%A1%B0%EC%B2%B4%EB%B6%80%ED%84%B0-%EC%8A%A4%EC%9C%84%EC%B9%98%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@dxxh_e/Swift-%EB%AC%B8%EB%B2%95-%EA%B5%AC%EC%A1%B0%EC%B2%B4%EB%B6%80%ED%84%B0-%EC%8A%A4%EC%9C%84%EC%B9%98%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Sun, 09 Mar 2025 05:01:08 GMT</pubDate>
            <description><![CDATA[<h1 id="1-구조체">1. 구조체</h1>
<ul>
<li>키워드 : <code>struct</code></li>
<li>의미 : 하나의 동작을 수행하는 <code>객체</code></li>
<li>💡 <code>struct</code> 내부엔 <code>func</code> 와 <code>var</code> 등이 포함된다.</li>
<li><strong>구조체는 <code>값 타입</code> 으로 데이터를 묶어서 저장하고, 복사 시 <code>값</code> 이 복사 된다.</strong><ul>
<li>값을 복사하여 전달되기 때문에 인스턴스를 다른 변수에 할당하거나 함수에 전달할 때 원본이 아닌 <code>복사본</code> 이 전달된다.</li>
</ul>
</li>
<li>자동 멤버와이즈 이니셜라이저 제공<ul>
<li>Swift의 구조체는 모든 프로퍼티를 초기화하는 <strong>기본 생성자(멤버와이즈 이니셜라이저, Memberwise Initializer)</strong> 제공 → <strong>⭐ 클래스에선 제공되지 않는다!</strong></li>
<li>Java의 “생성자”와 매우 유사하며 Swift에선 기본 생성자가 자동 제공되어 코드가 깔끔하고 직관적이다.</li>
</ul>
</li>
<li>구조체 메서드에서 자신의 프로퍼티를 변경하려면 <code>mutating</code> 키워드 필수</li>
<li>상속이 불가능하다. (클래스만 상속 가능)</li>
<li><code>let</code>으로 선언한 구조체 인스턴스는 내부 프로퍼티를 변경 할 수 없음.</li>
<li>언제 사용하는가?<ul>
<li>데이터의 복사가 필요할 때(ex. 좌표, 색상, 설정값)</li>
<li>상속이 필요 없는 경우</li>
<li>값의 <code>불변성</code> 을 유지하는 데이터 모델을 만들 때</li>
</ul>
</li>
</ul>
<pre><code class="language-swift">// 문법

// 구조체 정의
struct Person{
    // 프로퍼티(속성)
    var name: String
    var age: Int

    // 메서드
    func introduce(){
        print(&quot;안녕하세요 제 이름은 \(name)이고, \(age)살 입니다.&quot;)
    }
}

// 구조체 인스턴스 생성
var person1 = Person(name: &quot;홍길동&quot;, age: &quot;25&quot;)
person1.introduce() // 출력 : 안녕하세요 제 이름은 홍길동이고 25살입니다.

// 메소드에서 프로퍼티 변경 시 (mutating)
struct Counter{
    var count = 0

    mutating func increment(){ // func increment는 오류
        count += 1
    }
}

var counter = Counter()
counter.increment()
print(counter.count) // 출력 : 1

// let으로 선언한 구조체 인스턴스의 경우
let person2 = Person(name: &quot;고길동&quot;, age: &quot;30&quot;) // 구조체 인스턴스 생성
person2.age = 31 // 오류 발생 </code></pre>
<hr>
<h1 id="2-클래스">2. 클래스</h1>
<ul>
<li>키워드 : <code>class</code></li>
<li>클래스는 <code>참조 타입(Reference Type)</code> 이다. 클래스를 복사하면 원분과 복사본이 같은 객체를 참조한다.</li>
<li>클래스를 <code>상속</code> 할 수 있다.</li>
<li>클래스는 <code>디이니셜라이저(Deinitializer)</code> 를 제공한다.<ul>
<li>객체가 메모리에서 해제될 때 실행되는 <code>deinit</code> 메서드를 제공한다.</li>
</ul>
</li>
<li>구조체와 달리 멤버와이즈 이니셜라이저를 제공하지 않는다.<ul>
<li>직접 <code>init</code> 생성자를 정의해야한다.</li>
</ul>
</li>
<li>두 객체가 같은 인스턴스를 참조하는지 확인할 수 있다.<ul>
<li><code>Identical 연산자 ===</code> 사용 가능</li>
</ul>
</li>
</ul>
<pre><code class="language-swift">// 클래스 정의
class Person {
    var name: String
    var age: Int

    // 이니셜라이저 (생성자)
    init(name: String, age: Int){
        self.name = name
        self.age = age
    }

    // 메서드
    func introduce() {
        print(&quot;안녕하세요 제 이름은 \(name)이고, \(age)살 입니다.&quot;)
    }
}

// 클래스 인스턴스 생성
let person1 = Person(name: &quot;지민&quot;, 25)
person1.introduce()

// 클래스를 복사하면 원문과 복사본이 같은 객체를 공유한다.
let person2 = person1
person2.name = &quot;민지&quot;
print(person1.name) // 출력 : 민지

// Identical 연산자 (===)
let person3 = person1
print(person1 === person3) // 출력 : true (같은 객체를 참조한다.</code></pre>
<ul>
<li>클래스는 상속을 통해 다른 클래스를 확장할 수 있다. (Inferitance)</li>
</ul>
<pre><code class="language-swift">class Student: Person {
    var studentID: String

    init(name: String, age: Int, studentID: String) {
        self.studentID = studentID
        super.init(name: name, age: age)
    }

    override func introduce() {
        print(&quot;저는 학생 \(name)이고, \(age)살이며 학번은 \(studentID)입니다.&quot;)
    }
}

let student = Student(name: &quot;유나&quot;, age: 20, studentID: &quot;S1234&quot;)
student.introduce()
// 출력: 저는 학생 유나이고, 20살이며 학번은 S1234입니다.</code></pre>
<ul>
<li>메모리에서 해제될 때 실행되는 <code>deinit</code></li>
</ul>
<pre><code class="language-swift">class File {
    var filename: String

    init(filename: String) {
        self.filename = filename
        print(&quot;\(filename) 파일이 생성되었습니다.&quot;)
    }

    deinit {
        print(&quot;\(filename) 파일이 삭제되었습니다.&quot;)
    }
}

var file: File? = File(filename: &quot;test.txt&quot;)
file = nil // 파일 삭제 시 deinit 호출
// 출력: test.txt 파일이 삭제되었습니다.</code></pre>
<hr>
<h1 id="tip🤔-구조체와-클래스의-차이는">Tip.🤔 구조체와 클래스의 차이는?</h1>
<ul>
<li>구조체(struct)는 <code>값 타입</code> 으로 <strong>인스턴스가 복사될 때 <code>값</code>이 복사된다.</strong></li>
<li>클래스(class)는 <code>참조 타입</code> 으로 인스턴스가 복사될 때 <code>참조</code> 가 복사된다.</li>
</ul>
<h3 id="구조체에-대한-자세한-의미">구조체에 대한 자세한 의미.</h3>
<p> 구조체는 값 타입이기 때문에 원본 구조체를 복사해도 다른 변수에 영향을 주지 않는다.</p>
<pre><code class="language-swift">struct Person{
    var name: String
}

var person1 = Person(name: &quot;Alice&quot;)
var person2 = person1 // person1을 2에 복사
person2.name = &quot;Bob&quot; // 원본 구조체에 영향가지 않음. 따라서 person2만 변경된다.

// 실제 결과
print(person1.name) // 출력 : &quot;Alice&quot;
print(person2.name) // 출력 : &quot;Bob&quot;

// 즉, person1과 person2은 &quot;서로 다른 복사본&quot;</code></pre>
<h3 id="클래스에-대한-자세한-의미">클래스에 대한 자세한 의미</h3>
<ul>
<li><p>클래스는 참조타입이다. 클래스를 변수에 할당하거나 함수에 전달할 때 <code>참조가 복사된다.</code></p>
<p>  → 즉, 같은 인스턴스를 여러 변수에서 참조하게 되어, 한 곳에서 변경하면 다른 곳에도 영향을 끼친다.</p>
</li>
</ul>
<pre><code class="language-swift">class Person{
    var name: String
    init(name: String){
        self.name = name
    }
}

var person1 = Person(name: &quot;Alice&quot;)
var person2 = person1 // person2에 person1 참조 전달
person2.name = &quot;Bob&quot; // person1과 person2 모두 데이터가 변경됨.

print(person1.name) // 출력 : &quot;Bob&quot;
print(person2.name) // 출력 : &quot;Bob&quot;

// 즉, person1과 person2는 같은 객체를 참조하고 있기에 하나를 변경하면 다른 하나도 변경된다.</code></pre>
<hr>
<h1 id="2-1-클래스와-swiftui-데이터-연동-요약">2-1. 클래스와 SwiftUI 데이터 연동 요약</h1>
<ul>
<li><strong>클래스는 참조 타입(Reference Type)</strong>같은 인스턴스를 여러 변수에서 공유하고, 한 곳에서 변경하면 모든 곳에 반영됨.</li>
<li><strong>SwiftUI에서 클래스 상태 관리:</strong><ul>
<li><code>@ObservedObject</code> → 뷰가 클래스 인스턴스를 구독해 데이터 변화를 감지.</li>
<li><code>@Published</code> → 클래스 속성에 붙여, 값이 바뀔 때 SwiftUI가 자동으로 화면 업데이트.</li>
<li>클래스는 <code>ObservableObject</code> 프로토콜을 채택해야 <code>@Published</code>가 작동.</li>
</ul>
</li>
</ul>
<p>💡 <strong>한 줄 정리:</strong></p>
<p><code>@ObservedObject</code>와 <code>@Published</code>는 <strong>클래스 전용</strong>. 값 변경 → 화면 자동 업데이트!</p>
<pre><code class="language-swift">import SwiftUI

struct Diff: View {

    // 구조체
    let myCar = Car(name: &quot;리어카&quot;, owner: &quot;라이오&quot;)
    // 클래스
    @ObservedObject var myKar = Kar(name: &quot;리어카2&quot;, owner: &quot;라이오2&quot;)

    var body: some View {
        VStack{
            Text(&quot;\(myKar.name)의 주인은 \(myKar.owner)입니다.&quot;)
            Button{
                let broCar = myKar
                broCar.name = &quot;동생차&quot;
                broCar.owner = &quot;동생&quot;

                myKar.sayHi()
            } label : {
                Text(&quot;출발&quot;)
            }
        }
    }
}

struct Car{
    let name: String
    let owner: String

    func sayHi(){
        print(&quot;hi \(owner)&quot;)
    }
}

class Kar: ObservableObject{
    @Published var name: String
    var owner: String

    init(name: String, owner: String){
        self.name = name
        self.owner = owner
    }

    func sayHi(){
        print(&quot;hi \(owner)2&quot;)
    }
}

#Preview {
    Diff()
}</code></pre>
<hr>
<h1 id="3-열거형">3. 열거형</h1>
<ul>
<li><p><code>열거형(Enumeration, enum)</code> : 관련된 값들의 그룹을 한데 묶어 표현하는 <code>데이터 타입</code></p>
</li>
<li><p>단순 정수 형태 뿐만 아닌, 다양한 타입의 값이나 연관된 데이터를 가질 수 있다.</p>
</li>
<li><p>열거형에 접근할 때는 <code>열거형이름.값</code> 형태로 접근하지만 같은 타입 내에서 사용할 때는 <code>.값</code> 으로 축약이 가능하다.</p>
</li>
<li><p><strong>⭐ 자바의 제네릭처럼 특정 변수에 들어가야 하는 값의 형식을 미리 정의할 수 있다.</strong></p>
<p>  <strong>→ 인수인계의 극대화!</strong></p>
</li>
</ul>
<pre><code class="language-swift">// 기본 열거형 선언
enum CompassPoint {
    case north
    case south
    case east
    case west
}

// 방법 1
var direction = CompassPoint.north
direction = .east // 축약형 사용 가능
print(direction) // east

// 방법 2
var dirction: CompassPoint = .north
print(dicetion) // north

// 즉, direction에는 4가지의 변수만 들어갈 수 있도록 하고싶다.</code></pre>
<ul>
<li>열거형에 기본 타입에 원시 값(Raw Value)를 연결할 수 있다.</li>
</ul>
<pre><code class="language-swift">enum Weekday: String{
    case monday = &quot;Mon&quot;
    case tuesday = &quot;Tue&quot;
    case wednesday = &quot;Wed&quot;
}

print(Weekday.monday.rawValue) // &quot;Mon&quot;

// 실제 Swift UI
import SwiftUI

struct Choice: View {
    var direction: Direction = .north
    var member: String = &quot;대현&quot;

    var body: some View {
        Text(&quot;방향은 \(direction.rawValue)쪽 입니다.&quot;)
        // 출력 : 방향은 북쪽 입니다.
    }
}

enum Direction: String {
    case north = &quot;북&quot;
    case west
    case east
    case south
}</code></pre>
<ul>
<li>정수형 원시 값은 첫 값부터 자동으로 0부터 할당된다.<ul>
<li>문자열 또한 <code>case</code> 이름을 그대로 원시 값으로 사용할 수 있다.</li>
</ul>
</li>
</ul>
<pre><code class="language-swift">enum Number: Int {
    case one = 1
    case two
    case three
}

print(Number.two.rawValue)</code></pre>
<ul>
<li>각 열거형 케이스에 서로 다른 타입의 데이터를 저장할 수 있다. (연관 값, Associated Values)</li>
</ul>
<pre><code class="language-swift">enum MediaType {
    case audio(String)
    case video(String, Int)
}

let song = MediaType.audio(&quot;Pop&quot;)
let movie = MediaType.video(&quot;Action&quot;, 120)

switch movie {
case .audio(let genre):
    print(&quot;Audio Genre: \(genre)&quot;)
case .video(let genre, let duration):
    print(&quot;Video Genre: \(genre), Duration : \(duration) min&quot;)
}

// Video Genre: Action, Duration: 120 min</code></pre>
<ul>
<li><p>열거형은 메서드와 프로퍼티를 가질 수 있다.</p>
<p>  → 열거형 자체가 <strong>하나의 타입으로 취급된다.</strong></p>
</li>
</ul>
<pre><code class="language-swift">enum Beverage: String{
    case coffee, tea, jucie

    var description: String{
        switch self {
        case .coffee: return &quot;뜨겁거나 차가운&quot;
        case .tea: return &quot;얼그레이나 복숭아&quot;
        case .juice: return &quot;스무디나 에이드&quot;
        }
    }
}

let drink = Beverage.coffee
print(dring.description) // 뜨겁거나 차가운</code></pre>
<ul>
<li>열거형은 <code>옵셔널 타입</code> , <code>예외 처리</code> , <code>상태 관리</code> 등 매우 자주 사용된다.</li>
</ul>
<pre><code class="language-swift">enum NetworkError: Error{
    case badURL
    case timeout
    case noInternet
}</code></pre>
<hr>
<h1 id="4-스위치">4. 스위치</h1>
<ul>
<li><p><code>Switch</code> 는 하나의 값에 따라 여러 경우(case) 중 실행할 코드를 결정하는 조건문</p>
</li>
<li><p><code>if-else</code> 보다 가독성이 뛰어나고 복잡한 조건 처리에 적합하다.</p>
</li>
<li><p><code>switch</code> 는 강력하고 안전한 패턴 매칭을 지원한다.</p>
</li>
<li><p>스위치는 모든 경우를 반드시 처리해야한다.</p>
<p>  → 모든 가능성을 처리해야 하며, 특히 ⭐ <code>enum</code> 의 모든 케이스가 나오지 않으면 오류 발생</p>
<p>  → swift의 switch는 각 case 실행 후 <strong>자동으로 종료되기 때문에 <code>break</code> 가 필요 없다.</strong></p>
<p>  → 단순 값 비교 외에 <code>range</code>, <code>where</code> 절 등 다양한 조건 추가 가능</p>
<p>  → <code>default</code> 를 반드시 사용해야 한다. (단, 모든 <code>enum</code> 케이스를 처리하면 필요 없다.)</p>
</li>
</ul>
<pre><code class="language-swift">// switch 문법 구조
switch 값 {
case 조건1:
    code
case 조건2:
    code
default:
    위 조건에 모두 해당되지 않을 때
}

// 예시
import SwiftUI

struct Diff: View {

    @State var myDirection: Direction = .south

    var body: some View {
        switch myDirection{
        case .north:
            Text(&quot;북쪽은 추워요&quot;)
        case .west:
            Text(&quot;서쪽은 석양이 예뻐요&quot;)
        case .east:
            Text(&quot;동쪽은 해보기 좋아요&quot;)
        case .south:
            Text(&quot;남쪽은 놀기 좋아요&quot;)
        }

        Button{
            myDirection = .east
        }label:{
            Text(&quot;돌리기&quot;)
        }
    }
}

enum Direction: String{
    case north = &quot;북&quot;
    case west = &quot;서&quot;
    case east = &quot;동&quot;
    case south = &quot;남&quot;
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 언더스코어(_)와 매개변수 레이블 정리]]></title>
            <link>https://velog.io/@dxxh_e/Swift-%EB%AC%B8%EB%B2%95-%EC%96%B8%EB%8D%94%EC%8A%A4%EC%BD%94%EC%96%B4%EC%99%80-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98-%EB%A0%88%EC%9D%B4%EB%B8%94-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@dxxh_e/Swift-%EB%AC%B8%EB%B2%95-%EC%96%B8%EB%8D%94%EC%8A%A4%EC%BD%94%EC%96%B4%EC%99%80-%EB%A7%A4%EA%B0%9C%EB%B3%80%EC%88%98-%EB%A0%88%EC%9D%B4%EB%B8%94-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sun, 09 Mar 2025 04:57:59 GMT</pubDate>
            <description><![CDATA[<hr>
<h3 id="1-매개변수-레이블과-매개변수-이름의-차이">1. 매개변수 레이블과 매개변수 이름의 차이</h3>
<p>Swift 함수에서는 <strong>매개변수 레이블(parameter label)</strong>과 <strong>매개변수 이름(parameter name)</strong>이 각각 존재하며, 서로 다른 역할을 한다.</p>
<ul>
<li><strong>매개변수 레이블</strong>: 함수 <strong>호출 시 사용</strong>되는 이름으로, <strong>함수 외부에서 가독성을 높이는 역할</strong>을 한다.</li>
<li><strong>매개변수 이름</strong>: 함수 <strong>내부에서 사용</strong>되는 이름으로, <strong>전달된 값을 참조하는 데 사용된다.</strong></li>
</ul>
<p><strong>예시:</strong></p>
<pre><code class="language-swift">func divide(number: Int, by divisor: Int) -&gt; Int {
    return number / divisor
}

// 함수 호출
let result = divide(number: 10, by: 2)
print(result) // 5</code></pre>
<ul>
<li><code>number</code>: <strong>매개변수 레이블</strong> → 함수 호출 시 사용</li>
<li><code>by</code>: <strong>매개변수 레이블</strong> → 함수 호출 시 사용</li>
<li><code>divisor</code>: <strong>매개변수 이름</strong> → 함수 내부에서 사용</li>
</ul>
<h3 id="2-언더스코어_의-사용-매개변수-레이블-생략">2. 언더스코어(<code>_</code>)의 사용: 매개변수 레이블 생략</h3>
<ul>
<li><em><code>_</code>(언더스코어)*</em>를 사용하면 매개변수 레이블을 생략할 수 있어 함수 호출 시 <strong>인수만 전달 가능하다.</strong></li>
</ul>
<p><strong>예시:</strong></p>
<pre><code class="language-swift">func multiply(_ number: Int, _ factor: Int) -&gt; Int {
    return number * factor
}

// 함수 호출 시 레이블 없이 사용 가능
let result = multiply(5, 2)
print(result) // 10</code></pre>
<ul>
<li><code>number</code>와 <code>factor</code> 모두 <strong>레이블 없이 호출</strong></li>
</ul>
<h3 id="3-매개변수-레이블의-활용-가독성-향상">3. 매개변수 레이블의 활용: 가독성 향상</h3>
<p>Swift의 <strong>API 디자인 가이드라인</strong>에서는 함수의 의도를 명확하게 표현하고 가독성을 높이는 레이블을 활용하도록 유도한다.</p>
<p><strong>예시:</strong></p>
<pre><code class="language-swift">func move(from start: String, to destination: String) {
    print(&quot;Moving from \(start) to \(destination)&quot;)
}

// 자연스러운 함수 호출 형태
move(from: &quot;Seoul&quot;, to: &quot;Busan&quot;)</code></pre>
<ul>
<li><strong><code>from</code></strong>, <strong><code>to</code></strong>: 함수 호출 시 동작의 의미가 명확해짐</li>
</ul>
<h3 id="4-매개변수-레이블을-매개변수-이름과-동일하게-설정">4. 매개변수 레이블을 매개변수 이름과 동일하게 설정</h3>
<p>매개변수 레이블과 매개변수 이름을 같게 할 수 있다.</p>
<p><strong>예시:</strong></p>
<pre><code class="language-swift">func divide(number: Int, divisor: Int) -&gt; Int {
    return number / divisor
}

let result = divide(number: 10, divisor: 2)
print(result) // 5</code></pre>
<h3 id="5-매개변수-레이블의-관례와-종류">5. 매개변수 레이블의 관례와 종류</h3>
<p>Swift에서는 <strong>동작 + 전치사 조합</strong>의 레이블을 많이 사용한다고 한다.</p>
<table>
<thead>
<tr>
<th><strong>레이블</strong></th>
<th><strong>의미</strong></th>
<th><strong>예시 함수</strong></th>
<th><strong>호출 방식</strong></th>
</tr>
</thead>
<tbody><tr>
<td><code>to</code></td>
<td>목적지</td>
<td><code>move(to:)</code></td>
<td><code>move(to: &quot;Home&quot;)</code></td>
</tr>
<tr>
<td><code>from</code></td>
<td>출발지</td>
<td><code>copy(from:)</code></td>
<td><code>copy(from: &quot;File&quot;)</code></td>
</tr>
<tr>
<td><code>with</code></td>
<td>함께 사용하는 값</td>
<td><code>combine(with:)</code></td>
<td><code>combine(with: &quot;A&quot;)</code></td>
</tr>
<tr>
<td><code>by</code></td>
<td>방법이나 기준</td>
<td><code>sort(by:)</code></td>
<td><code>sort(by: &lt;)</code></td>
</tr>
<tr>
<td><code>for</code></td>
<td>목적이나 대상</td>
<td><code>prepare(for:)</code></td>
<td><code>prepare(for: &quot;Trip&quot;)</code></td>
</tr>
</tbody></table>
<h3 id="6-정리">6. 정리</h3>
<ul>
<li><strong>매개변수 레이블</strong>: 함수 호출 시 사용, <strong>외부 가독성 향상</strong></li>
<li><strong>매개변수 이름</strong>: 함수 내부에서 사용, <strong>값 참조</strong></li>
<li><strong>언더스코어(<code>_</code>)</strong>: 레이블 생략 가능, <strong>간단한 호출 시 유용</strong></li>
<li><strong>Swift 관례</strong>: 동작 + 전치사 형태로 <strong>자연어 스타일</strong> 지향</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 변수, 타입, 컬렉션, 조건문]]></title>
            <link>https://velog.io/@dxxh_e/Swift-%EB%AC%B8%EB%B2%95-%EB%B3%80%EC%88%98-%ED%83%80%EC%9E%85-%EC%BB%AC%EB%A0%89%EC%85%98-%EC%A1%B0%EA%B1%B4%EB%AC%B8</link>
            <guid>https://velog.io/@dxxh_e/Swift-%EB%AC%B8%EB%B2%95-%EB%B3%80%EC%88%98-%ED%83%80%EC%9E%85-%EC%BB%AC%EB%A0%89%EC%85%98-%EC%A1%B0%EA%B1%B4%EB%AC%B8</guid>
            <pubDate>Thu, 16 Jan 2025 01:21:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dxxh_e/post/a4a84f41-2229-4e4d-9251-e469c400144f/image.png" alt=""></p>
<h2 id="1-변수">1. 변수</h2>
<ul>
<li><code>var</code> : 변수 (변하는 수)</li>
</ul>
<pre><code class="language-swift">var place: String

var place: String = &quot;Paris&quot;

var name: String = &quot;라이언&quot;
Text(&quot;\(name)님 안녕하세요&quot;)

# 결과 : 라이언님 안녕하세요</code></pre>
<ul>
<li><code>\(name)</code>은 서식문자와 같이 활용</li>
</ul>
<h2 id="2-변수의-타입">2. 변수의 타입</h2>
<ul>
<li><code>String</code> : 문자열</li>
<li><code>Int(Integer)</code> : 정수</li>
<li><code>Float</code> : 실수</li>
<li><code>Double</code> : 더 긴 실수</li>
<li><code>Bool</code> : 참과 거짓(true, false)</li>
</ul>
<blockquote>
<p>왜 타입이 중요한가?
→ 스위프트는 <code>안전</code> 을 지향한다.
→ <code>JS</code> 와는 반대.</p>
</blockquote>
<pre><code class="language-swift">import SwiftUI

struct VariableType: View {

    var name: String = &quot;DaeHyeon&quot;
    var age: Int = 25
    var height: Float = 180.1
    var havePet: Bool = true

    var body: some View {
              // VStack = Vertical Stack (세로)
        VStack{
                // Text()는 문자열을 props로 받길 원함
            Text(&quot;\(name)&quot;)
            Text(&quot;\(age)&quot;)
            Text(&quot;\(height)&quot;)
            // havePet은 bool이므로 description()을 호출하여 문자열로 변경
            // 원래는 해당 변수에 대한 &quot;설명&quot;을 불러옴.
            Text(&quot;\(havePet.description)&quot;)
        }
    }
}</code></pre>
<h2 id="3-컬렉션">3. 컬렉션</h2>
<ul>
<li><p><code>Array</code> : 배열 (⭐ 같은 변수 만들기)</p>
<ul>
<li><p><code>indexes</code> 와 <code>Values</code> 로 구성</p>
</li>
<li><p>index(인덱스)로 접근</p>
<pre><code class="language-swift">let data: [String] = [&quot;eggs&quot;, &quot;milk&quot;, &quot;flour&quot;]</code></pre>
</li>
</ul>
</li>
<li><p><code>Set</code> : 집합 (⭐ 모임)</p>
<ul>
<li><p><code>Array</code> 와 흡사하여 헷갈림 주의</p>
<pre><code class="language-swift">let musics: Set&lt;String&gt; = [&quot;Rock&quot;, &quot;Jazz&quot;, &quot;Classical&quot;]</code></pre>
</li>
<li><p>집합이라는 특성 상 부분집합, 교집합, 합집합 등등이 존재</p>
</li>
<li><p><code>같은 요소들은 제거된다. (중복제거)</code></p>
</li>
<li><p><code>순서가 없다.</code></p>
</li>
</ul>
</li>
<li><p><code>Dictionary</code> : 딕셔너리(사전) (⭐ Key와 Value)</p>
<ul>
<li><p><code>Key</code> 와 <code>Value</code> 로 구성됨 (마치 Json 처럼)</p>
</li>
<li><p>Apple : 사과, Desk : 책상 등등..</p>
<pre><code class="language-swift">var dict = [Key : Value]
var dict = [&quot;XYZ&quot; : &quot;Toronto Pearson&quot;]
dict[&quot;XYZ&quot;] 결과 -&gt; &quot;Toronto Pearson&quot;</code></pre>
</li>
</ul>
</li>
<li><p>실습 코드</p>
</li>
</ul>
<pre><code class="language-swift">import SwiftUI

struct MyCollections: View {

    var foods: [String] = [&quot;eggs&quot;, &quot;bananas&quot;, &quot;beans&quot;]
    var jazzs: Set&lt;String&gt; = [&quot;재즈1&quot;, &quot;재즈2&quot;, &quot;재즈3&quot;, &quot;재즈4&quot;]
    var hiphop: Set&lt;String&gt; = [&quot;힙합1&quot;, &quot;힙합2&quot;, &quot;힙합3&quot;, &quot;재즈4&quot;]
    var koEngDict: [String: String] = [&quot;사과&quot; : &quot;Apple&quot;, &quot;바나나&quot;: &quot;Banana&quot;]

    var body: some View {
        // Array 예제
        Text(foods[0])
        Text(foods[1])
        Text(foods[2])

        // Set 예제 (hiphop과 jazzs의 합집합(intersection) 출력(description))
        Text(hiphop.intersection(jazzs).description)

        // Dict 예제
        // &quot;!&quot;는 &quot;옵셔널&quot;의 의미를 가지고 있으며 추후 학습 예정
        Text(koEngDict[&quot;사과&quot;]!)
        Text(koEngDict[&quot;바나나&quot;]!)

        Button {
            var intersectionMusic = hiphop.intersection(jazzs)
        } label: {
            Text(&quot;클릭&quot;)
        }

    }
}
</code></pre>
<h2 id="4-조건문">4. 조건문</h2>
<pre><code class="language-swift">if {참 or 거짓} {
    // 실행될 코드
} else {
    // 실행될 코드
}

// else if
let score = 75

if score &gt;= 90 {
    print(&quot;A 학점&quot;)
} else if score &gt;= 80 {
    print(&quot;B 학점&quot;)
} else if score &gt;= 70 {
    print(&quot;C 학점&quot;)
} else {
    print(&quot;F 학점&quot;)
}

// 예제 (다중조건문)
let age = 20
let isStudent = true

if age &gt;= 18 &amp;&amp; isStudent {
    print(&quot;성인 학생입니다.&quot;)
}

if age &lt; 18 || isStudent {
    print(&quot;학생이거나 미성년자입니다.&quot;)
}

// 삼항연산자
let score = 90
let result = score &gt;= 80 ? &quot;합격&quot; : &quot;불합격&quot;
print(result) // 합격</code></pre>
<ul>
<li>전반적으로 다른 언어들과 사용 방법이 같음.</li>
<li>하지만, Swift는 <code>guard</code> 라는 요소가 존재함.</li>
</ul>
<pre><code class="language-swift">guard 조건 else {
    // 조건이 false일 때 실행 (조기 탈출)
    exit(0) // 함수 종료, 에러 처리 등
}

// guard문은 반드시 else 문이 포함되어있어야 동작한다.</code></pre>
<h3 id="41-조건문-guard">4.1 조건문 <code>Guard</code></h3>
<ul>
<li><p><code>guard</code> 는 <code>swift</code> 의 <code>조기 탈출(Early exit)</code> 를 위해 사용되는 조건문.</p>
<ul>
<li><p>⭐ 특정 조건이 <code>거짓(false)</code> 일때 코드 블록을 탈출하거나 오류를 처리하는 사용한다.</p>
<p>  → <code>if문</code> 은 <code>true</code> 가 전재 조건이라면 <code>guard문</code> 은 <code>false</code> 가 전재조건!</p>
</li>
</ul>
</li>
<li><p>사용 예제</p>
<pre><code class="language-swift">  func checkAge(_ age: Int) {
      guard age &gt;= 18 else {
          print(&quot;미성년자는 입장할 수 없습니다.&quot;)
          return
      }
      print(&quot;입장 가능합니다.&quot;)
  }

  checkAge(20)  // 입장 가능합니다.
  checkAge(16)  // 미성년자는 입장할 수 없습니다.</code></pre>
</li>
</ul>
<h3 id="42-if문과-guard문의-차이점">4.2 if문과 guard문의 차이점</h3>
<ul>
<li><p>if문 사용 예제</p>
<pre><code class="language-swift">  func checkUser(name: String?) {
      if let validName = name {
          print(&quot;이름은 \(validName)입니다.&quot;)
      } else {
          print(&quot;이름이 없습니다.&quot;)
      }
  }
  checkUser(name: &quot;John&quot;)
  checkUser(name: nil)</code></pre>
</li>
<li><p>guard문 사용 예제</p>
<pre><code class="language-swift">  func checkUser(name: String?) {
      guard let validName = name else { // else문 필수
          print(&quot;이름이 없습니다.&quot;)
          return // 조기 탈출 필수
      }
      print(&quot;이름은 \(validName)입니다.&quot;)
  }
  checkUser(name: &quot;John&quot;)
  checkUser(name: nil)</code></pre>
</li>
<li><p>🤔 왜 <code>guard</code> 문을 사용하는가?</p>
<ol>
<li>중첩 방지 : guard는 if문보다 코드의 중첩을 줄이고 가독성을 개선한다.</li>
<li>조기 탈출 : 조건이 충족되지 않을 경우 코드의 실행을 즉시 중단할 수 있다.</li>
<li>옵셔널 바인딩 유용 : <code>guard let</code> 을 사용하여 옵셔널을 해제 후 코드에서 안전하게 사용할 수 있다.</li>
</ol>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[pod install] `find_spec_for_exe': can't find gem cocoapods (>= 0.a) with executable pod (Gem::GemNotFoundException)]]></title>
            <link>https://velog.io/@dxxh_e/pod-install-findspecforexe-cant-find-gem-cocoapods-0.a-with-executable-pod-GemGemNotFoundException</link>
            <guid>https://velog.io/@dxxh_e/pod-install-findspecforexe-cant-find-gem-cocoapods-0.a-with-executable-pod-GemGemNotFoundException</guid>
            <pubDate>Thu, 09 Jan 2025 07:02:39 GMT</pubDate>
            <description><![CDATA[<h2 id="pod-install-오류">pod install 오류</h2>
<p>어느날 pod install 명령어를 수행했지만 아래와 같은 오류가 뿜어졌다.</p>
<pre><code>/Users/{name}/.rbenv/versions/3.1.2/lib/ruby/3.1.0/rubygems.rb:265:in `find_spec_for_exe&#39;: can&#39;t find gem cocoapods (&gt;= 0.a) with executable pod (Gem::GemNotFoundException)
        from /Users/{name}/.rbenv/versions/3.1.2/lib/ruby/3.1.0/rubygems.rb:284:in `activate_bin_path&#39;
        from /usr/local/bin/pod:25:in `&lt;main&gt;&#39;</code></pre><p>이 오류는 <strong>cocoapods</strong>가 시스템에 설치되지 않았거나 현재 사용 중인 Ruby 버전에서 cocoapods gem을 찾을 수 없을 때 발생하는 오류라고 한다.
그렇다면 원인은 셋 중 하나라고 생각이 들었다.</p>
<pre><code>1.    Gem 미설치: cocoapods가 해당 Ruby 버전에 설치되지 않았을 때
2.    rbenv 버전 문제: rbenv로 관리 중인 Ruby 버전과 cocoapods 설치 버전 불일치.
3.    Path 설정 오류: gem 경로가 제대로 설정되지 않았음.</code></pre><p>그렇다면 일단 <code>gem install cocoapods</code> 를 실행하여 pod 버전을 확인하려고 하였다.</p>
<h3 id="gem-install-cocoapods-수행-시">gem install cocoapods 수행 시...</h3>
<p><del><em><strong>엥</strong></em></del></p>
<pre><code>Fetching xcodeproj-1.27.0.gem
Fetching benchmark-0.4.0.gem
Fetching securerandom-0.3.2.gem
Fetching cocoapods-core-1.16.2.gem
Fetching activesupport-7.2.2.gem
Fetching cocoapods-1.16.2.gem
ERROR:  While executing gem ... (Errno::ENOENT)
    No such file or directory @ dir_s_mkdir - </code></pre><p>혹시 몰라 권한 문제인가 <code>sudo</code>를 포함하여 다시 실행시켜보았다.</p>
<pre><code>Fetching benchmark-0.4.0.gem
Fetching cocoapods-1.16.2.gem
Fetching xcodeproj-1.27.0.gem
Fetching activesupport-7.2.2.gem
Fetching cocoapods-core-1.16.2.gem
Successfully installed xcodeproj-1.27.0
Successfully installed benchmark-0.4.0
ERROR:  Error installing cocoapods:
        The last version of drb (&gt;= 0) to support your Ruby &amp; RubyGems was 2.0.6. Try installing it with `gem install drb -v 2.0.6` and then running the current command again
        drb requires Ruby version &gt;= 2.7.0. The current ruby version is 2.6.10.210.</code></pre><p><img src="https://velog.velcdn.com/images/dxxh_e/post/cf3b7039-24ba-466a-9af0-8a8fa4032043/image.jpeg" alt=""></p>
<p>맨 마지막에 출력된 문장을 주목하자.</p>
<pre><code>The last version of drb (&gt;= 0) to support your Ruby &amp; RubyGems was 2.0.6. Try installing it with `gem install drb -v 2.0.6` and then running the current command again
        drb requires Ruby version &gt;= 2.7.0. The current ruby version is 2.6.10.210.</code></pre><p>보아하니, <code>drb</code> 버전과 현재 사용중인 <code>Ruby</code> 버전이 호환되지 않아 발생한 문제인 것 같다.
<code>drb</code>는 <code>Ruby 2.7.0</code> 부터 지원하지만 현재 내가 사용중인 버전은 <code>2.6.10</code>이어서 발생한 문제인 것 같다. 따라서 <code>Ruby</code> 버전을 업그레이드하는 작업을 수행하였다!</p>
<pre><code>rbenv install 3.1.2
rbenv global 3.1.2 # 글로벌로 설정
rbenv rehash # 환경 새로고침
ruby -v

# cocoapods 재설치
sudo gem install cocoapods</code></pre><p><strong>성공🎉</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[머신러닝의 정의와 원리]]></title>
            <link>https://velog.io/@dxxh_e/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@dxxh_e/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EC%9D%98-%EC%A0%95%EC%9D%98%EC%99%80-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Tue, 07 Jan 2025 11:51:48 GMT</pubDate>
            <description><![CDATA[<h1 id="머신러닝machine-learning-ml이란">머신러닝(Machine Learning, ML)이란?</h1>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/00be8212-cc86-49d5-ae75-8cf511dce921/image.png" alt=""></p>
<p>이미지 출처 :  <a href="https://hyeonjiwon.github.io/machine%learning/ML-1/">https://hyeonjiwon.github.io/machine%learning/ML-1/</a></p>
<ul>
<li><code>인공지능(AI)</code>의 하위 분야</li>
<li>컴퓨터가 명시적으로 프로그램되지 않고도 데이터를 통해 학습하고 경험을 통해 성능을 개선하는 기술</li>
<li>데이터에서 패턴과 구조를 분석하여 예측하거나 결정을 내릴 수 있는 모델을 개발하는 데 중점을 둠.</li>
</ul>
<hr>
<h3 id="머신러닝의-정의">머신러닝의 정의</h3>
<ul>
<li>머신러닝은 1950년대 AI의 선구자 <code>아서 사무엘</code> 이 “명시적으로 프로그래밍하지 않고도 컴퓨터가 학습할 수 있도록 하는 연구 분야”로 정의함.</li>
</ul>
<blockquote>
<p>전통적인 프로그래밍에서는 사람이 규칙과 논리를 명확히 정의해야 하지만, 머신러닝은 데이터를 기반으로 컴퓨터가 스스로 규칙을 학습함.</p>
</blockquote>
<h3 id="머신러닝의-원리">머신러닝의 원리</h3>
<ol>
<li>데이터 준비<ol>
<li>머신러닝의 핵심은 <code>데이터</code>이다. <code>데이터</code> 는 학습 알고리즘에 입력되며 그 품질과 양은 모델 성능에 큰 영향을 끼친다.</li>
<li>데이터 전처리 과정에서는 결측값 처리, 이상치 제거, 정규화 등의 작업이 이루어진다.</li>
</ol>
</li>
<li>모델 선택 및 학습<ol>
<li>적합한 알고리즘이나 모델을 선택하는 단계. 문제 유형에 따라 <code>선형 회귀</code>, <code>의사 결정 트리</code>, <code>신경망</code> 등 다양한 모델이 사용된다.</li>
<li>학습 과정에서는 데이터를 활용하여 모델의 <code>매개변수(파라미터)</code> 를 조정하며, <code>손실 함수(Loss Function)</code> 를 최소화하는 방향으로 최적화한다. 이를 위하여 경사 하강법과 같은 최적화 기법이 사용된다.</li>
</ol>
</li>
<li>평가 및 튜닝<ol>
<li>학습된 모델은 테스트 데이터를 통해 성능을 평가받는다. 이 과정에서 <code>과적합</code>이나 <code>과소적합</code>을 방지하기 위해 <code>하이퍼파라미터 튜닝</code> 이 이루어진다.</li>
<li>대표적인 평가 지표로는 정확도(Accuracy), 정밀도(Precision), 재현율(Recall) 등이 사용된다.</li>
</ol>
</li>
</ol>
<h3 id="머신러닝의-유형">머신러닝의 유형</h3>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/de650a26-22ee-471b-9b66-64fd6fa3c5b9/image.png" alt=""></p>
<p>이미지 출처 : <a href="https://jeongminhee99.tistory.com/68">https://jeongminhee99.tistory.com/68</a></p>
<ul>
<li><p><strong>지도 학습(Supervised Learning)</strong>
  : 입력 데이터와 해당 출력(레이블)이 제공되는 경우</p>
<ul>
<li>예시 - 이메일 스팸 분류, 주택 가격 예측
: 지도 학습은 학습 결과를 바탕으로 미래의 무엇을 예측하냐에 따라 <code>분류</code>, <code>회귀</code>, <code>예측</code> 으로 구분할 수 있다.</li>
</ul>
<ol>
<li><p><code>분류(Classification)</code> 
 : 데이터가 범주형 변수를 예측하기 위해 사용될 때 지도학습을 <code>분류</code> 라고 한다. 이미지에 강아지나 고양이와 같은 레이블을 할당하는 경우가 해당된다. 레이블이 두 개인 경우는 <code>이진 분류</code>, 범주가 두 개 이상인 경우는 <code>다중 클래스 분류</code> 라고 부른다.</p>
</li>
<li><p><code>회귀(Regression)</code>
 : 연속 값을 예측할 때 문제는 회귀 문제가 된다. 트레이닝 데이터를 이용하여 연속적인 값을 예측하는 것을 말한다.</p>
</li>
<li><p><code>예측(Forecasting)</code>
 : 과거 및 현재 데이터를 기반으로 미래를 예측하는 과정이다. 예측은 동향(trends)을 분석하기 위해 가장 많이 사용된다. 예로 들면 올해와 전년도 매출을 기반으로 내년의 매출을 추산하는 과정을 말한다.</p>
</li>
</ol>
</li>
<li><p><strong>비지도 학습(Unsupervised Learning)</strong>
  : 레이블 없이 데이터의 패턴이나 구조를 찾는 경우</p>
<ul>
<li><p>예시 - 고객 군집화, 차원 축소
: 비지도 학습은 수행할 때 미분류 데이터만을 제공받는다. 모델은 <code>클러스터링 구조</code>, <code>저차원 다양체</code>, <code>희소 트리 및 그래프</code> 등과 같은 데이터의 기저를 이루는 고유 패턴을 발견하도록 설정된다.</p>
</li>
<li><p><code>클러스터링(Clustering)</code>
  : 특정 기준에 따라 유사한 데이터 사례들을 하나의 세트로 <code>그룹화</code> 한다. 이 과정은 종종 전체 데이터 세트를 여러 그룹으로 분류하기 위해 사용된다. 사용자는 고유한 패턴을 찾기 위해 개별 그룹 차원에서 분석을 수행할 수 있다.</p>
</li>
<li><p><code>차원 축소(Dimension Reduction)</code>
  : 고려 중인 변수의 개수를 줄이는 작업이다. 많은 애플리케이션에서 원시 데이터(raw data)는 아주 높은 차원의 특징을 지닌다. 이때 일부 특징들은 중복되거나 작업과 아무런 상관이 없다. 따라서 차원수를 줄이면 관계를 도출하기 용이하다.</p>
</li>
</ul>
</li>
<li><p><strong>강화 학습(Reinforcement Learning)</strong>
  : 환경과 상호작용하며 보상을 최대화하는 행동을 학습</p>
<ul>
<li><p>예시 - 게임 AI, 로봇 제어</p>
<p>: 강화 학습은 환경으로부터의 피드백을 기반으로 <code>행위자(agent)</code>의 행동을 분석하고 최적화한다. 모델은 어떤 액션을 취해야 할지 듣기보다는 최고의 보상을 산출하는 액션을 발견하기 위해 다양한 시나리오들을 시도한다. 대표적인 <code>시행 착오(trial-and-error)</code> 와 <code>지연 보상(delayed reward)</code> 는 다른 기법과 구별되는 <code>강화 학습(RL)</code> 만의 특징이다.</p>
</li>
</ul>
</li>
<li><p><strong>준지도 학습(Semi-Supervised Learning)</strong>
  : 일부 데이터만 레이블이 제공된 경우를 처리하는 방식</p>
</li>
</ul>
<hr>
<h3 id="머신러닝과-딥러닝의-차이는">머신러닝과 딥러닝의 차이는?</h3>
<ul>
<li><code>머신러닝(Machine Learning, ML)</code>은 인공지능의 한 분야로 컴퓨터가 학습할 수 있도록 하는 알고리즘과 기술을 개발하는 분야를 말한다.</li>
<li><code>딥 러닝(Deep Learning, DL)</code> 은 심층 학습으로도 불리우며 여러 비선형 변환 기법의 조합을 통하여 높은 수준의 추상화를 시도하는 기계 학습 알고리즘의 집합으로 정의된다. 큰 틀에서 사람의 사고방식을 컴퓨터에게 가르치는 기계학습의 한 분야라고 이야기할 수 있다. 딥 러닝은 특징 추출부터 패턴까지 모든 과정을 <code>사람의 개입 없이 심층인공신경망</code> 을 토대로 학습 방식을 구현하는 기술이다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/edf62377-0289-4586-b552-01f8955eceaa/image.png" alt=""></p>
<p>위 사진이 설명하는 바는 아래와 같다.</p>
<ul>
<li>머신 러닝은 인간이 데이터에 대한 결과 값을 미리 알려주어야 하고 목표치에 가까운 결과 값의 특징을 미리 정의해야 한다.</li>
<li>딥러닝은 인간의 신경망인 뉴런의 작동 원리를 모방한 인공 신경망을 이용하여 방대한 데이터로부터 결과값을 추출하는 원리로 작동한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[테스트란 뭘까?]]></title>
            <link>https://velog.io/@dxxh_e/%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%9E%80-%EB%AD%98%EA%B9%8C</link>
            <guid>https://velog.io/@dxxh_e/%ED%85%8C%EC%8A%A4%ED%8A%B8%EB%9E%80-%EB%AD%98%EA%B9%8C</guid>
            <pubDate>Tue, 20 Aug 2024 06:52:54 GMT</pubDate>
            <description><![CDATA[<h2 id="💻-개요">💻 개요</h2>
<blockquote>
<p><code>테스트(Test)</code> 는 소프트웨어 개발 과정에서 작성된 코드가 예상대로 작동하는지 확인하는 과정을 말한다.
이는 <strong><em>코드의 기능적 요구사항이 충족되고, 버그가 없는지 확인하기 위해 수행된다.</em></strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/f31a8c63-1075-4579-9538-555f98239d9d/image.png" alt=""></p>
<hr>
<h3 id="🤔-테스트를-왜-하는걸까">🤔 테스트를 왜 하는걸까?</h3>
<p>소프트웨어 테스팅 분야는 매우 넓다. 대표적으로 아래와 같은 이유로 테스팅을 진행한다.</p>
<ol>
<li><code>버그 예방 및 발견</code> <ul>
<li>코드를 작성하면서 발생할 수 있는 <code>다양한 버그</code>를 예방한다.</li>
<li>기존 코드 수정 시 발생할 수 있는 <code>새로운 버그</code>를 발견하여 대처한다.</li>
</ul>
</li>
<li><code>코드 품질 향상</code> <ul>
<li>테스트는 코드의 <code>품질을 높이며</code>, <code>유지보수성</code>을 개선한다.</li>
</ul>
</li>
<li><code>안정성 제공</code><ul>
<li>테스트를 통해 <code>코드의 변경이 예상치 못한 문제를 일으키지 않도록 한다.</code></li>
</ul>
</li>
<li><code>자동화</code><ul>
<li>반복적인 <code>테스트 과정</code> 을 <code>자동화</code>하여 개발자의 시간을 절약한다.</li>
</ul>
</li>
</ol>
<hr>
<h3 id="🤔-장단점은-없을까">🤔 장단점은 없을까?</h3>
<ul>
<li><p>👍 소프트웨어 테스팅의 <code>장점</code></p>
<p>  1) <code>안정성</code> : 코드 변경 시 문제를 빠르게 발견할 수 있어 <code>사용자들에게 안정적인 소프트웨어 제공이 가능하다.</code></p>
<p>  2) <code>디버깅 용이</code> : 버그 발생 시 <code>문제의 원인을 빠르게 파악할 수 있다.</code></p>
<p>  3) <code>문서화</code> : 테스트는 코드의 <code>사용 방법과 동작 방식</code> 을 <code>문서화</code> 시켜주는 역할을 한다.</p>
<p>  4) <code>자동화</code> : <code>CI/CD</code> 파이프라인에 통합하여 배포 전 <code>자동으로 테스트를 수행할 수 있다.</code></p>
</li>
<li><p>👎 소프트웨어 테스팅의 <code>단점</code></p>
<p>  1) <code>시간 소요</code> : 초기 테스트 작성엔 <code>많은 시간이 소요될 수 있다.</code></p>
<p>  2) <code>유지보수의 증가</code> : 코드가 변경되면 <code>테스트 코드도 함께 수정해야 할 경우가 많다.</code></p>
<p>  3) <code>복잡성 증가</code> : 복잡한 <code>테스트 환경 설정</code> 이 필요할 수 있다.</p>
</li>
</ul>
<hr>
<h2 id="🤔-소프트웨어-테스팅에-대한-개인적인-궁금증">🤔 소프트웨어 테스팅에 대한 개인적인 궁금증</h2>
<h3 id="😲-1-소프트웨어-테스트는-풀스택일까-명확한-기술적-선이-있을까">😲 1. 소프트웨어 테스트는 풀스택일까? 명확한 기술적 선이 있을까?</h3>
<blockquote>
<p><code>소프트웨어</code> 즉, <code>프로그래밍</code> 에서 <code>테스트</code> 는 특정한 분야(프론트엔드, 백엔드)에 국한되지 않고 <code>풀스택</code> 개발의 중요한 부분이다. 따라서 소프트웨어 테스트는 개발 분야 모든 곳에서 활용된다. 또한 명확한 선을 긋기가 어렵다. 
<strong><em>각각의 분야에서 다루는 테스트의 종류와 방법이 다를 수 있지만, 전반적인 원칙과 목적은 유사하다.</em></strong></p>
</blockquote>
<p>그렇다면 대표적인 <code>프론트엔드</code> , <code>백엔드</code> , <code>풀스택</code> 에 따른 테스트 방법이 뭘까?</p>
<hr>
<h3 id="💡1-1-프론트엔드-테스트-방법">💡1-1. 프론트엔드 테스트 방법</h3>
<ul>
<li><code>유닛 테스트</code> : <code>컴포넌트</code>나 <code>함수</code> 단위의 테스트를 말한다. 예를 들어 <code>React 컴포넌트</code> 가 예상대로 렌더링되는 지 확인하는 것을 말한다.</li>
<li><code>통합 테스트</code> : <code>여러</code> 컴포넌트나 모듈이 함께 작동하는지 테스트하는 것을 말한다.</li>
<li><code>엔드 투 엔드(E2E) 테스트</code> : 전체 애플리케이션의 <code>흐름</code> 을 <code>실제 사용자 관점</code> 에서 테스트하는 것을 말한다. 이는 브라우저에서 실제로 동작되는 것을 확인한다.</li>
</ul>
<hr>
<h3 id="💡1-2-백엔드-테스트-방법">💡1-2. 백엔드 테스트 방법</h3>
<ul>
<li><code>유닛 테스트</code> : 특정 함수나 메서드의 로직이 정상적으로 작동하는지 확인하는 방법을 말한다.</li>
<li><code>통합 테스트</code> : 여러 모듈이나 서비스가 <code>함께 정상적으로</code> 동작하는지 테스트하는 방법을 말한다. 예를 들어 <code>애플리케이션</code>이 <code>데이터베이스</code>와의 상호작용이 정상적으로 동작하는지 확인하는 것을 말한다.</li>
<li><code>API 테스트</code> : <code>RESTful API</code> , <code>GraphQL API</code> 의 엔드포인트가 예상대로 동작하는지 확인하는 방법을 말한다. 이는 <code>Insomnia</code> , <code>Postman</code> 같은 도구를 사용하여 테스트할 수 있다.</li>
</ul>
<hr>
<h3 id="💡1-3-풀스택-테스트-방법">💡1-3. 풀스택 테스트 방법</h3>
<p>→ 풀스택 개발자는 <code>프론트엔드</code>와 <code>백엔드</code> 양쪽의 테스트를 모두 관리해야하므로 특정 테스트 기법이 존재하지 않는다.</p>
<p>→ 프론트엔드와 백엔드를 통합하여 <code>전체 애플리케이션의 흐름을 테스트</code> 하는 <code>E2E</code> 테스트를 주로 수행한다.</p>
<hr>
<h3 id="💡1-4-결론">💡1-4. 결론</h3>
<p>소프트웨어 개발 즉, 프로그래밍에서 테스트는 프론트엔드와 백엔드, 풀스택 개발 등 모든 분야에서 중요한 역할을 하며 명확히 구분되지 않는다. 각 분야의 특성이 맞는 테스트의 기법이 존재하지만 <code>전반적인 테스트 원칙과 목적은 유사하다는 점이 있다.</code> 궁극적으로는 <code>사용자의 경험을 개선하고 버그를 줄이기 위해 테스트를 진행한다.</code></p>
<hr>
<h3 id="😲-2-소프트웨어-테스트를-반드시-해야할까">😲 2. 소프트웨어 테스트를 반드시 해야할까?</h3>
<blockquote>
<p><code>테스트를 반드시 수행해야하는 걸까?</code> , <code>만일 작은 프로젝트를 진행하게 된다면 테스트를 꼭 해야하는 걸까?</code>
<em>위와 같은 의문이 떠올라 이에 관련된 정보를 찾아보았다.</em></p>
</blockquote>
<blockquote>
<p>💡 ChatGPT
테스트가 중요한 이유는 사용자 경험을 최적화하고, 버그를 사전에 방지하며, 코드의 품질을 높이는 데 있습니다. 하지만 모든 프로젝트에서 테스트를 반드시 해야 하는 것은 아닙니다. 특히 <code>작은 프로젝트</code>의 경우, 테스트의 필요성과 <code>범위</code>를 신중히 고려할 필요가 있습니다.</p>
</blockquote>
<h3 id="💡2-1-테스트를-왜-해야할까">💡2-1. 테스트를 왜 해야할까?</h3>
<ol>
<li><p><code>안정성</code></p>
<p> → 테스트는 코드의 안정성을 보장한다. 이를 통해 예상치 못한 버그나 오류를 사전에 발견할 수 있다.</p>
</li>
<li><p><code>유지보수성</code></p>
<p> → 코드가 변경될 때마다 기존 기능이 제대로 작동하는지 확인할 수 있다. 특히 장기적으로 유지보수가 필요한 프로젝트에서 중요하게 작용한다.</p>
</li>
<li><p><code>사용자 경험</code></p>
<p> → 테스트를 통해 사용자에게 일관된 경험을 제공할 수 있다. 이는 중요한 기능이 언제나 개발자의 의도대로 작동할 것을 보장한다.</p>
</li>
</ol>
<h3 id="💡-2-2-그렇다면-작은-프로젝트-에서는">💡 2-2. 그렇다면 <code>작은 프로젝트</code> 에서는?</h3>
<p>상대적으로 작은 사이드 프로젝트 혹은 공부용 토이 프로젝트같은 경우는 <code>비용과 시간</code> 적인 이유로 테스트의 범위를 신중하게 고려할 필요가 있다.</p>
<ol>
<li><p><code>비용과 시간의 문제</code></p>
<p> → 테스트를 진행하기 위해 코드를 작성하고 유지하는 것은 많은 시간을 필요로 한다. 작은 프로젝트나 짧은 기간의 프로젝트에서는 모든 로직을 테스트하기보다는, <strong><code>주요 기능이나 핵심 로직에 대한 테스트를 진행하는 것이 효율적일 수 있다.</code></strong></p>
</li>
<li><p><code>우선 순위 선정과 피드백</code></p>
<p> → 작은 프로젝트에서는 <code>테스트</code> 를 하는 것 보단 코드 변경 후 <code>직접 확인하는 방식</code> 이 더 빠르게 피드백을 받을 수 있어 효율적일 수 있다. 모든 기능을 테스트하는 것 보단 프로젝트의 목표와 사용자 기대치를 기반으로 우선순위를 정하여 <code>중요한 부분에 집중하는 것이 시간과 자원을 효율적으로 사용할 수 있다.</code></p>
</li>
</ol>
<hr>
<h2 id="😀-결론">😀 결론!</h2>
<p>테스트는 프로젝트의 <code>안정성과 유지보수성</code>을 높여주지만, 작은 사이드 프로젝트에서는 모든 것을 테스트하는 것이 비효율적일 수 있다. 중요한 것은 <code>프로젝트의 규모와 복잡성</code> 에 맞춰 테스트의 범위를 정하고, 비용과 시간을 감안한 접근을 진행하는 것이 좋다고 생각한다. <strong><code>반드시 프로젝트를 테스트할 필요는 없다고 생각하지만, 테스트의 결과로 사용자 경험에 매우 중대한 영향을 미칠 수 있는 부분은 진행하는 것이 좋다고 생각한다!</code></strong></p>
<p><strong>끝!</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🤔 NestJS 모듈화의 이점은 뭘까?]]></title>
            <link>https://velog.io/@dxxh_e/NestJS-%EB%AA%A8%EB%93%88%ED%99%94%EC%9D%98-%EC%9D%B4%EC%A0%90%EC%9D%80-%EB%AD%98%EA%B9%8C</link>
            <guid>https://velog.io/@dxxh_e/NestJS-%EB%AA%A8%EB%93%88%ED%99%94%EC%9D%98-%EC%9D%B4%EC%A0%90%EC%9D%80-%EB%AD%98%EA%B9%8C</guid>
            <pubDate>Sun, 18 Aug 2024 08:30:39 GMT</pubDate>
            <description><![CDATA[<h2 id="🤔-개요">🤔 개요</h2>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/18f0e5a2-0198-41ac-aade-3d045721c010/image.png" alt=""></p>
<p><code>NestJS</code> 를 공부하다가 아래와 같은 코드를 접하였다.</p>
<pre><code class="language-tsx">// app.module.ts
import { Module } from &#39;@nestjs/common&#39;;
import { MoviesModule } from &#39;./movies/movies.module&#39;;
import { AppController } from &#39;./app.controller&#39;;

@Module({
  imports: [MoviesModule],
  controllers: [AppController],
  providers: [],
})
export class AppModule {}</code></pre>
<p>이 코드를 보고 문뜩 어떤 생각이 들었다.</p>
<blockquote>
<p>왜 각각의 모듈을 컴포넌트처럼 분리하는거지?</p>
</blockquote>
<blockquote>
<p>그냥 모두 <code>app.module.ts</code> 에 적용하지 않는 이유가 있을까?</p>
</blockquote>
<blockquote>
<p><code>NestJS</code> 의 모듈화가 프로젝트 관리에 어떤 영향을 미칠까?</p>
</blockquote>
<blockquote>
<p><code>NestJS</code>에서 모듈을 분리함으로써 얻는 이점은??</p>
</blockquote>
<blockquote>
<p>이러한 모듈 구조로 프로젝트를 진행하면 협업에 미치는 영향은 없을까?</p>
</blockquote>
<p>이러한 의문을 해결하기 위해 이 글을 정리하였다!</p>
<hr>
<h2 id="💡nestjs의-모듈-구조를-사용하는-이유이자-장점은">💡NestJS의 모듈 구조를 사용하는 이유이자 장점은?</h2>
<h3 id="⭐-1-모듈화modularity와-캡슐화encapsulation">⭐ 1. 모듈화(Modularity)와 캡슐화(Encapsulation)</h3>
<ul>
<li><code>모듈화(Modularity)</code><ul>
<li><code>NestJS</code>는 애플리케이션을 작은 단위로 나눌 수 있도록 모듈을 지원한다.</li>
<li>각 모듈은 특정 도메인에 대한 기능을 <code>캡슐화</code>하여 독립적으로 관리할 수 있다.</li>
<li><code>코드의 구조를 명확하게 하고 유지보수성을 높이며 다른 개발자와의 협업을 수월하게 한다.</code></li>
</ul>
</li>
<li><code>캡슐화(Encapsulation)</code><ul>
<li>모듈화된 구조는 각 배정받은 모듈을 <strong>자신<em>이 책임지고 집중할 수 있도록 유도한다.</em></strong></li>
<li><code>다른 모듈 간의 의존성을 최소화하여 코드가 변경될 때 영향을 줄일 수 있다.</code></li>
</ul>
</li>
</ul>
<hr>
<h3 id="⭐-2-관심사의-분리separation-of-concerns">⭐ 2. 관심사의 분리(Separation of Concerns)</h3>
<ul>
<li><p><code>NestJS</code> 의 모듈 구조는 애플리케이션을 구성하는 각 부분이 독립적으로 개발될 수 있도록 도와준다.
  → 예시 : <code>AuthModule</code> 은 인증과 관련된 모든 로직을 다루고 <code>RegisterModule</code> 은 로그인 및 회원가입과 관련된 모든 로직을 다룬다.</p>
<ul>
<li>이를 통해 <strong><em><code>다른 모듈에서는 해당 로직을 신경 쓰지 않아도 되며 이는 유지보수와 테스트를 용이하게 만드는 효과가 있다.</code></em></strong></li>
</ul>
</li>
</ul>
<hr>
<h3 id="⭐-3-재사용성reusability🤔-개요">⭐ 3. 재사용성(Reusability)🤔 개요</h3>
<ul>
<li><code>NestJS</code> 의 모듈은 독립적으로 작성되어 다른 애플리케이션이나 프로젝트에서 재사용될 수 있다.
  → 예시 : <code>AuthModule</code> 은 다른 프로젝트에 재사용할 수 있으며, 필요한 경우 <code>모듈을 쉽게 확장하거나 수정할 수 있다.</code></li>
</ul>
<hr>
<h3 id="⭐-4-유연성flexibility">⭐ 4. 유연성(Flexibility)</h3>
<ul>
<li>새로운 기능을 추가해야 할 때, <strong><em>새로운 모듈을 생성하여 기존 모듈과 독립적으로 개발할 수 있다.</em></strong><ul>
<li><code>애플리케이션이 커짐에 따라 구조를 더 유연하게 확장할 수 있다.</code></li>
</ul>
</li>
</ul>
<hr>
<h3 id="⭐-5-테스트-용이성testability">⭐ 5. 테스트 용이성(Testability)</h3>
<ul>
<li>모듈이 독립적이므로 테스트 또한 각 모듈 단위로 수행되기에 훨씬 쉬워진다.
  → <code>이를 통해 각 모듈이 정상적으로 동작하는지 호율적으로 검증할 수 있고, 문제가 발생할 경우 해당 모듈에 집중할 수 있다.</code></li>
</ul>
<hr>
<h3 id="⭐--6-팀-협업-및-스케일링team-collaboration-and-scaling">⭐  6. 팀 협업 및 스케일링(Team Collaboration and Scaling)</h3>
<ul>
<li><code>협업의 용이성</code><ul>
<li>프로젝트 구성원 내에서 각 팀원이 특정 모듈이 집중하여 작업할 수 있어 <code>여러 사람이 동시에 다양한 기능을 개발하는 것이 용이해진다.</code></li>
</ul>
</li>
<li><code>스케일링(Scaling)</code><ul>
<li>프로젝트 규모가 커질 때, 모듈 단위로 작업을 분할함으로써 <code>효율적으로 협력할 수 있게 된다.</code></li>
</ul>
</li>
</ul>
<hr>
<h2 id="🤔-그렇다면-단점은-없을까">🤔 그렇다면 <code>단점</code>은 없을까?</h2>
<p>→ 모듈을 분리하는 것을 유도하는 만큼 아래와 같은 리스크와 단점이 존재한다!</p>
<h3 id="👎-1-프로젝트-복잡성-증가">👎 1. 프로젝트 복잡성 증가</h3>
<ul>
<li><code>NestJS</code> 는 사용 목적 자체가 작은 프로젝트에는 어울리지 않다. 작은 프로젝트에서 모듈을 너무 많이 나누게 된다면 오히려 <code>복잡성이 증가하여 유지보수가 힘들어질 수 있다.</code></li>
<li>필요한 모듈 간의 관계를 <code>잘못 관리하면 의존성 사이클(Dependency cycle)</code> 이 발생할 수 있다!</li>
</ul>
<h3 id="👎-2-초기-설계의-문제">👎 2. 초기 설계의 문제</h3>
<ul>
<li>모듈을 분리하여 각각의 독립체로 운영하기 때문에 프로젝트 초반부터 모듈 구조를 잘못 설계하면 <code>추후 변경하는 데 많은 시간이 소요될 수 있다.</code>
  → <strong><em>따라서 초기 설계 단계에서 모듈을 잘 나누는 것이 중요!</em></strong></li>
</ul>
<hr>
<h2 id="😝-결론">😝 결론!</h2>
<blockquote>
<p>NestJS에서 지원하는 모듈화 구조는 <code>Spring</code> 과 같이 엔터프라이즈급 애플리케이션을 관리하기에 매우 유용한 구조라고 생각한다. 마치 <code>MVC(Model-View-Controller)</code>를  연상시키는 구조를 통해 유지보수성과 재사용성을 높이고, 팀 협업을 원활하게 하며, 유연하게 확장할 수 있는 서비스를 개발할 수 있다는 것은 정말 좋다고 생각한다.
 하지만, 과유불급이라는 말이 있다. 작은 프로젝트에서는 오히려 <code>복잡성</code>을 증가시켜 프로젝트를 원활히 진행하지 못하게 될 수 있어 <code>적절한 모듈화 전략</code>이 꼭 선행되어야 한다고 생각한다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[NestJS] PartialType을 사용하여 DTO 만들기]]></title>
            <link>https://velog.io/@dxxh_e/NestJS-PartialType%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-DTO-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@dxxh_e/NestJS-PartialType%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC-DTO-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 14 Aug 2024 11:41:25 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/dxxh_e/post/9fe4c265-ed51-47a4-bb39-2b67a9875d61/image.png" alt=""></p>
<blockquote>
<p><code>NestJS</code> 에서 <code>PartialType</code> 은 <code>@nestjs/mapped-types</code> 패키지에서 제공하는 유틸리티 함수로, 전달된 DTO 클래스의 모든 속성을 <code>선택적(optional)</code> 으로 만드는 새로운 클래스를 생성한다.
즉, <code>PartialType</code> 은 기존 DTO의 모든 속성을 <code>선택적</code> 변경시켜 <strong>새로운 DTO를 생성하도록 도와준다.</strong></p>
</blockquote>
<p><code>PartialType</code> 을 사용하기 위해선 아래와 같은 라이브러리를 설치해야한다.</p>
<pre><code class="language-jsx">$ npm i --save @nestjs/mapped-types</code></pre>
<hr>
<h2 id="💡-partialtype-사용해보기">💡 <code>PartialType</code> 사용해보기</h2>
<p>만약, 아래와 같이 <code>CreateMoveDTO</code> 가 있다 가정한다. </p>
<pre><code class="language-tsx">// CreateMoveDTO.ts
import { IsString, IsNumber } from &#39;class-validator&#39;;

export class CreateMoiveDTO {
  @IsString()
  title: string;

  @IsNumber()
  year: number;

  @IsString({ each: true })
  genres: string[];
}
</code></pre>
<p>해당 DTO는 <code>title</code>, <code>year</code>, <code>genres</code> 의 필드를 가진다. </p>
<p>종종 DTO를 생성할 때 존재하는 DTO에서 특정 필드를 제거하거나, 모두 <code>선택적(Optional)</code> 화 하거나, 특정 필드만 선택하여 변경하고 싶은 경우가 많이 있다. 이때 사용되는 라이브러리가 <code>@nestjs/mapped-types</code> 의 <code>PartialType</code> 이다.</p>
<p>사용법은 아래와 같이 새롭게 만들고자 하는 DTO를 작성하고 <code>PartialType</code> 를 상속받는다.</p>
<pre><code class="language-tsx">import { PartialType } from &#39;@nestjs/mapped-types&#39;;
import { CreateMoiveDTO } from &#39;./create-movie.dto&#39;;

export class UpdateMovieDTO extends PartialType(CreateMoveDTO) {}</code></pre>
<pre><code class="language-tsx">PartialType(`Optional`화 시키고 싶은 DTO 클래스)</code></pre>
<p>위와 같이 Optional화 시키고자 하는 클래스를 <code>PartialType</code> 에 사용한다.</p>
<p>위 <code>PartialType</code> 으로 생성된 <code>UpdateMovieDTO</code> 는 아래와 동등하다.</p>
<pre><code class="language-tsx">export class UpdateMovieDTO{
    title?: string;
    year?: number;
    genres?: string[];
}</code></pre>
<p>위 DTO는 아래와 같은 동작 방식을 가진다.</p>
<ol>
<li><strong>데이터 생성 요청(Create): 모든 필드(<code>title</code>, <code>year</code>, <code>genres</code> ) 필수로 요청 데이터에 포함되어야 한다.</strong></li>
<li><strong>데이터 업데이트 요청(Update)</strong> : 요청 데이터엔 일부 필드만 포함될 수 있으며 특정 필드만 업데이트할 수 있다. (ex <code>year</code> 필드만 업데이트하려면 <code>{ &quot;year&quot;: 2024 }</code> 와 같이 보낼 수 있다.</li>
</ol>
<hr>
<h2 id="👍-partialtype의-장점">👍 <code>PartialType</code>의 장점!</h2>
<ol>
<li><strong>코드 재사용성의 증가로 중복된 코드가 작성될 우려 없이 쉽게 DTO를 정의할 수 있다!</strong></li>
<li><strong>특정 필드를 선택적으로 변경할 수 있어 클라이언트가 특정 데이터를 업데이트할 시 필요한 필드만 제공할 수 있다!</strong></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[NestJS의 ValidationPipe 대표 옵션 정리]]></title>
            <link>https://velog.io/@dxxh_e/NestJS%EC%9D%98-ValidationPipe-%EB%8C%80%ED%91%9C-%EC%98%B5%EC%85%98-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@dxxh_e/NestJS%EC%9D%98-ValidationPipe-%EB%8C%80%ED%91%9C-%EC%98%B5%EC%85%98-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 14 Aug 2024 05:55:32 GMT</pubDate>
            <description><![CDATA[<hr>
<blockquote>
<p>NestJS에서 <code>ValidationPipe</code> 는 요청 데이터를 유효성 검사하며 필요에 따라 데이터를 변환하는 데 사용되는 <code>파이프(Pipe)</code> 이다. 이는 <code>main.ts</code> 에서 글로벌로 설정할 수 있으며 다양한 옵션을 활성화하여 파이프 동작을 커스터마이징 할 수 있다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/a1bd3849-51ec-4058-acaa-23862278b304/image.png" alt=""></p>
<hr>
<h2 id="💡--validationpipe-의-주요-옵션">💡  <code>ValidationPipe</code> 의 주요 옵션</h2>
<h3 id="🎈-1-whitelist">🎈 1. <code>whitelist</code></h3>
<ul>
<li>DTO에 <strong>정의되어 있지 않은 속성들이 요청 데이터에 포함되어 있으면 이를 자동으로 제거</strong>한다.
  → 클라이언트가 의도치 않게 추가 데이터를 전송하더라도, 서버는 필요한 데이터만 받게 된다.</li>
</ul>
<pre><code class="language-tsx">new ValidationPipe({ whitelist: true })</code></pre>
<hr>
<h3 id="🎈-2-forbidnonwhitelisted">🎈 2. <code>forbidNonWhitelisted</code></h3>
<ul>
<li><code>whitelist</code> 옵션과 함께 사용하는 옵션이다.</li>
<li>DTO에 정의되지 않은 속성이 요청 데이터에 포함되어 있으면 <strong>에러를 발생시킨다.</strong>
  → <strong>허용되지 않은 속성이 포함된 요청을 서버가 거부하게 된다.</strong></li>
</ul>
<pre><code class="language-tsx">new ValidationPipe({
    whitelist: true,
    forbidNonWhitelisted: true,
})</code></pre>
<hr>
<h3 id="🎈-3-transform">🎈 3. <code>transform</code></h3>
<ul>
<li><p>요청 데이터를 <strong>자동으로 변환하여 컨트롤러에서 정의된 타입에 맞게 전달된다.</strong>
  → ex) <strong><em>HTTP 요청 Body에 포함된 숫자가 문자열로 요청되었을 경우 이를 숫자 타입으로 변환한다.</em></strong></p>
<pre><code class="language-tsx">  new ValidationPipe({ transform: true })</code></pre>
</li>
</ul>
<hr>
<h3 id="🎈-4-transformoptions">🎈 4. <code>transformOptions</code></h3>
<ul>
<li><code>transform</code> 옵션과 함께 사용하는 옵션이다.</li>
<li><code>transform</code> 옵션을 더욱 세밀하게 조정할 수 있으며 <code>class-transformer</code> 라이브러리의 옵션을 사용할 수 있다.</li>
</ul>
<pre><code class="language-tsx">new ValidationPipe({
    transform: true,
    transformOptions: { enbleImplicitConversion: true },
})</code></pre>
<hr>
<h3 id="🎈-5-disableerrormessages">🎈 5. <code>disableErrorMessages</code></h3>
<ul>
<li><p>유효성 검사 실패 시 에러 메시지를 <strong>비활성화</strong> 시킨다.</p>
<p>  → 프로덕션 환경에서 보안을 위해 상<strong>세한 에러 메시지를 숨길 때 유용하다.</strong></p>
</li>
</ul>
<pre><code class="language-tsx">new ValidationPipe({ disableErrorMessages: true })</code></pre>
<hr>
<h3 id="🎈-6-exceptionfactory">🎈 6. <code>exceptionFactory</code></h3>
<ul>
<li><p>유효성 검사 실패 시 <strong>커스텀 예외를</strong> 생성할 수 있다</p>
<p>  → 기본 예외 대신 사용자 정의 예외를 발생시키고자 할 때 사용한다.</p>
</li>
</ul>
<pre><code class="language-tsx">new ValidationPipe({
    exceptionFactory: (errors) =&gt; new MyCustomException(errors),
})</code></pre>
<hr>
<h2 id="💡--validationpipe-대표-옵션들이-http-요청-시-어떻게-작동할까">💡  <code>ValidationPipe</code> 대표 옵션들이 HTTP 요청 시 어떻게 작동할까?</h2>
<p>우선, 아래와 같은 <code>DTO</code> 를 작성하자. 해당 <code>DTO</code> 는<code>age</code> 필드만을 가지고 있다.</p>
<pre><code class="language-tsx">// CreateUserDTO
export class CreateUserDTO{
    age: number;
}</code></pre>
<p>그 후 <strong>클라이언트는 다음과 같은 JSON 데이터</strong>를 요청한다 가정한다.</p>
<pre><code class="language-json">{
    &quot;name&quot;: &quot;gildong&quot;
}</code></pre>
<h3 id="🎈-1-whitelist-활성화">🎈 1. <code>whitelist</code> 활성화</h3>
<ul>
<li>요청 본문에는 <code>name</code> 필드와 <code>gildong</code> 이 포함되어 있지만 실제 서버 <code>DTO</code> 에는 <code>name</code> 필드가 정의되어 있지 않다. 이에 따라 서버는 정의되어있지 않은 필드가 요청에 포함되었을 경우 제거시키는 <code>whitelist</code> 옵션이 활성화 되어있으므로 <code>{}, 빈 객체</code> 를 받게 된다.</li>
<li>하지만, <strong>에러는 발생하지 않으므로</strong>  <code>forbidNonWhitelisted</code>와 함께 사용하여 응용할 수 있다.</li>
</ul>
<hr>
<h3 id="🎈-2-forbidnonwhitelisted-활성화">🎈 2. <code>forbidNonWhitelisted</code> 활성화</h3>
<ul>
<li>해당 옵션은 위 <code>whitelist</code> 와 함께 사용되는 옵션이다.</li>
<li>위와 같은 상황에서 <code>forbidNonWhitelisted</code> 가  활성화 되어있다면 필드가 제거되는 대신 <strong>예외를 발생시켜 클라이언트에게 잘못된 필드가 포함되었다고 알린다.</strong></li>
<li>따라서 서버는 <code>HTTP 400 (Bad Request)</code> 를 반환하고 에러 메시지는 <code>&#39;name&#39; is not allowed</code> 와 같은 내용이 포함된다.</li>
</ul>
<hr>
<h3 id="🎈-3-transform-활성화">🎈 3. <code>transform</code> 활성화</h3>
<ul>
<li>요청 본문엔 <code>name</code> 필드가 전달되었지만 <code>DTO</code> 에는 <code>age</code> 필드만 존재하기에 <code>transform</code> 옵션만으로는 큰 변화가 존재하지 않는다.</li>
<li>만약, 요청 본문이 아래와 같이 <code>age</code> 필드가 <code>문자열</code>로 전달되었을 경우</li>
</ul>
<pre><code class="language-json">{
    &quot;age&quot;: &quot;24&quot;,
}</code></pre>
<p><code>CreateUserDTO</code> 의 <code>age</code> 는 <code>숫자(number)</code> 타입이므로 자동으로 <code>숫자</code>로 형변환이 이루어진다.</p>
<hr>
<h3 id="🎈-4-disableerrormessages-활성화">🎈 4. <code>disableErrorMessages</code> 활성화</h3>
<ul>
<li><code>disableErrorMessage</code> 는 다른 옵션과 조합할 수 있다.</li>
<li>예를 들어 <code>forbidNonWhitelisted</code> 를 사용하면 <code>&#39;name&#39; is not allowed</code> 와 같이 어떤 필드가 잘못되었는지 알려주지만 <code>disableErrorMessages</code> 를 활성화 시 <code>HTTP 400 (Bad Request)</code> 를 반환하지만 에러 메시지는 숨겨지며 클라이언트에게 상세한 정보를 제공하지 않는다.</li>
</ul>
<hr>
<blockquote>
<p><code>ValidationPipe</code> 에 있는 각 옵션을 통해 요청 데이터의 유효성을 엄격하게 관리하여, 애플리케이션의 보안과 안정성을 손쉽게 높일 수 있다는 점이 또다른 강점이지 않을까싶다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[🔥 Google I/O Extended 2024 Incheon 후기]]></title>
            <link>https://velog.io/@dxxh_e/Google-IO-Extended-2024-Incheon-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@dxxh_e/Google-IO-Extended-2024-Incheon-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Sat, 10 Aug 2024 10:09:51 GMT</pubDate>
            <description><![CDATA[<hr>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/584b2e54-534d-4dc1-af36-597aea0ba375/image.jpeg" alt=""></p>
<h2 id="🧢-서론">🧢 서론</h2>
<p>군대 전역 후 개발에 대한 열정을 되살리고 싶고 현재 개발 분야의 최신 트렌드를 알고 싶어 GDG 송도에서 개최하는 <code>Google I/O Extended</code>와 <code>인프콘 2024</code>를 참여하고자 했다.
<del>하지만 <code>인프콘 2024</code>는 추첨에서 떨어져 가지 못한게 한..ㅠㅠ</del>
<code>Google I/O Extended</code>에 참석하여 정말 다양한 세션을 재미있게 경청하여 좋은 영감을 많이 얻고 온 것 같아 뜻깊었다고 생각한다. 또한 오거나이저분들의 친절한 안내와 준비성, 열정에 정말 감탄을 많이 했다. 연사자분들의 지식 공유로 최신 기술 동향과 학생 개발자로서의 동기 부여를 얻었다고 생각한다.</p>
<p><strong><em>이 글은 GDG 인천에서 얻은 다양한 인사이트들을 남기고싶어 연사분들의 강연 내용을 간략하게 정리하고, 그에 따른 후기를 작성한 글이다.</em></strong></p>
<hr>
<h2 id="📢-세션-정리">📢 세션 정리</h2>
<h3 id="🎈-구글-커뮤니티-구성원들의-io-현장-참가-경험과-글로벌-컨퍼런스-참여-팁">🎈 구글 커뮤니티 구성원들의 I/O 현장 참가 경험과 글로벌 컨퍼런스 참여 팁</h3>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/e138c6db-1520-4860-ac7e-5d9f28b3a2ae/image.jpeg" alt=""></p>
<ul>
<li>연사 : <code>최가인</code>님</li>
<li>위치 : 13:00 ~ 13:50 (113호, 1F) / <code>General</code><blockquote>
<p>📚 해당 강연을 참석한 이유는?
<code>Google I/O</code>에 관심이 많고 다양한 글로벌 컨퍼런스에 참여하고 싶어 그에 따른 정보와 참여 팁 등을 얻고싶어 참석하였다.</p>
</blockquote>
</li>
</ul>
<p>해당 세션은 아래와 같은 주제를 다루셨다.</p>
<ol>
<li><p><code>Google I/O</code>에 대해</p>
<ul>
<li><code>Google I/O</code>란 무엇인가</li>
<li><code>Google I/O</code>의 현장 분위기</li>
<li><code>2024 Google I/O</code>의 주요 메세지는 <code>선다 피차이(Sundar Pichai) CEO</code>가 언급한 <code>AI는 우리 인생에서 정말 큰 기술적 변화를 초래할 것이다.</code> -&gt; 구글이 개발한 인공지능 검색 서비스 <code>Gemini</code>의 시대를 선포한 것으로 생각하였다.</li>
</ul>
</li>
<li><p><code>Google I/O</code> 참여 방법</p>
<ul>
<li><code>Google I/O</code>의 참여 방법 변경 (2024년부터 초대 받은 사람만 참석 가능)</li>
<li><code>Google I/O</code>는 <code>GDE</code>, <code>GDG</code> 뿐만 아니라 누구나 흥미롭게 여겨지는 이벤트.</li>
<li><code>Google I/O</code> 초대권 같은 경우 구글 코리아에서 특정 인원을 추천하여 해당 추천자들에게 참석 의사를 요구. 그 후 레지스터 메일을 통해 등록 절차를 진행.
  -&gt; 생각보다 참석자 한 명 한 명의 불편사항과 선호도를 모두 체크한다고 함.
  -&gt; 등록 절차가 완료되면 개별 초대권 코드 확인 절차를 통해 <code>Google I/O</code> 참여 진행</li>
</ul>
</li>
<li><p><code>DevRel</code>에 대해</p>
<ul>
<li><code>Developer Relations</code> 또는 <code>Developer Advocacy</code>
  -&gt; 특정 제품이나 기술에 대해 개발자에게 알리기 위해 커뮤니티를 만들거나, 콘텐츠를 만들거나, 제품의 개발자 경험을 향상시키는 등 다양한 활동을 진행</li>
<li>최근 굉장히 떠오르는 분야</li>
<li><code>DevRel</code>이 되기 위해선 <code>코딩 능력</code>, <code>커뮤니티 빌딩 능력</code>, <code>콘텐츠 생성 능력</code> 등이 필요함.</li>
</ul>
</li>
<li><p>다양한 국제 컨퍼런스 소개</p>
<ul>
<li><code>GDG</code></li>
<li>아시아 최대 규모 오픈소스 기술 커뮤니티 <code>Fossasia</code></li>
<li><code>HCI</code> 컨퍼런스</li>
<li><code>Google I/O</code>를 다양한 사람들과 현장에서 온라인으로 즐길 수 있는 <code>Watch Party</code></li>
</ul>
</li>
<li><p>다양한 글로벌 컨퍼런스 정보 찾는법</p>
<ul>
<li><code>Google for Developers Program</code>에 프로필을 등록하여 기술 이벤트 메일 받기</li>
<li><code>nomad coder</code>님과 같은 해외 글로벌 컨퍼런스 정보를 가장 빠르게 아는 인플루언서들의 뉴스레터 구독하기</li>
<li>스폰서 받기</li>
</ul>
</li>
<li><p>그 외</p>
<ul>
<li><strong>명함의 중요성</strong>
  -&gt; 자기를 소개할 수 있는 자료 또는 대사(ex Linkedin)</li>
</ul>
</li>
</ol>
<blockquote>
<p>후기 : <code>Google I/O</code>의 현장 경험을 자세히 소개해주셔서 재미있었고 다양한 글로벌 컨퍼런스, 참석 방법 등 유의미한 정보를 얻을 수 있던 것 같다.</p>
</blockquote>
<hr>
<h3 id="🎈-it-행사-에서-내향인이-네트워킹하는-법">🎈 IT 행사+ 에서 내향인이 네트워킹하는 법</h3>
<ul>
<li>연사 : <code>성태이</code>님</li>
<li>위치 : 14:00 ~ 14:50 (113호, 1F) / <code>General</code><blockquote>
<p>📚 해당 강연을 참석한 이유는?
다양한 행사에 참석했을 때 다양한 사람들과 효과적으로 네트워킹하는 방법을 배우고 싶어 참석하였다.</p>
</blockquote>
</li>
</ul>
<p>해당 세션은 아래와 같은 주제를 다루셨다.</p>
<ol>
<li><p>네트워크 전략</p>
<ul>
<li>네트워크를 하는 이유</li>
<li>네트워킹의 장점
  -&gt; 빠른 트렌드 파악, 커리어 기회, 개인의 성장 등등</li>
<li>효과적인 네트워킹 방법
  -&gt; 경청하기, 대화 촉진 질문, 양보단 질</li>
<li>나만의 네트워크 목표를 설정
  -&gt; 신중, 경청, 관찰, 양보단 질(다수와의 관계보다 한, 두 사람을 만나더라도 잘 알아가기)</li>
</ul>
</li>
<li><p>네트워킹 방법</p>
<ul>
<li>상황별 방법
  -&gt; 지인과 함께 (인사이드 교류 극대화)
  -&gt; 혼자서 (마인드셋, 오거나이저, 관계자, 참석자에게 네트워킹 시도)</li>
</ul>
</li>
<li><p>팔로업</p>
<ul>
<li>첫만남 이후 인연 이어가는 방법
  -&gt; 간단한 자기소개(메시지 남기기, 인상적이었던 대화 내용 혹은 상대와의 공통점 파악)</li>
<li>SNS 팔로업
  -&gt; <strong>프로필 세팅을 미리 해두기</strong></li>
</ul>
</li>
<li><p>IT 행사에 적용</p>
<ul>
<li>컨퍼런스 / 세미나
  -&gt; 연사 : 뒷풀이, 연사 대기실 이용<pre><code> -&gt; 참가자 : 행사 후 네트워킹 유무에 따라 적용</code></pre></li>
<li>해커톤
  -&gt; 빌딩, 해커톤 후 뒷풀이</li>
<li>행사/커뮤니티 자원봉사 (오거나이저 등등)
  -&gt; 가장 자연스럽게 연사, 커뮤니티 구성원과 친해질 수 있는 계기</li>
</ul>
</li>
<li><p>커뮤니티 오거나이저(Community organizers)</p>
<ul>
<li>만약, 본인이 오거나이저일 때 행사 구성하는 방법
  -&gt; 그룹 네트워킹일 때<pre><code>  : 그룹 네트워킹이 가능하다면 관심사/직무에 따라 자리 정해주기
  (Tip. 해당 테이블에 주도적으로 이끌 수 있는 인물 선정)</code></pre>  -&gt; 자유 네트워킹일 때<pre><code>  : 서성이는 사람들에게 먼저 네트워킹 시도, 다른 사람과 연결 시도</code></pre>  -&gt; 참여형 교육을 위한 퍼실리레이터(Facilitatier)의 역할 및 역량 가이드<pre><code>  : [모두의 연구소](https://modulabs.co.kr/blog/facilitator-guide-for-participatory-education/)</code></pre></li>
</ul>
</li>
</ol>
<blockquote>
<p>후기 : 듣다보면 나도 모르게 컨퍼런스에 참석하고 싶다는 욕구(?)가 올라왔다. 정말 좋은 정보를 얻을 수 있었으며 <strong><em>링크드인</em></strong> 세팅의 필요성을 절실하게 느꼈다..</p>
</blockquote>
<hr>
<h3 id="🎈-사수-없는-주니어-개발자가-성장하는-방법">🎈 사수 없는 주니어 개발자가 성장하는 방법</h3>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/2097c590-9627-4638-9cea-d27e7d3601be/image.jpeg" alt=""></p>
<ul>
<li>연사 : <code>이승민</code>님</li>
<li>위치 : 15:00 ~ 15:50 (프리미어볼룸, 2F) / <code>General</code><blockquote>
<p>📚 해당 강연을 참석한 이유는?
군 전역 후 학업을 진행하며 올바른 주니어 개발자로서 성장하기 위한 방법을 배우고 싶어 참석하였다.</p>
</blockquote>
</li>
</ul>
<ol>
<li><p>주니어 개발자의 성장을 위한 방법</p>
<ul>
<li>절대로 가지 말아야 할 회사는 없다. (간혹 있을 수 있지만..)<ul>
<li>사수가 없는 회사도 성장할 수 있지만.. 많은 노력이 필요하다</li>
</ul>
</li>
<li>성장에 중요한 것은 <strong>첫 회사</strong></li>
<li><strong><em>물론 일반화는 금물.</em></strong></li>
</ul>
</li>
<li><p>발표와 블로그를 통한 나만의 브랜드 형성</p>
<ul>
<li>다양한 커뮤니티에서 연사로 발표하기<ul>
<li>발표의 특징</li>
</ul>
<ol>
<li>흩어진 지식들의 연관관계 명확화</li>
<li>그냥 사용하던 기술들의 원리 파악 가능</li>
<li>어떻게 발표하나? (그냥하자. 모르는 주제여도 신청하고! 그 뒤 공부하고 발표 준비)</li>
<li>퍼스널 브랜딩이 된다.
<code>무서워도 괜찮다.</code> <code>사람들이 다 아는 내용인 것 같아도 누군가에게는 충분히 의미가 있다.</code> <code>경험에 자신감을 가진다.</code></li>
</ol>
</li>
<li>블로그로 지식과 경험을 공유하기<ul>
<li>발표와 장점이 비슷하며 브랜드 형성이 된다.</li>
<li>발표보다 컨텐츠가 더 오래 남는다.</li>
<li>개발자 브랜드를 쌓으면 왜 좋나?
  -&gt; 유명하다고 고수는 아니다. 하지만 <code>기회가 있다.</code></li>
</ul>
</li>
</ul>
</li>
<li><p>커뮤니티 참여하기</p>
<ul>
<li>발표, 블로그 등 지식공유를 하다보면 함께 지식을 공유하는 커뮤니티를 만난다.</li>
<li>커뮤니티에서는 지식을 공유하는 훌륭한 개발자들과 직접 지식을 주고받는다.<ul>
<li>커뮤니티 참여 방법은?<ul>
<li>지식공유 (블로깅, 발표, 커뮤니티 기여 등등)<ul>
<li>오거나이저로 지식공유의 장을 만들며 커뮤니티 기여</li>
<li>참여자로 참석하여 공유받은 지식을 활용하여 사회에 기여</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>커뮤니티의 단점은?<ul>
<li>시간은 많이 들어가지만 물질적 보상은 없다.<ul>
<li>커뮤니티를 지속하려면 내적 동기를 만들어야 한다.
(지식공유의 <code>즐거움</code>, 사람들과 교류하는 <code>즐거움</code> 등 나만의 동기 만들기)   </li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<ol start="4">
<li><p>스터디, 사이드 프로젝트, 연합동아리 등</p>
<ul>
<li>학교, 회사, 사이드 프로젝트 혹은 스터디 진행
  -&gt; 현생을 살면서 저녁 시간을 투자하는 것은 힘들긴하다.
  -&gt; 꾸준히 실천하는 것은 어렵지만, 어떻게든 시간을 내서 공부하는 습관 구축<blockquote>
<p>🙋 스터디는 나중에 가서 잊으면 의미 없는 거 아닌가요?
: 아니다. 경험 하나하나가 쌓여가는 것이 의미가 크다. (물론 사람도 남는다.)
: 맞는 사람들끼리 교류하며 스터디 또는 프로젝트를 완주하는 것은 좋다.</p>
</blockquote>
</li>
<li>연합동아리
  -&gt; 대학생, 사회 초년생이 함께 팀프로젝트를 진행함에 있어 매우 큰 의미.
  -&gt; 기술적인 기회도 있지만 <strong>협업을 경험하는 것이 가장 큰 장점</strong></li>
</ul>
</li>
<li><p>오픈소스</p>
<ul>
<li><strong>오픈소스는 개발 업계만 있는 가장 축복받은 문화</strong></li>
<li>전세계 개발자들과 소통할 수 있다.
  -&gt; 여러 나라로부터 발표 초청
  -&gt; 외국계 회사 리모트 입사 기회
  -&gt; 라이브러리나 API 개발</li>
<li><strong>장소와 시간에 제한받지 않고 전세계 개발자들과 교류하며 성장할 수 있다.</strong></li>
</ul>
</li>
<li><p>⭐️ 야근</p>
<ul>
<li>주니어가 사수 없이 회사의 문제를 풀기에 하루 8시간은 턱없이 부족하다.</li>
<li>사수없이 회사 일 혹은 개발 공부를 열심히 하면 스스로 <code>복잡한 문제</code>들을 해결하고 <code>하고싶은 기술</code>을 모두 적용해보며 <code>경험의 폭</code>이 빠르게 성장한다.</li>
<li><strong><em>물론 오래하면 당연히 <code>번아웃</code>이 온다. <code>번아웃</code>없이 꾸준히 성장하기 위해선 개발을 즐겨라.</em></strong></li>
</ul>
</li>
<li><p>개발을 즐겨라</p>
<ul>
<li>발표, 블록, 커뮤니티, 스토디, 사이드 프로젝트, 연합 동아리, 오픈소스 등등 회사 일만 야근이 아니다. 성장을 위한 모든 시간은 퇴근 후 이루어진다.
  -&gt; <strong>꾸준히 오래 해야한다.</strong></li>
<li><strong><em>지치지 않고 오랫동안 갓생을 살기 위해선 좋아하는 일을 해야한다.</em></strong></li>
<li>뭐든지 좋아하는 것이 있다면 <strong><em>지치지 않고 할 수 있으며 매일할 수 있다!</em></strong></li>
</ul>
</li>
<li><p>결론</p>
<blockquote>
<p>🙋 어떻게하면 개발과 취업을 잘할 수 있을까요?</p>
</blockquote>
<pre><code>- 방법론적으로 말하면 발표, 블로그, 커뮤니티 등등 여러가지가 있다.</code></pre><ul>
<li>하지만 근본적으로는 <strong><em>좋아하는 일을 하면 성장을 따라온다.</em></strong></li>
<li><strong><em>동기에 집중하면 습관이 쌓이고 성장은 따라온다.</em></strong></li>
<li><strong><em>성장을 의미로 생각하면 필연적으로 지친다.</em></strong></li>
</ul>
</li>
</ol>
<blockquote>
<p>후기 : 개인적으로 가장 <strong><em>의미가 있었던 강연</em></strong>이었다.
평소 홀로 고민하던 문제점과 개발자로서의 미래에 대한 걱정, 막막함 등 우려하던 요소가 많았지만 다시금 재정비할 수 있었던 계기가 된 강연이라고 생각한다.</p>
</blockquote>
<hr>
<h3 id="🎈-100명의-개발자분들을-도와-100개-넘는-오픈소스-pr을-함께-만들고-세상을-바꾼-이야기">🎈 100명의 개발자분들을 도와 100개 넘는 오픈소스 PR을 함께 만들고 세상을 바꾼 이야기</h3>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/a9b83fb5-b73b-4ee2-9374-78fa356017ed/image.jpeg" alt=""></p>
<ul>
<li>연사 : <code>김인제</code>님</li>
<li>위치 : 16:00 ~ 16:50 (116호, 1F) / <code>OpenSource</code><blockquote>
<p>📚 해당 강연을 참석한 이유는?
오픈소스에 대한 개념과 정의는 알고있지만 막상 실행하고자 하는 용기가 부족했고 그 방법을 알고싶어 참석하였다.</p>
</blockquote>
</li>
</ul>
<ol>
<li><p>오픈소스 기여가 어려운 이유</p>
<ul>
<li>수많은 이슈와 정보 부족</li>
<li>오픈소스 기여를 하기 위한 진입장벽이 너무 높음
  -&gt; 오픈소스 기여는 어떻게?
  -&gt; 이슈, 코드 스타일?
  -&gt; 어떤 코드를 어디까지 읽어야하지?
  -&gt; 코드 설계의 복잡성
  -&gt; 심리적 저항</li>
<li>국내 오픈소스 기여가 적은 이유
  -&gt; 막막함 + 주변에서 기여 방법을 물어보거나 자극받고 배울 기여자가 절대적으로 부족
  -&gt; 오픈소스 기여를 서로 공유하고 자랑하고 돕는 <code>문화</code>의 부재</li>
</ul>
</li>
<li><p>오픈소스 기여 사례와 방법 소개</p>
<ul>
<li>라인, Spring, React 등등 다양한 이슈들을 소개하고 이를 해결하는 과정을 직접적으로 소개해주심.</li>
<li>기술적 이슈를 캐치하여 PR까지 연결해가는 과정</li>
<li>오픈소스 기여를 한 경험을 상세히 강의하시는 것 또한 정말 유익한 인사이드였다.</li>
</ul>
</li>
</ol>
<blockquote>
<p>후기 : 전체적으로 특정 이슈를 어떻게 선정하고 해결 과정은 어떻게 되는지 등 방법을 주로 강연하셨다. 오픈소스 기여에 대한 흥미를 가지고 있는 나에겐 또다른 동기가 되었다.</p>
</blockquote>
<hr>
<h3 id="🎈-gemini-in-android-studio">🎈 Gemini in Android Studio</h3>
<p><img src="https://velog.velcdn.com/images/dxxh_e/post/ead64388-6840-44ad-a718-e9231d34da90/image.jpeg" alt=""></p>
<ul>
<li>연사 : <code>배필주</code>님</li>
<li>위치 : 17:00 ~ 17:50 (프리미어볼룸, 2F) / <code>Android</code></li>
</ul>
<blockquote>
<p>📚 해당 강연을 참석한 이유는?
입대하기 전 <code>Android</code>를 통한 사이드 프로젝트와 개발 경험이 있어 최근 트렌드를 배우고자 참석하였다.</p>
</blockquote>
<ol>
<li><p><code>Gemini API</code>를 Android에 적용하는 방법</p>
<ul>
<li><code>Gemini</code> 종류 소개
  -&gt; Nano, Pro, Ultra 등등 다양한 모델을 소개하며 그에 따른 예시를 설명해주셨다.</li>
<li><code>Gemini</code>의 Android 개발 호환성</li>
</ul>
</li>
<li><p>Gemini Nano use cases on Android</p>
<ul>
<li>Gemini Nano 활용 방법</li>
<li>Nano를 사용하기 위한 Integration 4단계 소개
  (1) Google AI Studio에서 프롬포트를 프로토타이핑
  (2) Google AI Studio에서 API키 발급
  (3) 프로젝트에 Google AI Client SDK에 대한 종속성 추가
  (4) Gemini를 Kotlin 코드에 통합</li>
<li>Gemini를 활용한 다양한 케이스 소개</li>
</ul>
</li>
</ol>
<blockquote>
<p>후기 : 전반적으로 Android Studio에 Gemini를 사용할 수 있는 방법에 대해 말씀하였으며 Gemini를 통해 좀 더 효율적인 앱 개발을 진행할 수 있다는 것을 강조하셨다. Android 개발의 트렌드는 <code>AI</code>와 함께 나아간다는 느낌을 강하게 받았다.</p>
</blockquote>
<hr>
<h1 id="😄-참석-후기">😄 참석 후기</h1>
<blockquote>
<p>이번 컨퍼런스의 경우 기술 정보를 얻기보단 현직자분들의 다양한 경험과 팁, 트렌드 등을 파악하겠다는 목표를 가지고 참석하였다. 
현재 지방에 거주하고 있어 인천까지 가는데 너무 힘들었지만, 그만한 경험과 인사이드를 얻고 온 것 같아 뜻깊었다. 개발자로서의 성장 방법, 오픈 소스 기여를 위한 동기 부여, 다양한 행사에 참석할 수 있는 용기 등등 정말 많은 것을 얻게 된 컨퍼런스였다.
다음에 또 가야지~ <del>인프콘 참석 못 한 게 아직도 아쉽다..ㅠㅠ</del></p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>