<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>zuu3</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 29 Mar 2025 07:33:50 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. zuu3. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/44-444" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[티치몬 회고록]]></title>
            <link>https://velog.io/@44-444/%ED%8B%B0%EC%B9%98%EB%AA%AC%EC%9D%84-%EA%B0%9C%EB%B0%9C%ED%95%98%EB%A9%B0</link>
            <guid>https://velog.io/@44-444/%ED%8B%B0%EC%B9%98%EB%AA%AC%EC%9D%84-%EA%B0%9C%EB%B0%9C%ED%95%98%EB%A9%B0</guid>
            <pubDate>Sat, 29 Mar 2025 07:33:50 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/44-444/post/d9825ca4-be5c-49b5-8d06-a5d5369eac41/image.png" alt=""></p>
<blockquote>
<p>티치몬이란? 부산소마고 &quot;자습 감독 및 방과후 이석 관리 서비스&quot;</p>
</blockquote>
<h2 id="팀원-구성-계기">팀원 구성 계기</h2>
<p>24년 11월 말 즈음 H와 함께 전공동아리 팀원을 구성하자는 것에서 시작되었다. 필자의 친구 한 명(J)과 H의 친구(Y)와 함께 4인 팀을 꾸렸는데, 필자와 J, Y의 포지션은 프론트엔드였다. H의 포지션은 백엔드로 팀원 구성상 백엔드 한명이 더 있으면 좋겠다고 생각해 H와 필자의 친구인 K를 데려와 5인팀이 구성되었다.</p>
<p>이렇게 되니 디자인할 친구가 부족한 상황이 발생하였다. 그러나 6인 팀은 인원이 많은 거 같아 프론트엔드에서 디자인까지 맡게 되었다.</p>
<h2 id="팀원-구성-이후">팀원 구성 이후</h2>
<p>H와 Y가 디자인 시간에 프로젝트로 진행한 티치몬과, K가 구상해 온 학원 프로젝트 2개가 나와 H, Y 따로, J, K, 필자 이렇게 따로 프로젝트를 진행하자는 의견이 나왔다. 하지만 시간관계상 2개의 프로젝트를 따로 나눠서 하는 것보단, 5명 같이 하나의 프로젝트를 하자는 의견이 나왔다. 기획과 디자인이 완료된 티치몬을 선정해 방학 동안의 프로젝트를 시작하게 된다. 시기 좋게 이때, AI 경진대회 공모전도 나와 이 공모전에도 티치몬으로 참가하게 된다.</p>
<h2 id="회의">회의</h2>
<p>티치몬 개발기간이 1월 초  ~ 2월 초 사이인 점을 감안하여 매일 정기 회의 시간을 21시 ~ 23시로 잡고 진행하였다. 정의는 21시 ~ 23시였지만, 대부분 새벽을 넘겨가며 회의를 진행했다. 공휴일, 주말 예외 없었다. 특별한 사정이 아니였으면 무조건 회의는 필참이였다. 이 회의에서는 서로 각자 개발하거나 수정해야할 부분 등 여러가지를 진행했다.</p>
<h2 id="개발">개발</h2>
<h3 id="기술스택">기술스택</h3>
<blockquote>
<p>코어: React, Javascript
상태 관리: React-Query, Zustand
스타일링: Styled-components
패키지 매니저: npm
CI/CD: GitHub Actions</p>
</blockquote>
<p>나는 24년 중반 즈음 나는 리액트의 중요성을 깨닫고 기본기만 알고 있던 상황이였다. 그러나 티치몬에서 Zustand? Styled-components? 이게 뭐지 하는 다양한 라이브러리, 프레임워크를 사용했다. 나는 퍼블리싱밖에 해보지 않았기에 이 부분에 대해서도 정확히 알지 못했다. 그러나 역시는 역시였다. 개발은 프로젝트를 하며 길러가는 것이였다.</p>
<p>프레임워크와 라이브러리는 써보면서 실력을 기르는 것이다. 아예 몰랐던 나도 Y가 써둔 코드를 따라쳐보면서, &quot;아 이렇게 하는 거구나&quot; 하며 배운 것이 정말 많았다. 아래는 내가 처음 Styled-components 코드를 작성한 것이다.</p>
<pre><code class="language-javascript"> import styled from &quot;styled-components&quot;;
 import (... 생략)

 export const ConfirmContainer = styled.div`
   width: 120px;
   height: 42px;
   color: white;
   display: flex;
   justify-content: center;
   align-items: center;
   gap: 10px;
   border-radius: 10px;
   background-color: ${(props) =&gt; (props.color === &#39;red&#39; ? &#39;#F87067&#39; : props.color === &#39;blue&#39; ? &#39;#2E6FF2&#39; : &#39;&#39;)};
   cursor: pointer;
   &amp;:hover {
     opacity: 0.95;
   }
 `;
