<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>gang_gang_gang.log</title>
        <link>https://velog.io/</link>
        <description>낭만 찾아 집떠난 개발자</description>
        <lastBuildDate>Wed, 02 Jul 2025 12:50:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>gang_gang_gang.log</title>
            <url>https://velog.velcdn.com/images/gang_gang_gang/profile/ccb73b60-2cf9-4952-93d0-f3d398cb9821/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. gang_gang_gang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/gang_gang_gang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[ky로 fetch 대체하기 (fetch 딥 다이브)]]></title>
            <link>https://velog.io/@gang_gang_gang/Ky-replacement-for-fetch</link>
            <guid>https://velog.io/@gang_gang_gang/Ky-replacement-for-fetch</guid>
            <pubDate>Wed, 02 Jul 2025 12:50:57 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/gang_gang_gang/post/006d6317-75c7-481e-9c4a-ca41871439e3/image.png" alt=""></p>
<h3 id="nextjs에선-axios-대신-fetch를-확장해서-쓰자">Next.js에선 axios 대신 fetch를 확장해서 쓰자!</h3>
<p>JS 생태계에서 Axios 대신 fetch를 확장해서 쓰고자 하는 움직임은 꾸준히 있었다.
Next.js 환경에서는 fetch를 이용해야 캐싱도 next.js 환경에서 의도한 바 대로 동작하게 할 수 있고, 별도의 HTTP 클라이언트를 두지 않아 번들 사이즈를 최적화 할 수 있다고 한다. 작은 번들 사이즈는 오히려 CSR 환경에서 더욱 중요해 보인다.</p>
<p>그런데 글을 쓰면서 알아보니 24년도에 axios의 adapter 설정으로 next.js의 fetch를 이용할 수 있게 됐다고 한다. 이 글에서 next.js의 fetch가 어떻게 구현돼있는지에 대한 인사이트도 얻을 수 있었다. globalThis의 fetch를 오버라이딩 한다는 거였다. </p>
<p><a href="https://velog.io/@bbbjihan/Next.js-%EC%BA%90%EC%8B%B1-%EB%95%8C%EB%AC%B8%EC%97%90-Axios-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0%EB%A5%BC-%ED%8F%AC%EA%B8%B0%ED%95%98%EB%9D%BC%EA%B3%A0-Axios-adapter-%EC%84%A4%EC%A0%95%EC%9C%BC%EB%A1%9C-Next.js-caching-%EC%A7%80%EC%9B%90-%EB%B0%9B%EA%B8%B0">https://velog.io/@bbbjihan/Next.js-%EC%BA%90%EC%8B%B1-%EB%95%8C%EB%AC%B8%EC%97%90-Axios-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0%EB%A5%BC-%ED%8F%AC%EA%B8%B0%ED%95%98%EB%9D%BC%EA%B3%A0-Axios-adapter-%EC%84%A4%EC%A0%95%EC%9C%BC%EB%A1%9C-Next.js-caching-%EC%A7%80%EC%9B%90-%EB%B0%9B%EA%B8%B0</a></p>
<h3 id="return-fetch를-써봤어요">return-fetch를 써봤어요</h3>
<p>나도 React 환경에서 axios를 이용했지만, next.js 환경에서는 next.js에서의 서버 컴포넌트, 캐시 등을 이유로 fetch을 확장해서 만든 return-fetch 를 써봤다. Axios처럼 인터셉트 기능을 지원해서 매우 좋았지만, 당시에 패키지 매니저 관련 이슈로 인해 직접 core 패키지에 코드를 포함해 이용해야만 하는 단점이 있었다. 그래서 이번에는 ‘ky’ 를 써보기로 했다. 아, 여담이지만 이 라이브러리 꽤 많은 곳에서 이용하는 나름 공룡이 돼버렸다.</p>
<p><img src="https://velog.velcdn.com/images/gang_gang_gang/post/e0612fa1-14f4-4bd3-bb2e-ba5ddba1d84f/image.png" alt="">
<img src="https://velog.velcdn.com/images/gang_gang_gang/post/10a89ec8-2c7c-4239-8869-67f3b2694310/image.png" alt="">
나도 React 환경에서 axios를 이용했지만, next.js 환경에서는 next.js에서의 서버 컴포넌트, 캐시 등을 이유로 fetch을 확장해서 만든 return-fetch 를 써봤다. Axios처럼 인터셉트 기능을 지원해서 매우 좋았지만, 당시에 패키지 매니저 관련 이슈로 인해 직접 core 패키지에 코드를 포함해 이용해야만 하는 단점이 있었다. 그래서 이번에는 ‘ky’ 를 써보기로 했다. 아, 여담이지만 이 라이브러리 꽤 많은 곳에서 이용하는 나름 공룡이 돼버렸다.</p>
<h3 id="어디였는지는-모르겠는데요-어디선가-봤어요">어디였는지는 모르겠는데요, 어디선가 봤어요</h3>
<p>어디선가 ky 를 이용해 API 호출 인스턴스를 만든 것을 기억해뒀다가 도입하기로 했다. 도입하기로 한 이후로는 탄탄대로였다. Interceptor와 같은 개념인 ‘hooks’ 개념으로 Request, Response에 대한 Interceptor를 구현할 수 있다. </p>
<pre><code class="language-typescript">const api = ky.create({
  prefixUrl: process.env.EXPO_PUBLIC_API_URL,
  timeout: 5000, // 5초 후 타임아웃
  headers: {
    &quot;Content-Type&quot;: &quot;application/json&quot;,
  },
  hooks: {
    beforeRequest: [
      async (request) =&gt; {
        console.debug(&quot;🚀 Request START:&quot;, request.method, request.url);
        // 로컬 스토리지에서 토큰 가져오기
        // 토큰 없으면 경고 표시
        // 토큰 헤더에 추가
        return request;
      },
    ],
    afterResponse: [
      async (request, options, response) =&gt; {
          // 응닫 처리
        try {
          const body = await response.clone().json();
          // ResponseWrapper 구조를 갖고 있는지? (TS Type Guard)
          // 객체에 존재하는 JS Date 포매팅
          // 새로운 응답 객체로 반환
        } catch (e) {
            // 파싱 관련 에러 처리
        }
        return response;
      },
    ],
    beforeError: [
      async (error) =&gt; {
          // 에러가 발생한 경우 Body가 존재하면 ResponseWrapper 구조로 파싱
          // 파싱된 객체에서 message, status 파악해 로깅
          // 그대로 다시 반환, 호출하는 쪽에서 HTTPError 핸들링 하게 처리
      },
    ],
  },
})</code></pre>
<h3 id="딥-다이브-하기">딥 다이브 하기</h3>
<p>글을 쓰다 보니 fetch를 왜 next.js에서 지양해야 한다고 사람들이 말했는지를 확실하게 알 수 있었고, next.js의 fetch가 어떻게 동작하는지도 알 수 있게 된 딥 다이브였다. 이렇게 라이브러리를 쓰다 보면 안쪽이 어떻게 구현돼있는지가 궁금해지기 마련이고, 그럴 때 주저 없이 딥다이브 해보자. 더 깊이 빠져 죽어도 되니까. 아, 물론 이정도로 무슨 딥다이브냐고 할 사람들도 있을 것이다. 그런 분들껜 나댄 것에 대한 심심한 사과를..</p>
<p>Tanstack Query를 팠을 때도 그랬고, 확실히 딥다이브를 하면 인사이트가 한층 상승하는 것 같다. 성장..? 이라고 해야할까 이걸? </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CoreML로 객체 인식 기능 개발하기]]></title>
            <link>https://velog.io/@gang_gang_gang/CoreML%EB%A1%9C-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%EC%8B%9D-%EA%B8%B0%EB%8A%A5-%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@gang_gang_gang/CoreML%EB%A1%9C-%EA%B0%9D%EC%B2%B4-%EC%9D%B8%EC%8B%9D-%EA%B8%B0%EB%8A%A5-%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 02 Jul 2025 10:46:51 GMT</pubDate>
            <description><![CDATA[<p>비전에 입문하는 것은 쉬운 일은 아니다. 적절한 전처리도 필요하고, 직접 모델을 학습하는 경우 데이터의 수집, 선별, 가공까지 해야하기 때문이다. 그럼에도 불구하고 인천대학교 서비스 개발 해커톤 “유니톤”에서 나온 아이디어를 실현하기 위해 비전이 필수적이었다.</p>
<h3 id="쓰레기를-분류하고-싶어">쓰레기를 분류하고 싶어</h3>
<p>처음에는 딸기를 먹다가 “딸기꼭지는 일반쓰레기일까, 음식물일까?” 라는 의문에서 시작했다고 한다. 나도 부모님의 영향을 받아 분리배출을 굉장히 열심히 하는 사람으로서 이런 상황에서 분류를 도와줄 모델, 이걸 구동할 경량의 앱이 있다면 분리배출을 조금 더 잘 할 수 있지 않을까 싶었다.</p>
<h3 id="분류-모델을-써보자-뭔가-아쉬운데">분류 모델을 써보자! 뭔가 아쉬운데..</h3>
<p>간단한 모델 학습 코드를 가져와 이미지 분류 모델인 MobileNetV2에 kaggle에 올라가 있는 TrashNet 데이터셋을 학습시켜 간단하게 테스트를 해보았다. ONNX 모델로 export 해 모바일 기기에서 각각 구동했다. 생각보다 잘 분류하는 모습을 보고 괜찮다 싶었지만, 뭔가 좀 아쉽다는 생각을 했다. 그래서 객체 인식과 분류를 동시에 하는 YOLO 모델로 눈을 돌렸다. 그러지 말아야 했는데..</p>
<pre><code class="language-python">model = models.mobilenet_v2(pretrained=True)
model.classifier[1] = nn.Linear(model.last_channel, len(class_names))
model = model.to(device)</code></pre>
<h3 id="바이브-코딩의-위험성">바이브 코딩의 위험성</h3>
<p>호기롭게 Ultralytics에서 제공하는 파이썬 라이브러리를 이용해 엄청 간단하게 coco 데이터셋으로 학습된 모델을 ONNX로 내보낼 수 있었다. 그런데 문제는 여기서부터 시작됐다. 모델의 I/O를 대충은 알지만, 문제는 정확한 모델의 특성을 모르고 바이브코딩에 의존했던 것이다. </p>
<p>그래서 코드를 한 줄 한 줄 읽어보기 시작했다. 그리고 학습한 주피터 노트북을 열어 출력값을 한 줄 한 줄 읽어보기 시작했다. (1, 640, 640)의 입력과 (1, 84, 8400)의 출력을 가진 모델이란 것은 알고 있었지만 정확히 어떻게 데이터가 도출되는 것인지는 몰랐는데, LLM에 모델의 특성에 대해 질문하고 이를 기반으로 이해를 넓혀가다 보니 모델을 어느 정도 정보가 되었다. 하지만 여전히 모델의 정보를 상세히 알아야 하는 점에서 AI에 깊은 이해를 가지지 않은 내가 이용하기에는 부담이 되었다.</p>
<h3 id="그-후의-많은-시행착오">그 후의 많은 시행착오</h3>
<p>많은 시행착오를 겪었다. ONNX에서 VisionCamera Plugin을 이용해 TFLite 모델을 RN에서 불러와 프레임프로세서로 넘겨도 보고, TFLite를 iOS 네이티브에서 이용도 해보기도 했다. 그러다 애플의 CoreML이 떠올랐다. “애플의 프레임워크면 iOS 환경에 최적화되어 있지 않을까?” 싶은 생각에서 시작했다. </p>
<h3 id="coreml로-암에서-탈출했어요">CoreML로 암에서 탈출했어요</h3>
<p><img src="https://velog.velcdn.com/images/gang_gang_gang/post/9bc8e33c-f442-46e4-a09f-79728919fd92/image.png" alt="">
지금은 CoreML이 Apple 제품에서 온디바이스 모델을 구동하기에 최적의 프레임워크라고 확신한다.
coremltools 파이썬 라이브러리를 용해 Tensorflow, ONNX 등 여러 다른 머신러닝 프레임워크의 모델을 CoreML용으로 변환 가능해 대부분의 경우 정상적으로 CoreML 모델로의 변환이 가능하다.
그리고 모델을 OS의 통제 아래에 둬 성능 최적화가 간편하고, 무엇보다 모델의 입출력 구조가 어떻게 되든 사전에 모델을 컴파일해  확실한 인터페이스화가 되고 모델 구동이 간편해지는 장점이 있다. Xcode에서 이해하고 있는 입력 형태로 넣어만 주면 매우 잘 돌아간다.</p>
<h3 id="coreml은-신이고-바이브-코딩은-지양하자">CoreML은 신이고 바이브 코딩은 지양하자</h3>
<p>난 객체인식 기능을 개발하는 과정을 겪으며 무지성 바이브 코딩은 오히려 직접 가는 길이 아닌 돌아가는 길임을 뼈저리게 깨닿게 되었다. 특히 비전 기능과 같이 비교적 정보가 많이 없는 기술의 경우 더더욱. 앞으론 쉬운 길을 우선 탐색해보기로 하자.</p>
]]></description>
        </item>
    </channel>
</rss>