</code></pre>
<p>정말 어려운 것은 아니였다. 단지 시도를 안해본 것뿐...</p>
<p>서버와의 통신도 나는 티치몬을 하면서 처음 해보는 것이였다. axios를 사용해야 한다는 건 알았지만 Y친구가 axiosInstanse라는 걸 만들어 두었고 이걸 사용하라 하였다.</p>
<p>처음엔 이게 뭔지 몰랐지만 설명을 들어보니 &quot;이렇게 쓰는게 훨씬 좋구나&quot; 라는 생각을 하게 되었다. (자세한 코드는 깃허브 레포지토리를 참고하면 좋을 것같다.)</p>
<p>또한 상태관리는 React-query를 사용하게 되었는데 이 것 또한 난생 처음보는 거였다. 왜 쓰는 건지 정말 의아해했는데 찾아보고 공부해보고 하니 React-query를 쓰는게 훨씬 완전 개 이득이란걸 알게되었다.</p>
<p>아래 코드는 내가 처음 axios통신하는 코드와 React-query 코드를 짠 것이다.</p>
<pre><code class="language-js"> import axiosInstance from &quot;../lib/axiosInstance.js&quot;;

 export const autoAssignment = async ({start, end}) =&gt; {
     try {
         const res = axiosInstance.post(`${API_ENDPOINTS.SUPERVISION}/assignment`, {
             start: start,
             end: end
         })
         if (res.status !== 200 &amp;&amp; res.status !== 201) {
             return Promise.reject({
                 status: res.status,
                 message: res.message || &#39;Request failed&#39;
             });
         }
         return res;
     } catch(err) {
         return Promise.reject(err);
     }
 }
</code></pre>
<pre><code class="language-js"> import { useMutation, useQuery } from &#39;@tanstack/react-query&#39;;
 import { useNavigate } from &#39;react-router-dom&#39;;

 export const useAutoAssignment = () =&gt; {
     const navigate = useNavigate();
     return useMutation({
         mutationFn: (props) =&gt; API.autoAssignment(props),
         onSuccess: () =&gt; {
             navigate(&#39;/supervision/detail&#39;);
         },
         onError: (err) =&gt; {
             console.error(&#39;Assignment 실패:&#39;, err);
         }
     });
 };</code></pre>
<p>이것 또한 정말 어려운 것은 아니였다. 단지 사용법과 개념을 몰랐을 뿐.</p>
<h3 id="💢트러블슈팅">💢트러블슈팅</h3>
<pre><code class="language-js">export const useGetMonthlySupervision = (month) =&gt; {
    return useQuery({
        queryKey: [&#39;getMonthlySupervision&#39;, month],
        queryFn: async () =&gt; {
            const res = await API.getMonthlySupervision(month);
            return res.data || [];
        }
    })
}</code></pre>
<p>아래 통신을 진행하면서 였다.</p>
<p>처음엔</p>
<pre><code class="language-js">import { useGetMonthlySupervision } from
&#39;../../../hooks/useChange.js&#39;;

const { data: TeacherList, isLoading, isError }
= useGetMonthlySupervision(currentMonth);</code></pre>
<p>이런식으로 가져다 사용하였다. 그러나 정상 작동을 하지 않았다. 이유를 찾아보기 위해 API명세서를 확인해보았는데,</p>
<pre><code class="language-json">{
    &quot;data&quot; : [
        {
            &quot;week&quot; : &quot;2월 1주차&quot;,
            &quot;day&quot; : &quot;2월 1일 (월)&quot;,
            &quot;date&quot; : &quot;2025-02-11&quot;,
            &quot;self_study_teacher&quot;: {
                &quot;7th_teacher&quot;: &quot;이름/1/me&quot;,
                &quot;8th_teacher&quot; : &quot;이름/2&quot;,
                &quot;10th_teacher&quot; : &quot;이름/3&quot;
            },
            &quot;leave_seat_teacher&quot;: {
                &quot;7th_teacher&quot;: &quot;이름/1/me&quot;,
                &quot;8th_teacher&quot; : &quot;이름/2&quot;,
                &quot;10th_teacher&quot; : &quot;이름/3&quot;
            },
            &quot;night_teacher&quot;: &quot;이름/1/me&quot;
        }
    ]
}</code></pre>
<p>위와 같이 응답이 오는 것이였다.
<strong>&quot;어 그럼 응답 받아오는 곳에서 res.data를 반환해주는데 정상적으로 바로 떠야하는거 아닌가? 근데 왜 흰 화면이 가끔씩 뜨지?&quot;</strong>
이렇게 생각했다. 그러나 문제가 있었다.</p>
<p>React Query는 데이터를 비동기적으로 받아오기 때문에 컴포넌트가 처음 렌더링될 때는 아직 data가 할당되지 않아 undefined 상태가 된다. 따라서 바로 data에 접근하면 &quot;undefined&quot; 에러가 발생할 수 있다.</p>
<p>예를 들어, 아래와 같이 작성하면</p>
<pre><code class="language-js">const { data: TeacherList, isLoading, isError } = useGetMonthlySupervision(currentMonth);</code></pre>
<p>초기 렌더링 시 TeacherList는 undefined가 될 가능성이 있다. 그 상태에서 TeacherList.data에 접근하면 에러가 발생하게 된다.</p>
<pre><code class="language-js">const { data: TeacherList = { data: [] }, isLoading, isError } = useGetMonthlySupervision(currentMonth);</code></pre>
<p>만약 data가 undefined라면 TeacherList에 기본값인 { data: [] }가 할당된다. 이렇게 하면 렌더링 시점에서 TeacherList.data를 안전하게 사용하여 undefined 에러를 예방할 수 있다.</p>
<p>즉, 초기 데이터가 아직 로드되지 않은 상태에서도 기본값이 지정되어 컴포넌트가 문제없이 렌더링될 수 있도록 한 것이다.</p>
<h2 id="프로젝트를-거의-끝맺음-하며">프로젝트를 거의 끝맺음 하며...</h2>
<p>프로젝트에서 가장 중요한건 역시나 협업인거 같다. 서로 소통이 잘되고 불화를 일으키지 않으며 원활히 잘 진행된 것도 우리 프로젝트에서 한 건을 한거 같다.</p>
<p>티치몬 개발을 마무리 하고 배포를 진행하고 사용자를 받아 운영해보니 힘든 점도 꽤 많았다. 요구사항, 버그, 에러 등등...
이렇게 큰 프로젝트를 처음 해보면서 배운점, 깨달은 점이 매우 많은 것 같다. 아무것도 안하는 것 보단 팀을 꾸려 프로젝트를 해보는게 개발 인생에서 매우 중요한 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] 장치 컨트롤러와 장치 드라이버]]></title>
            <link>https://velog.io/@44-444/CS-%EC%9E%A5%EC%B9%98-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC%EC%99%80-%EC%9E%A5%EC%B9%98-%EB%93%9C%EB%9D%BC%EC%9D%B4%EB%B2%84</link>
            <guid>https://velog.io/@44-444/CS-%EC%9E%A5%EC%B9%98-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC%EC%99%80-%EC%9E%A5%EC%B9%98-%EB%93%9C%EB%9D%BC%EC%9D%B4%EB%B2%84</guid>
            <pubDate>Tue, 03 Dec 2024 23:45:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/44-444/post/023172ac-6b6f-4e99-8a3b-7eb8a07bafd8/image.png" alt=""></p>
<p>이야기 시작하기 전 CPU, 메모리가 더 다루기 어려울까요? 아니면 입출력장치 다루기가 더 까다로울까요?</p>
<p>정답은 <strong>입출력창치 다루기</strong>입니다. 여기에는 크게 2가지 이유가 있는데요.</p>
<h3 id="첫째-입출력장치에는-종류가-너무나도-많습니다">첫째, 입출력장치에는 종류가 너무나도 많습니다.</h3>
<p>지금 당장 떠올릴 수 있는 장치만 하더라도 키보드, 모니터, USB 메모리, CD-ROM, SSD, 마우스, 프린터, 스피커, 마이크 등 매우 많습니다. 장치가 이렇게 다양하면 자연스레 장치마다 속도, 데이터 전송 방법 등도 다양합니다. 따라서 정보를 주고 받는 방식을 규격화하기가 어렵습니다. 아래 사진이 가장 좋은 예시를 들어주는거 같습니다.
<img src="https://velog.velcdn.com/images/44-444/post/584471fa-b0e8-48be-97b7-94c7e2c64c7f/image.png" alt=""></p>
<h3 id="둘째-일반적으로-cpu와-메모리의-데이터-전송률은-높지만-입출력장치의-데이터-전송률은-낮습니다">둘째, 일반적으로 CPU와 메모리의 데이터 전송률은 높지만 입출력장치의 데이터 전송률은 낮습니다.</h3>
<p><strong>전송률이란?</strong> 데이터를 얼마나 빨리교환할 수 있는지를 나타내는 지표입니다.</p>
<p>CPU나 메모리처럼 전송률이 높은 장치는 1초에 수많은 데이터를 주고 받을 수 있지만, 키보드나 마우스와 같이 상대적으로 전송률이 낮은 장치는 같은 시간동안 적은량의 데이터만 주고받을 수 있습니다. 아래 사진과 같이 1초에 1000마디를 내밷는 사람과 1초에 한 마디를 내뱉는 사람끼리 제대로된 대화를 하기엔 어려움이 있습니다. 따라서 <strong>전송률의 차이는 CPU와 메모리, 입출력장치 간의 통신을 어렵게 합니다.</strong>
<img src="https://velog.velcdn.com/images/44-444/post/80677fb7-e773-4157-9c9c-2ce6827a186d/image.png" alt=""></p>
<p>위와 같은 이유로 입출력장치는 컴퓨터에 직접 연결되지 않고 <strong>장치 컨트롤러</strong>라는 하드웨어를 통해 연결됩니다.</p>
<h2 id="장치-컨트롤러">장치 컨트롤러</h2>
<p>장치 컨트롤러는 <strong>입출력 제어기</strong>, <strong>입출력 모듈</strong>등으로 다양하게 불립니다. 모든 입출력장치는 각자의 장치 컨트롤러를 통해 컴퓨터 내부와 정보를 주고받고, 장치 컨트롤러는 하나 이상의 입출력장치와 연결되어 있습니다.</p>
<h3 id="장치-컨트롤러의-대표적인-역할">장치 컨트롤러의 대표적인 역할</h3>
<ol>
<li>CPU와 입출력장치간의 통신 중개</li>
<li>오류 검출</li>
<li>데이터 버퍼링</li>
</ol>
<p>아까 보았던 정보 규격화가 어려웠던 문제는 장치 컨트롤러가 일종의 번역가 역할을 함으로써 해결할 수 있습니다. 그 과정에서 <strong>장치 컨트롤러는 자신과 연결된 입출력장치에 문제는 없는지 오류를 검출하기도 합니다.</strong>
<img src="https://velog.velcdn.com/images/44-444/post/48c0633b-bcc8-4086-96b2-d5660c616a69/image.jpg" alt="">
여기서 잠깐 그럼 <strong>데이터 버퍼링</strong>은 무엇인가요? 먼저 버퍼링이란 <strong>전송률이 높은 장치와 낮은 장치 사이에 주고받는 데이터를 버퍼라는 임시 저장 공간에 저장하여 전송률을 비슷하게 맞추는 방법</strong>입니다. 쉽게 말해 버퍼링은 <strong>&#39;버퍼에 데이터를 조금씩 모았다가 한꺼번에 내보내거나, 데이터를 한 번에 많이 받아 조금씩 내보내는 방법&#39;</strong> 이라고 보시면 됩니다.</p>
<h3 id="장치-컨트롤러의-간략화된-내부-구조">장치 컨트롤러의 간략화된 내부 구조</h3>
<p><img src="https://velog.velcdn.com/images/44-444/post/698babc6-a28e-4a07-b82b-5c0489a2f19e/image.png" alt=""></p>
<h4 id="상태-레지스터와-제어-레지스터는-하나의-레지스터상태제어-레지스터로-사용되기도-합니다">상태 레지스터와 제어 레지스터는 하나의 레지스터(상태/제어 레지스터)로 사용되기도 합니다.</h4>
<blockquote>
<ol>
<li>데이터 레지스터 : <strong>데이터가 담기는 레지스터</strong>, 앞서 데이터 버퍼링으로 전송률 차이를 완화한다고 했었는데, <strong>데이터 레지스터가 그 버퍼 역할</strong>을 합니다. 주고받는 데이터가 많은 입출력장치에서는 레지스터 대신 RAM을 사용하기도 합니다.</li>
<li>상태 레지스터 : 입출력 작업을 할 준비가 되었는지, 입출력 작업이 완료되었는지, 오류가 없는지 등의 <strong>상태 정보가 저장</strong>됩니다.</li>
<li>제어 레지스터 : 입출력장치가 수행할 내용에 대한 제어 <strong>정보와 명령을 저장</strong>합니다.</li>
</ol>
</blockquote>
<p>이 레지스터들에 담긴 값들은 버스를 타고 CPU나 다른 입출력장치로 전달되기도 하고, 장치 컨트롤러에 연결된 입출력장치로 전달됩니다.</p>
<h2 id="장치-드라이버">장치 드라이버</h2>
<p>장치 드라이버란? <strong>장치 컨트롤러의 동작을 감지하고 제어함으로써 장치 컨트롤러가 컴퓨터 내부와 정보를 주고받을 수 있게 하는 프로그램</strong>입니다. </p>
<blockquote>
<p>장치 컨트롤러가 입출력장치를 연결하기 위한 <strong>하드웨어적인 통로</strong>라면, 장치 드라이버는 입출력장치를 연결하기 위한 <strong>소프트웨어적인 통로</strong>입니다.
<img src="https://velog.velcdn.com/images/44-444/post/ca30967d-9940-41e4-822f-a0d74d1bbdbd/image.png" alt=""></p>
</blockquote>
<h3 id="그렇다면-장치-드라이버를-인식하고-실행하는-주체는-누구인가요">그렇다면 장치 드라이버를 인식하고 실행하는 주체는 누구인가요?</h3>
<p>장치 드라이버를 인식하고 실행하는 주체는 윈도우, macOS와 같은 <strong>운영체제</strong>입니다.</p>
<blockquote>
<p>장치 드라이버는 운영체제가 기본적으로 제공하는 것도 있지만, 장치 제작자가 따로 제작하기도 합니다. <strong>장치 제작자가 장치 드라이버를 따로 제공하는 경우 입출력장치는 해당 드라이버를 직접 설치해야만 사용이 가능합니다.</strong>
<img src="https://velog.velcdn.com/images/44-444/post/d70fa32e-aedc-4ea7-b6ce-8831e0211ecf/image.png" alt=""></p>
</blockquote>
<hr>
<p><img src="https://velog.velcdn.com/images/44-444/post/811c381b-f15d-40d6-a464-84892bbe4c52/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>