<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Sijun Yang</title>
      <link>https://sijun-yang.com/</link>
      <description>Sijun Yang의 블로그</description>
      <generator>Zola</generator>
      <language>ko</language>
      <atom:link href="https://sijun-yang.com/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Sat, 28 Feb 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>[월간 기록] 2026년 2월</title>
          <pubDate>Sat, 28 Feb 2026 00:00:00 +0000</pubDate>
          <author>Sijun Yang</author>
          <link>https://sijun-yang.com/blog/monthly-log-2026-02/</link>
          <guid>https://sijun-yang.com/blog/monthly-log-2026-02/</guid>
          <description xml:base="https://sijun-yang.com/blog/monthly-log-2026-02/">&lt;h2 id=&quot;sujib&quot;&gt;수집&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;흥미롭거나 유용했던 자료들&lt;&#x2F;p&gt;&lt;h3 id=&quot;todo&quot;&gt;TODO&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;geu-oe-sujibhan-geul&quot;&gt;그 외 수집한 글&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;TODO&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;jageob&quot;&gt;작업&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;학습, 개발, 실험 등 직접 손댄 것들&lt;&#x2F;p&gt;&lt;h3 id=&quot;todo-1&quot;&gt;TODO&lt;&#x2F;h3&gt;
&lt;h2 id=&quot;jjalbeun-saenggag&quot;&gt;짧은 생각&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;근황과 요즘 하는 생각&lt;&#x2F;p&gt;
&lt;p&gt;TODO&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>[월간 기록] 2026년 1월</title>
          <pubDate>Sat, 31 Jan 2026 00:00:00 +0000</pubDate>
          <author>Sijun Yang</author>
          <link>https://sijun-yang.com/blog/monthly-log-2026-01/</link>
          <guid>https://sijun-yang.com/blog/monthly-log-2026-01/</guid>
          <description xml:base="https://sijun-yang.com/blog/monthly-log-2026-01/">&lt;p&gt;이번 달에는 정규표현식 내부 구조, 비동기 모델, 스레드 메모리 위치 같은 기술 관련 내용을 파봤다. 기술 관련 글을 읽다가 궁금해진 것들이다.
그리고 여러 개인, 기업, 교육기관에서 AI 활용 능력을 다룬 글들이 많이 눈에 띄었다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sujib&quot;&gt;수집&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;흥미롭거나 유용했던 자료들&lt;&#x2F;p&gt;&lt;h3 id=&quot;the-missing-semester-of-your-cs-education&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;missing.csail.mit.edu&#x2F;&quot;&gt;The Missing Semester of Your CS Education&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;MIT에서 진행하는 강의다. CS 수업과 달리 명령줄, 에디터, 버전 관리 시스템 등 개발자가 매일 사용하는 도구를 효율적으로 활용하는 방법에 초점을 둔다. 강의 자료와 영상은 인터넷에 공개되어 있어 외부 사용자도 자유롭게 학습할 수 있다.&lt;&#x2F;p&gt;
&lt;p&gt;Git, 디버깅, Shell 활용, dotfiles 관리, 기본적인 보안 개념 등 실무에서 알아두면 좋은 주제들을 넓고 얕게 정리해 준다. 관심 있는 주제만 골라서 봐도 이해하는 데 상관없어 부담 없이 볼 수 있다.&lt;&#x2F;p&gt;
&lt;p&gt;2026년 강의는 현재 촬영 중이며, 2020년 이후 새롭게 공개되는 강의이다. LSP와 AI 기반 도구 관련 내용이 추가되고 Shell이나 Vim의 비중은 줄어드는 등, 개발 환경의 변화가 비교적 잘 반영되고 있는 듯하다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;73-programming-project-ideas-to-inspire-and-challenge-you-hackernews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codecrafters.io&#x2F;blog&#x2F;programming-project-ideas&quot;&gt;73 Programming Project Ideas to Inspire and Challenge You&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=46439027&quot;&gt;HackerNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;직접 구현해볼 수 있는 73개의 프로그래밍 프로젝트 아이디어와 참고 자료를 정리한 글이다.&lt;&#x2F;p&gt;
&lt;p&gt;GitHub에서 유명한 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;codecrafters-io&#x2F;build-your-own-x&quot;&gt;build-your-own-x&lt;&#x2F;a&gt; 레포가 있는데, CodeCrafters에서 운영하고 있다.&lt;&#x2F;p&gt;
&lt;p&gt;CodeCrafters는 Redis, Git 같은 유명한 프로젝트를 직접 만들어보는 서비스를 제공한다. 관심 가는 프로젝트들이 있어서 시간 나면 시도해볼 생각이다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;regular-expression-matching-can-be-simple-and-fast-hackernews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;swtch.com&#x2F;~rsc&#x2F;regexp&#x2F;regexp1.html&quot;&gt;Regular Expression Matching Can Be Simple And Fast&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=40422997&quot;&gt;HackerNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;대부분의 프로그래밍 언어는 backreference, look-around 같은 확장 기능을 지원하기 위해 백트래킹 NFA를 사용하는데, 이 방식은 최악의 경우 지수 시간이 걸릴 수 있다. 반면 Thompson NFA는 이런 확장 기능을 지원하지 못하지만, 최악의 경우에도 O(mn) 시간을 보장한다. &lt;code&gt;awk&lt;&#x2F;code&gt;, &lt;code&gt;grep&lt;&#x2F;code&gt; 같은 전통적인 Unix 텍스트 처리 도구가 이 방식을 사용한다.&lt;&#x2F;p&gt;
&lt;p&gt;정규표현식이 유한 상태 기계(Finite State Machine)로 구현된다는 사실은 들어봤는데, 실제 코드를 보니 더욱 흥미로웠다. 정규표현식과 FSM을 변환해주는 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ivanzuzak.info&#x2F;noam&#x2F;webapps&#x2F;fsm2regex&#x2F;&quot;&gt;FSM2Regex&lt;&#x2F;a&gt;를 사용해보면 이해에 도움이 된다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-async-rust-hackernews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;without.boats&#x2F;blog&#x2F;why-async-rust&#x2F;&quot;&gt;Why async Rust?&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=37891020&quot;&gt;HackerNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Rust의 async가 왜 현재의 모습을 가지는지 핵심 기여자가 설명한 글.&lt;&#x2F;p&gt;
&lt;p&gt;글 자체로도 좋지만, 다중 스레드의 생성 원리, 비동기 실행 모델과 Rust의 executor에 대한 궁금증이 생겨서 추가로 찾아보게 된 좋은 계기였다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cs146s-the-modern-software-developer-gongsig-hangugeo-beonyeogbon&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;themodernsoftware.dev&#x2F;&quot;&gt;CS146S: The Modern Software Developer&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kr.themodernsoftware.dev&#x2F;&quot;&gt;공식 한국어 번역본&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Stanford 강의와 공식 한국어 번역본이다. 강의에서 AI 기반 개발을 꽤 자세하게 다루는 것 같다.
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.team-attention.com&#x2F;&quot;&gt;번역하는 팀&lt;&#x2F;a&gt;을 봤는데 시니어&#x2F;리더급 엔지니어 분들이다.&lt;&#x2F;p&gt;
&lt;p&gt;AI 기반 번역이고 검수가 되지 않은 듯한 부분에서 누락&#x2F;오역 등의 문제가 있어 원문과 비교하면서 보는 걸 추천한다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-the-index-luke&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;use-the-index-luke.com&#x2F;&quot;&gt;Use The Index, Luke&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=46751826&quot;&gt;&quot;Introduction to PostgreSQL Indexes&quot; 해커뉴스 글&lt;&#x2F;a&gt;의 댓글에서 추천받아 알게 되었다.&lt;&#x2F;p&gt;
&lt;p&gt;목차까지만 보았는데 SQLP 준비할 때 배웠던 내용과 겹치는 부분이 많아서 잘 구성된거 같고, 여러 DBMS를 다루고 있어서 기억해두려고 한다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ai-sidae-ripaegteoringeun-deo-isang-nogadaga-anida-geeknews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.lemonbase.team&#x2F;ai-%EC%8B%9C%EB%8C%80-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81%EC%9D%80-%EB%8D%94-%EC%9D%B4%EC%83%81-%EB%85%B8%EA%B0%80%EB%8B%A4%EA%B0%80-%EC%95%84%EB%8B%88%EB%8B%A4-24f3cfae20b6&quot;&gt;AI 시대, 리팩터링은 더 이상 노가다가 아니다&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=26040&quot;&gt;GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;레거시 컴포넌트들이 코드베이스에 혼재하는 문제를 AI와 Codemod로 해결한 사례를 설명한 글이다. AI를 매우 잘 사용한 좋은 예시가 될 수 있겠다.&lt;&#x2F;p&gt;
&lt;p&gt;이런 자동화 관련된 사례가 많이 보이는데, 이제 AI를 사용해서 대규모, 엣지 케이스가 있는 작업도 자동화가 쉽게 가능해진 것 같다.&lt;&#x2F;p&gt;
&lt;p&gt;비슷한 글: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;insight.infograb.net&#x2F;blog&#x2F;2026&#x2F;01&#x2F;28&#x2F;claude-skills-gitlab&#x2F;&quot;&gt;Claude Skills로 GitLab 업그레이드 자동화하기&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dibeoging-maindeuses-dibeogingyi-gotongeul-jeolbaneuro-julyeojuneun-gosudeulyi-haengdongpaeteon-ddarahagi&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.stdy.blog&#x2F;infcon-2024-debugging-mindset&#x2F;&quot;&gt;디버깅 마인드셋: 디버깅의 고통을 절반으로 줄여주는 고수들의 행동패턴 따라하기&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;실력 있는 개발자들의 디버깅 패턴을 정리한 글. 핵심은 원인 파악에 시간을 투자하고, 정상 동작에 대한 심적 표상(머릿속에 구축된 지식 구조)를 쌓아야 한다는 말.&lt;&#x2F;p&gt;
&lt;p&gt;이전에 읽고 실천했을 때 효과가 좋았고, 오랜만에 봐도 좋은 내용이라고 생각한다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;moltbot-jejagja-naneun-ilgji-anheun-kodeureul-baepohanda-geeknews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=26222&quot;&gt;MoltBot 제작자: “나는 읽지 않은 코드를 배포한다” | GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;창업자 출신인 Peter Steinberger의 개인 프로젝트지만 많은 관심을 받고 있는 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.molt.bot&#x2F;&quot;&gt;Moltbot&lt;&#x2F;a&gt;은 메신저를 인터페이스로,
로컬 머신을 실행 환경으로 사용하는 LLM 에이전트 게이트웨이다.
로컬에서 지속적으로 실행되며 개인용 AI 에이전트로 활용할 수 있다.&lt;&#x2F;p&gt;
&lt;p&gt;개발 워크플로우를 다룬 인터뮤가 공개되었는데, AI 에이전트를 적극 활용한 개발 방식을 사용한다.
코드 자체보다 프롬프트를 보고 결과물을 평가하는 접근이 인상적이였다.&lt;&#x2F;p&gt;
&lt;p&gt;물론 책임 소재가 사용자에게 있는 오픈소스에 개인 프로젝트라서나 가능한 방식이고,
회사 환경에서는 책임 소재나 검증 문제로 그대로 적용하기 어려울 거 같다.&lt;&#x2F;p&gt;
&lt;p&gt;에이전트 기반 개발의 한 방향성으로 참고할 만하다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;seonggonghaneun-eoneoyi-jogeon-creul-gyesog-baeweoya-haneun-iyue-daehan-yigyeon&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;sijun-yang.com&#x2F;blog&#x2F;monthly-log-2026-01&#x2F;(https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;Zig&#x2F;comments&#x2F;1fe9f1a&#x2F;comment&#x2F;neblpba&#x2F;)&quot;&gt;성공하는 언어의 조건, C를 계속 배워야 하는 이유에 대한 의견&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;간단한 토이프로젝트를 만드려고 했는데 애플이 제공하는 C 라이브러리를 사용해야 했다. Rust는 FFI가 필요해서, C 라이브러리를 바로 쓸 수 있는 Zig로 해볼까 검색하며 찾아보는 흥미로운 의견을 발견헀다.&lt;&#x2F;p&gt;
&lt;p&gt;Zig는 성공하는 언어의 기준에 맞지 않아 성공하기 어렵고 C는 여전히 필요하다는 흥미로운 의견을 발견했다.
극단적이긴 하지만, 언어가 기업의 선택을 받고 성공하는 기준에 대해 그럴듯하고 공감가는 의견이라 기록해둔다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;geu-oe-sujibhan-geul&quot;&gt;그 외 수집한 글&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.g15e.com&#x2F;pages&#x2F;Source%20code%20quality%20in%20the%20AI%20era&quot;&gt;&lt;strong&gt;AI 시대의 소스코드 품질 - akwiki&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;: AI로 작업하면서 품질 하락을 막기 위한 구체적인 도구들을 소개한다.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;evan-moon.github.io&#x2F;2026&#x2F;01&#x2F;25&#x2F;types-as-proofs-typescript-hidden-math&#x2F;&quot;&gt;&lt;strong&gt;타입 시스템은 왜 증명처럼 동작하는가&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;: 예전에 OCmal 공부할 때 Hindley-Milner, Curry-Howard 같은 타입 이론을 들어봤는데, TypeScript를 이런 Curry-Howard 이론 관점에서 설명한다. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;n0whur&#x2F;against_curry_howard_mysticism&quot;&gt;언어를 Curry-Howard 이론으로 설명하는게 무용하다는 의견&lt;&#x2F;a&gt;도 있다.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kerkour.com&#x2F;&quot;&gt;&lt;strong&gt;Sylvain Kerkour의 블로그&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;: Rust, 보안에 대한 내용을 다룬다. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kerkour.com&#x2F;rust-devcontainers&quot;&gt;Dev Containers&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kerkour.com&#x2F;rust-organize-errors-large-projects&quot;&gt;오류 처리&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kerkour.com&#x2F;rust-web-services-axum-sqlx-postgresql&quot;&gt;Rust, Axum, SQLx 스택&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kerkour.com&#x2F;rust-how-to-organize-large-workspaces&quot;&gt;대규모 코드베이스 권장사항&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kerkour.com&#x2F;rust-web-application-clean-architecture&quot;&gt;아키텍처&lt;&#x2F;a&gt; 등을 다룬다. 다만 웹 개발&#x2F;보안 쪽에 치우쳐져 있고 동의하지 않는 주장도 있어 주의하기.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;jageob&quot;&gt;작업&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;학습, 개발, 실험 등 직접 손댄 것들&lt;&#x2F;p&gt;&lt;h3 id=&quot;sigan-deiteoreul-olbareuge-daruneun-bangbeob-beulrogeu-jagseong&quot;&gt;&lt;a href=&quot;&#x2F;blog&#x2F;how-to-handle-time-data&quot;&gt;&quot;시간 데이터를 올바르게 다루는 방법&quot;&lt;&#x2F;a&gt; 블로그 작성&lt;&#x2F;h3&gt;
&lt;p&gt;원래는 핵심 원칙만 간단히 정리할 생각이었지만, 쓰다 보니 시간 처리의 역사나 참고한 Temporal API까지 추가하는 게 이해하기 좋을 것 같아 내용이 대폭 늘었다.
그 과정에서 글의 완성도를 신경 쓰다 보니 시간이 많이 들었다.&lt;&#x2F;p&gt;
&lt;p&gt;다음에 블로그를 쓸 때는 머릿속으로 구조를 완성해두고 명확히 잡는 편이 좋을 것 같다. 이번 글은 아직 하나의 글로 마무리하기에는 준비가 덜 된 주제여서 많은 시간이 걸렸다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thompson-nfa-guhyeon-ihaehagi&quot;&gt;Thompson NFA 구현 이해하기&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;swtch.com&#x2F;~rsc&#x2F;regexp&#x2F;regexp1.html&quot;&gt;Regular Expression Matching Can Be Simple And Fast&lt;&#x2F;a&gt; (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rosettalens.com&#x2F;s&#x2F;ko&#x2F;regular-expression-matching-can-be-simple-and-fast&quot;&gt;한국어 번역&lt;&#x2F;a&gt;) 글을 보고 Python 코드로 바꿔가며 이해를 높이려고 했다.&lt;&#x2F;p&gt;
&lt;p&gt;정리한 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;426c651856dae8d57ce7907d90429c7d&quot;&gt;Gist 글&lt;&#x2F;a&gt;. AI를 쓰기도 했고, 실제로 여러 번 따라 쳐본 건 아니라 확실하게 이해했다고 하기엔 무리지만, 일단 이 정도면 충분한 것 같다.&lt;&#x2F;p&gt;
&lt;p&gt;정규표현식이 어떻게 오토마타로 구현되는지, 백트래킹 방식과 Thompson 알고리즘의 차이가 무엇인지 코드를 통해 이해할 수 있었다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-missing-semester-of-your-cs-education-gangyi-hagseub&quot;&gt;The Missing Semester of Your CS Education 강의 학습&lt;&#x2F;h3&gt;
&lt;p&gt;위에서 소개한 MIT 강의를 2020년 버전 위주로 영상과 스크립트를 훑어보았다. 깊이는 얕지만 무엇을 공부해야 할지 폭넓게 다뤄서 좋았다.
모르는 내용도 꽤 있었고, 2026년 강의에서 AI 관련 내용이 추가되는 것 같아 그것도 나중에 볼 예정이다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;c78182fd3ff0996ba34de41321c08ae0&quot;&gt;강의 노트&lt;&#x2F;a&gt;는 메모하고 AI로 내용 요약한 정도라 기억에 오래 남진 않을 것 같다.
필요할 때 찾아보는 정도로 쓸 듯.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;airo-tamsaeg-bidonggi-modelgwa-memori-gujo-jeongri&quot;&gt;AI로 탐색: 비동기 모델과 메모리 구조 정리&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;without.boats&#x2F;blog&#x2F;why-async-rust&#x2F;&quot;&gt;&quot;Why async Rust?&quot;&lt;&#x2F;a&gt;를 읽다가 궁금해진 부분을 파고들다 보니 비동기나 스레드의 메모리 위치에 대한 사실들을 알게 되었다.
Gist에 정리하였다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;973e406e46f0f7520ed883bb3b03aa0e&quot;&gt;Rust 비동기 실행 모델의 내부 원리&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;29d81bea78ab4c09a75027fd380f9cb6&quot;&gt;Linux 스레드와 메모리 구조&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;2f2ff6161078a7bfec57d95a689cb06a&quot;&gt;Stackful 비동기의 동작 방식 &amp;amp; 비동기 실행 모델의 분류&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;db-hubreul-sayonghan-mcp-server-sayong&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dbhub.ai&#x2F;&quot;&gt;DB Hub&lt;&#x2F;a&gt;를 사용한 MCP Server 사용&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;추가 — 2026&#x2F;02&#x2F;03&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;openai.com&#x2F;index&#x2F;introducing-the-codex-app&#x2F;&quot;&gt;어제(02&#x2F;02) OpenAI가 Mac용 Codex App을 출시했다.&lt;&#x2F;a&gt;
이를 활용하면 별도 채팅 UI를 구축할 필요가 없고, 인증&#x2F;설정에 필요한 env 기반 Bearer token과 Headers를 지원하므로 OAuth Provider 서버를 구축할 필요도 없어졌다.
key-value 기반의 액세스 키만 발급&#x2F;관리 기능만 만들면 가볍게 사용하기 충분하다.
가이드 문서를 제공하여 비개발 직군도 손쉽게 DB 분석 환경을 사용할 수 있게 되었다.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;추가 — 2026&#x2F;02&#x2F;12&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;최근에 MCP 서버를 공부하다가 알게 되었는데, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;agents&#x2F;guides&#x2F;remote-mcp-server&#x2F;&quot;&gt;OAuth Provider를 Auth0 같은 별도 서비스를 통해 직접 만들지 않고, mcp-auth-proxy와 같은 프록시를 사용하면 Github이나 Google 같은 외부 Provider를 사용해도 된다.&lt;&#x2F;a&gt;
Google 기반을 사용하면 조직 도메인 등으로 검증할 수 있어 세세한 권한 제어가 필요없는 작은 규모의 조직에서는 좋아보인다.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;회사에서 비개발 직군도 회사 DB에 접근할 수 있게 하는 것이 목적이었는데, 관리 비용과 보안 문제로 실패했다. 결국 몇몇 분에게만 VSCode + Codex 환경을 임시로 세팅해 드렸다.&lt;&#x2F;p&gt;
&lt;p&gt;대신 개발 쪽에서 아주 유용하게 쓰고 있다.&lt;&#x2F;p&gt;
&lt;p&gt;팁: 레거시로 인해 스키마&#x2F;컬럼명이 명확하지 않다면, Comment를 함께 전달하도록 tool을 작성하면 AI가 컨텍스트를 더 정확히 파악한다.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #383A42; background-color: #FAFAFA;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;문제 배경: 회사 DB 접근 MCP 서버를 비개발자도 안전하게 사용하게 하려면?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MCP 연동 방식별 특성:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - 로컬 개발 도구 (Codex, Claude Code 등): 로컬에서 직접 MCP 서버 호출 → IP 화이트리스트 적용 가능&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - 로컬 데스크톱 앱 (Claude 앱 등): 외부 MCP 서버 연결 기능 미지원&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  - 웹 서비스 (GPT, Claude 웹): AI 회사 서버 경유 → 우리 측 IP 제한 불가&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;선택지:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1. 외부 IP 노출 안 함&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   ├─ a. 로컬 개발 도구 사용 (Codex, Claude Code 등)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   │      → 문제: 비개발자 사용 어려움, UX 목적과 불일치&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   └─ b. 자체 중간 서버 구축 (LLM API + MCP 연동)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          → 문제: 별도 개발&#x2F;운영 필요&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  별도 채팅 UI&#x2F;서버 필요 (슬랙 연동 등으로 UI 대체가 가능하나 자유로운 대화가 제한)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  API Key 비용 발생&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          → 장점: IP 화이트리스트 유지 가능&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. 외부 IP 노출함&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   ├─ a. OAuth Provider 서버 구축 → 자체 인증&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   │      → 배경: 웹 환경의 Claude&#x2F;GPT MCP 커넥터는 OAuth 인증 외에 다른 인증은 지원하지 않음&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   │      → 문제: OAuth Provider 인프라 개발 필요&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   │      → 장점: GPT&#x2F;Claude 웹에서 바로 사용, UX 최적, 사용자 관리 가능(IP보다 세밀한 제어 가능)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   └─ b. 퍼블릭 개방&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          → 제외 (보안 불가)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;airo-inhan-hagseubgwa-seongjang-banghyangseonge-daehan-saenggag&quot;&gt;AI로 인한 학습과 성장 방향성에 대한 생각&lt;&#x2F;h3&gt;
&lt;p&gt;요즘 해커뉴스나 긱뉴스를 보면 AI와 개발자 커리어에 대한 글이 자주 올라온다.&lt;&#x2F;p&gt;
&lt;p&gt;극단적인 의견도 있지만, 대부분의 의견은 이렇다. AI로 인한 변화는 피할 수 없고, 시니어급 개발자들이 보기에도 기존 개발 작업 대다수를 대신할 수 있을 정도로 발전했다.&lt;&#x2F;p&gt;
&lt;p&gt;관련한 의견들을 보면서 정리한 생각은, 앞으로 주니어가 성장해야 할 방향에는 크게 3가지 능력이 필요하고 이를 키우기 위해 노력해야 한다는 것이다.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;올바른 의사결정을 위한 CS 및 기초 지식
&lt;ul&gt;
&lt;li&gt;기초 지식은 개발뿐 아니라 도메인도 해당될 수 있다. 다만 주니어에게 도메인까지 기대하긴 어렵다.&lt;&#x2F;li&gt;
&lt;li&gt;프레임워크 기반 개발을 하던 과거에도 기초 지식은 중요했다. AI 시대가 되어도 이건 바뀌지 않는다.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;AI 활용과 도구 선택 능력
&lt;ul&gt;
&lt;li&gt;AI를 적절한 영역에 사용하고, 자동화&#x2F;프롬프팅&#x2F;에이전트 활용을 통해 효과적으로 동작하게 하는 능력이 중요하다.&lt;&#x2F;li&gt;
&lt;li&gt;동시에 AI가 잘 못하는 부분은 다른 도구로 보완할 수 있어야 한다.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;넓은 범위의 학습&#x2F;적용 능력
&lt;ul&gt;
&lt;li&gt;T자 인재의 필요성은 여전하다. 과거에는 신입에게 하나를 제대로 하거나 기초만 있어도 충분했다.&lt;&#x2F;li&gt;
&lt;li&gt;그러나 AI로 인해 다른 영역으로 확장하기 쉬워졌으므로, 주니어도 그 능력을 키워야 한다.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;관련되서 이번 달에 보았던 글을 정리해두었다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;notes.eatonphil.com&#x2F;2026-01-19-llms-and-your-career.html&quot;&gt;LLMs and your career&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=26005&quot;&gt;GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;karpathy&#x2F;status&#x2F;2015883857489522876&quot;&gt;Andrej Karpathy(OpenAI 공동 창립자)의 Claude 코딩 경험&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=26183&quot;&gt;GeekNews&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=46771564&quot;&gt;HackerNews&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;antirez.com&#x2F;news&#x2F;158&quot;&gt;Don&#x27;t fall into the anti-AI hype - antirez(Redis 창시자)&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=46574276&quot;&gt;HackerNews&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;addyosmani.com&#x2F;blog&#x2F;next-two-years&#x2F;&quot;&gt;The Next Two Years of Software Engineering&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=25769&quot;&gt;GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.stdy.blog&#x2F;xp-tdd-and-vibe-coding-kent-beck-interview-with-programmatic-engineer&#x2F;&quot;&gt;XP, TDD, 그리고 바이브 코딩: Kent Beck(TDD&#x2F;XP 창시자)의 인터뷰 번역&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;jjalbeun-saenggag&quot;&gt;짧은 생각&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;근황과 요즘 하는 생각&lt;&#x2F;p&gt;
&lt;p&gt;요즘에 AI 활용을 더 적극적으로 시도해보려고 하고 있다.
세계 상위권 대학들이 AI 관련 내용을 커리큘럼에 빠르게 추가하는 걸 보면, 교육 현장에서도 이런 능력이 중요하다고 판단하는 것 같다.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>시간 데이터를 올바르게 다루는 방법</title>
          <pubDate>Mon, 12 Jan 2026 00:00:00 +0000</pubDate>
          <author>Sijun Yang</author>
          <link>https://sijun-yang.com/blog/how-to-handle-time-data/</link>
          <guid>https://sijun-yang.com/blog/how-to-handle-time-data/</guid>
          <description xml:base="https://sijun-yang.com/blog/how-to-handle-time-data/">&lt;p&gt;프로그래밍을 어느 정도 해봤다면, 시간 관련 버그를 한 번쯤은 겪거나 들어보았을 것이다.
서버 환경을 바꾸니 시간이 9시간 밀린다거나, 로컬에서는 잘 되던 게 배포만 하면 시간이 이상하게 보인다거나.&lt;&#x2F;p&gt;
&lt;p&gt;이런 버그가 종종 보이는 이유는 단순한 문자열&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;이나 정수형 타입과 다르게 시간 데이터의 다루는 데 생각보다 많은 주의사항이 존재하기 때문이다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;이 글에서는 시간 데이터의 두 가지 타입과 관련 문제들을 살펴본 뒤, 내가 사용하는 두 가지 원칙을 소개한다.
마지막으로 이 원칙에 영향을 준 JavaScript Temporal API를 간단히 다룬다.&lt;&#x2F;p&gt;
&lt;p&gt;익숙한 Java&#x2F;JavaScript 생태계를 중심으로 설명하지만, 모든 언어에 적용 가능하다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;siganyi-2gaji-taib&quot;&gt;시간의 2가지 타입&lt;&#x2F;h2&gt;
&lt;p&gt;시간 데이터는 크게 두 종류로 나눌 수 있다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Exact Time(물리적 순간)&lt;&#x2F;strong&gt;: 유일한 하나의 시점을 가리킨다.
&quot;2024-01-01T00:00:00+00:00&quot;는 전 세계 어디서든 같은 순간이다.
Unix timestamp나 UTC 오프셋을 포함한 ISO 8601 형식(예: 2024-01-01T00:00:00Z)이 여기에 해당한다.&lt;br &#x2F;&gt;
&lt;strong&gt;Wall-clock Time(벽시계 시간)&lt;&#x2F;strong&gt;: 특정 시점이 아니라 날짜와 시간 값 자체를 의미한다.
&quot;12월 25일&quot;은 뉴욕 시간이나 한국 시간처럼 특정 지역의 시간을 의미하지 않는다.&lt;&#x2F;p&gt;
&lt;p&gt;JavaScript의 Temporal API가 이 개념을 잘 설명해서, 이 글에서도 Temporal의 용어를 차용하여 설명한다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sigan-deiteoreul-darul-ddae-juyihaeya-hal-jeom&quot;&gt;시간 데이터를 다룰 때 주의해야 할 점&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;taimjon-jeongbo-sonsil&quot;&gt;타임존 정보 손실&lt;&#x2F;h3&gt;
&lt;p&gt;Java의 &lt;code&gt;LocalDateTime&lt;&#x2F;code&gt;은 &lt;code&gt;Local-&lt;&#x2F;code&gt;로 시작하는 이름에서 유추할 수 있듯이 타임존 정보를 저장하지 않는다.
하지만 &lt;code&gt;LocalDateTime.now()&lt;&#x2F;code&gt;를 호출하면 시스템의 기본 타임존을 사용해서 현재 시각을 가져온다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
Python의 &lt;code&gt;datetime.now()&lt;&#x2F;code&gt;나 C#의 &lt;code&gt;DateTime.Now&lt;&#x2F;code&gt;도 비슷하게 절대 시점을 저장하지 않는다.&lt;&#x2F;p&gt;
&lt;p&gt;이러한 함수를 보았을 때 타임존 변환이 일어났는지 알기 어렵다. 또한 내부 구현에서 타임존 정보를 유지하지 않는다.
객체 생성하는 도중 타임존을 사용해서 변환은 했지만, 결과 객체에선 어떤 타임존이었는지는 저장하지 않는 것이다.
그래서 이 값을 직렬화하거나 저장하면 어느 지역의 시간인지 알 수 없게 된다.
직렬화할 때 로컬의 시간대 정보를 함께 보내면 되지 않나 싶지만,
&lt;code&gt;now()&lt;&#x2F;code&gt; 호출 시 타임존을 직접 지정하는 것도 가능하기 때문에 선언 시점을 제외하면 어떤 타임존이었는지 알 방법이 없다.&lt;&#x2F;p&gt;
&lt;p&gt;특히 요즘의 서비스에선 아주 많은 &quot;로컬&quot;이 존재할 수 있다.
클라이언트와 서버만 있는 간단한 웹 서비스도 2개의 노드가 존재한다.
MSA 서비스라면 LB, DB, Redis, 모니터링 등 서버만 수십 개가 넘어갈 수도 있다.
이때 타임존 없는 시간 문자열을 주고받으면, 원래 어떤 타임존이었는지 복구할 방법이 없다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;yeoreo-gisulyi-hamjeong&quot;&gt;여러 기술의 함정&lt;&#x2F;h3&gt;
&lt;p&gt;다양한 기술 스택에서 타임존 처리와 관련된 함정들이 존재한다.
직렬화 라이브러리, ORM, DB 등에서 타임존 관련 기본 설정이나 옵션이 직관적이지 않아 의도하지 않은 동작을 유발할 수 있다.
몇가지 예시를 살펴보자.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;jackson&quot;&gt;Jackson&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;code&gt;DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-4-1&quot;&gt;&lt;a href=&quot;#fn-4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;은 기본적으로 true로 설정되어 있는데,
이 옵션이 활성화되어 있으면 &lt;code&gt;ZonedDateTime&lt;&#x2F;code&gt;이나 &lt;code&gt;OffsetDateTime&lt;&#x2F;code&gt;을 역직렬화할 때 원본 타임존을 컨텍스트 타임존(기본값 UTC)으로 변환한다.
이 과정에서 시점 정보는 유지되지만, 원래 타임존 정보를 잃어버린다 (이 옵션은 Jackson 3버전 부터 &lt;code&gt;DateTimeFeature&lt;&#x2F;code&gt; 객체로 이관되었다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-5-1&quot;&gt;&lt;a href=&quot;#fn-5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;ansi-sqlyi-timestamp-with-time-zone&quot;&gt;ANSI SQL의 TIMESTAMP WITH TIME ZONE&lt;&#x2F;h4&gt;
&lt;p&gt;ANSI SQL 표준의 &lt;code&gt;TIMESTAMP WITH TIME ZONE&lt;&#x2F;code&gt; 데이터 타입은 이름과 달리 타임존 정보를 유지해야 한다는 요구사항이 없다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-6-1&quot;&gt;&lt;a href=&quot;#fn-6&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
그래서 Oracle의 경우 타임존 정보를 저장하는 반면, PostgreSQL은 타임존 정보를 저장하지 않는 등 제각각의 구현이 존재한다.&lt;&#x2F;p&gt;
&lt;p&gt;PostgreSQL을 자세하게 설명해보자면,
데이터 타입 &lt;code&gt;timestamp&lt;&#x2F;code&gt;(&lt;code&gt;timestamp without time zone&lt;&#x2F;code&gt;)는 문자열로 Wall-clock Time 정보를 저장한다. 그래서 시간 비교 등의 연산에서 취약하다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-7-1&quot;&gt;&lt;a href=&quot;#fn-7&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
Exact Time을 저장하려면 &lt;code&gt;timestamptz&lt;&#x2F;code&gt;(&lt;code&gt;timestamp with time zone&lt;&#x2F;code&gt;)를 사용해야 하는데, UTC로 변환되어 저장되고 타임존 정보는 유지되지 않는다.
또한 조회 시 세션의 타임존에 의존하여 시간 결과를 반환한다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;jpawa-hibernate&quot;&gt;JPA와 Hibernate&lt;&#x2F;h4&gt;
&lt;p&gt;Hibernate는 6.0 이후부터 &lt;code&gt;LocalDateTime&lt;&#x2F;code&gt;은 &lt;code&gt;TIMESTAMP&lt;&#x2F;code&gt;, &lt;code&gt;Instant&lt;&#x2F;code&gt;는 &lt;code&gt;TIMESTAMP_UTC&lt;&#x2F;code&gt;로 매핑된다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-8-1&quot;&gt;&lt;a href=&quot;#fn-8&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
&lt;code&gt;TIMESTAMP_UTC&lt;&#x2F;code&gt;는 저장 시 값을 UTC로 정규화하지만, &lt;code&gt;TIMESTAMP&lt;&#x2F;code&gt;는 변환 없이 그대로 저장된다.
즉, 두 타입을 Exact Time 표현용과 Wall-clock Time 표현용으로 구분하고 있다.&lt;&#x2F;p&gt;
&lt;p&gt;Hibernate는 &lt;code&gt;LocalDateTime&lt;&#x2F;code&gt;을 DB에 저장할 때 JVM 기본 타임존을 기준으로 &lt;code&gt;java.sql.Timestamp&lt;&#x2F;code&gt;로 변환한 뒤 UTC로 정규화한다.
이 과정에서 원본 타임존 정보가 사라진다.
여러 DB 접근 라이브러리를 함께 사용하는 환경에서는 각 라이브러리의 타임존 설정 차이로 인해 시간 오차가 발생할 수 있다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-9-1&quot;&gt;&lt;a href=&quot;#fn-9&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Spring Data 개발자 Jens Schauder 역시 &lt;code&gt;LocalDateTime&lt;&#x2F;code&gt;은 타임라인 상의 특정 순간을 표현할 수 없으므로 &lt;code&gt;Instant&lt;&#x2F;code&gt;를 사용하는 것이 바람직하다고 설명한다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-10-1&quot;&gt;&lt;a href=&quot;#fn-10&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;그럼에도 불구하고 많은 코드에서 여전히 Exact Time 데이터를 &lt;code&gt;LocalDateTime&lt;&#x2F;code&gt;으로 선언해 사용하고 있다
(예: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;team-dodn&#x2F;spring-boot-java-template&#x2F;blob&#x2F;750675f8bb7bc97b644e18576a5b26148ac65e17&#x2F;storage&#x2F;db-core&#x2F;src&#x2F;main&#x2F;java&#x2F;io&#x2F;dodn&#x2F;springboot&#x2F;storage&#x2F;db&#x2F;core&#x2F;BaseEntity.java&quot;&gt;spring-boot-java-template BaseEntity의 createdAt, updatedAt&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sigan-deiteoreul-daruneun-2gaji-weoncig&quot;&gt;시간 데이터를 다루는 2가지 원칙&lt;&#x2F;h2&gt;
&lt;p&gt;나는 시간 데이터를 다룰 때 두 가지 원칙을 기준으로 삼고 있다.&lt;&#x2F;p&gt;
&lt;p&gt;이걸 꼭 따라야 한다는 말은 아니다.
하지만 &quot;모든 노드(클라이언트, 서버, DB, 캐시 등)에서 시간 데이터에 대한 해석이 일관되어야 한다.&quot;는 조건을 만족하려면 이 원칙과 비슷한 결론에 도달할 것이다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;weoncig-1-exact-timegwa-wall-clock-timeeul-myeonghwaghi-gubunhara&quot;&gt;원칙 1: Exact Time과 Wall-clock Time을 명확히 구분하라&lt;&#x2F;h3&gt;
&lt;p&gt;시간 데이터가 특정 시점을 나타내는지, 아니면 단순한 날짜&#x2F;시간 값인지 먼저 판단해야 한다.&lt;&#x2F;p&gt;
&lt;p&gt;로그 타임스탬프, 결제 완료 시각, 이벤트 발생 시각처럼 &quot;언제 일어났는가&quot;가 중요한 데이터는 Exact Time으로 저장한다.
Exact Time이 아니면 정확한 시점을 알 수 없기 때문이다.
&lt;code&gt;LocalDateTime.now()&lt;&#x2F;code&gt;처럼 타임존 정보가 사라지는 방식으로 저장하면, 나중에 원래 시점을 복구할 방법이 없다.&lt;&#x2F;p&gt;
&lt;p&gt;생일, 기념일, 공휴일처럼 특정 시점이라는 개념 자체가 없는 데이터는 Wall-clock Time으로 저장해서 날짜&#x2F;시간 값 자체만 저장한다.
이런 데이터를 Exact Time으로 다루면 오히려 문제가 생길 수 있다.&lt;&#x2F;p&gt;
&lt;p&gt;단, 이 기준은 도메인에 따라 달라진다.
산부인과 병원 시스템이라면 출생아의 생일이 출생 시점(Exact Time)으로 관리되어야 할 수 있다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;jeojang-pomaes&quot;&gt;저장 포맷&lt;&#x2F;h4&gt;
&lt;p&gt;각 타입에 적합한 저장 포맷을 사용해야 한다.&lt;&#x2F;p&gt;
&lt;p&gt;Exact Time:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Unix timestamp (밀리초 또는 초 단위 정수)&lt;&#x2F;li&gt;
&lt;li&gt;PostgreSQL의 &lt;code&gt;TIMESTAMPTZ&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;ISO 8601 with offset (예: &lt;code&gt;2024-01-01T00:00:00Z&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Wall-clock Time:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DATE&lt;&#x2F;code&gt; 타입 (예: &lt;code&gt;2024-12-25&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;TIME&lt;&#x2F;code&gt; 타입 (예: &lt;code&gt;14:30:00&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;문자열 (예: &lt;code&gt;&quot;2024-12-25&quot;&lt;&#x2F;code&gt;, &lt;code&gt;&quot;14:30&quot;&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;taib-gaegce-seoneon-sijeom-juyisahang&quot;&gt;타입 객체 선언 시점 주의사항&lt;&#x2F;h4&gt;
&lt;p&gt;대부분의 시간 관련 버그는 코드에서 시간 타입을 생성할 때 발생하므로 주의 깊게 보아야 한다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Exact Time이 필요한 곳에서 &lt;code&gt;LocalDateTime.now()&lt;&#x2F;code&gt;를 쓰고 있지는 않은지 확인한다.
&lt;code&gt;Instant.now()&lt;&#x2F;code&gt; 또는 &lt;code&gt;System.currentTimeMillis()&lt;&#x2F;code&gt;를 사용해야 한다.&lt;&#x2F;li&gt;
&lt;li&gt;Wall-clock Time이 필요한 곳에서 UTC 변환을 하고 있지는 않은지 확인한다.
&lt;code&gt;LocalDate.of(2024, 12, 25)&lt;&#x2F;code&gt;처럼 날짜 값 자체만 저장해야 한다.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;weoncig-2-exact-timeeun-utcro-jeojanghago-taimjoneun-byeoldo-gwanrihara&quot;&gt;원칙 2: Exact Time은 UTC로 저장하고, 타임존은 별도 관리하라&lt;&#x2F;h3&gt;
&lt;p&gt;Exact Time 데이터는 저장, 직렬화&#x2F;역직렬화, 송수신 등 모든 과정에서 UTC 또는 Unix timestamp로 처리한다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;taimjoni-pilyohan-gyeongu&quot;&gt;타임존이 필요한 경우&lt;&#x2F;h4&gt;
&lt;p&gt;비행기 출발 시각, 회의 시간처럼 특정 지역의 시간 표현이 필요한 경우에는 Exact Time과 타임존을 별도 필드로 관리한다.&lt;&#x2F;p&gt;
&lt;p&gt;내부적으로는 UTC(Unix timestamp)로 저장하고, 사용자에게 보여줄 때만 해당 타임존으로 변환한다.&lt;&#x2F;p&gt;
&lt;p&gt;이렇게 하면 시간 비교나 집계 등의 계산이 편리해진다. 저장된 값 자체가 바뀌지 않기 때문이다.
앞서 말했듯 타임존 타입의 지원이 아직 완전하지 않거나 주의해야 하는 시스템이 존재하기 때문에&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-11-1&quot;&gt;&lt;a href=&quot;#fn-11&quot;&gt;11&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;,
모든 곳에서 타임존을 UTC로 고정하거나 타임존 정보가 없는 Exact Time인 Unix timestamp 형태로 관리하는 것이 안전하다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;jeonsong-jeojang-sijeom-juyisahang&quot;&gt;전송&#x2F;저장 시점 주의사항&lt;&#x2F;h4&gt;
&lt;p&gt;DB 저장, API 직렬화 등의 과정에서 정보가 손실되는지 확인해야 한다.
명시적인 포맷이나 타입 계약이 없다면, 동일한 값이라도 시스템마다 다르게 해석될 수 있다.&lt;&#x2F;p&gt;
&lt;p&gt;DB 데이터 타입, gRPC 같은 스키마 기반 통신 처럼 포맷(타입) 계약이 존재하면 이를 그대로 따른다.&lt;br &#x2F;&gt;
JSON이나 텍스트 기반 통신처럼 계약이 없거나 범용 포맷이 필요한 경우,
Unix timestamp 또는 UTC 오프셋을 포함한 ISO 8601을 사용한다.&lt;&#x2F;p&gt;
&lt;p&gt;ISO 8601는 가독성이 높고, 대부분의 직렬화 라이브러리에서 기본 지원된다.
Unix timestamp는 숫자 자체가 절대 시각이므로 해석 오류 여지가 없고, 저장 공간도 적다.
다만 자동 변환을 지원하지 않는 환경에서는 추가 처리가 필요하다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;dstwa-jeongcaeg-byeongyeong-daeeung&quot;&gt;DST와 정책 변경 대응&lt;&#x2F;h4&gt;
&lt;p&gt;타임존과 시간대 정보가 포함된 데이터를 다루는 경우, 여러 가지 모호한 상황(Ambiguity)이 발생할 수 있다.
이와 관련된 구체적인 예시는 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tc39.es&#x2F;proposal-temporal&#x2F;docs&#x2F;timezone.html&quot;&gt;&quot;Temporal Time Zones and Resolving Ambiguity - Temporal Proposal Documentation&quot;&lt;&#x2F;a&gt;에서 찾을 수 있다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-12-1&quot;&gt;&lt;a href=&quot;#fn-12&quot;&gt;12&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;DST 시작&#x2F;종료 같은 일시적 Offset 이동으로 인해서 동일한 벽시계 시간이 두 번 발생(fall back)하거나 존재하지 않는 시간(spring forward)이 생길 수 있다.&lt;&#x2F;li&gt;
&lt;li&gt;정책 변경으로 TimeZone 정의가 변경되어 기존에 저장된 미래 시점의 값과 새로운 규칙 간 충돌이 발생할 수 있다.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;지금 설명중인 2가지 원칙들을 따르면 이러한 문제 대부분을 피할 수 있다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;UTC로 저장하면 DST 영향을 받지 않는다. DST는 특정 타임존의 오프셋이 변경되는 것이지, UTC 자체가 바뀌는 것이 아니기 때문이다.&lt;&#x2F;li&gt;
&lt;li&gt;타임존 ID를 별도 필드로 저장하면 정책 변경 시에도 올바른 현지 시간을 계산할 수 있다. IANA 타임존 데이터베이스가 업데이트되면 새로운 규칙이 자동으로 적용된다.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;temporal-api-sogae&quot;&gt;Temporal API 소개&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;yeogsajeog-baegyeong&quot;&gt;역사적 배경&lt;&#x2F;h3&gt;
&lt;p&gt;1996년 Java 1.0에서 &lt;code&gt;java.util.Date&lt;&#x2F;code&gt;가 도입됐다.
이는 많은 문제가 있는 구현이였는데, 월이 0부터 시작하고 연도는 1900을 빼서 저장하고 객체가 mutable해서 언제든 값이 바뀔 수 있었다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-13-1&quot;&gt;&lt;a href=&quot;#fn-13&quot;&gt;13&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;JavaScript가 만들어질 때, Java의 Date 구현을 거의 그대로 가져왔다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-14-1&quot;&gt;&lt;a href=&quot;#fn-14&quot;&gt;14&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
Java는 이후 개선을 시도한 반면, Date는 거의 30년이 지난 지금까지 사용되고 있다. (그래서 프로덕션 환경에선 별도의 시간 라이브러리를 많이 쓴다.)&lt;&#x2F;p&gt;
&lt;p&gt;2002년 Stephen Colebourne이 Java Date의 문제를 보완한 Joda-Time 라이브러리를 만들었다.
Joda-Time은 큰 성공을 거뒀고, 2014년 Java 8의 공식 &lt;code&gt;java.time&lt;&#x2F;code&gt; 패키지(JSR-310)로 이어졌다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-15-1&quot;&gt;&lt;a href=&quot;#fn-15&quot;&gt;15&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;JavaScript에서는 Date의 문제를 해결하기 위해 Temporal API 제안이 진행되었고,
TC39(ECMAScript 기술위원회)에서 이 제안은 Stage 3(명세가 확정되어 구현을 진행) 상태에 있다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;temporalyi-seolgye&quot;&gt;Temporal의 설계&lt;&#x2F;h3&gt;
&lt;p&gt;Temporal은 Exact Time과 Wall-clock Time의 구분을 타입 시스템에서 강제한다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;temporal-object-model.svg&quot; alt=&quot;Temporal Object Model&quot; &#x2F;&gt;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tc39.es&#x2F;proposal-temporal&#x2F;docs&#x2F;object-model.svg&quot;&gt;원본 링크&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;위 다이어그램에서 왼쪽은 Exact Time(물리적 순간)을 아는 타입들이고, 오른쪽은 Wall-clock Time(벽시계 시간)을 아는 타입들이다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Temporal.Instant&lt;&#x2F;code&gt;는 물리적 순간만 표현한다. 타임존이나 캘린더 없이 절대 시점만 저장한다.
&lt;code&gt;Temporal.ZonedDateTime&lt;&#x2F;code&gt;은 물리적 순간에 타임존과 캘린더를 더해서 양쪽에 걸쳐 있다.
반면 &lt;code&gt;Plain-&lt;&#x2F;code&gt; 접두사가 붙은 타입들(&lt;code&gt;PlainDateTime&lt;&#x2F;code&gt;, &lt;code&gt;PlainDate&lt;&#x2F;code&gt;, &lt;code&gt;PlainTime&lt;&#x2F;code&gt; 등)은 타임존 정보가 없다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;temporal-persistence-model.svg&quot; alt=&quot;Temporal Persistence Model&quot; &#x2F;&gt;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tc39.es&#x2F;proposal-temporal&#x2F;docs&#x2F;persistence-model.svg&quot;&gt;원본 링크&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;이 다이어그램은 각 타입이 문자열로 직렬화될 때 어떤 정보가 포함되는지 보여준다.
&lt;code&gt;Instant&lt;&#x2F;code&gt;는 UTC 시간만, &lt;code&gt;ZonedDateTime&lt;&#x2F;code&gt;은 오프셋과 타임존 ID까지, &lt;code&gt;Plain&lt;&#x2F;code&gt; 타입들은 날짜&#x2F;시간 정보만 포함된다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;plain-vs-local&quot;&gt;Plain vs Local&lt;&#x2F;h3&gt;
&lt;p&gt;여기서 &quot;Plain&quot;이라는 네이밍이 중요하다. java.time의 &quot;Local&quot;은 이름에서 위치를 암시하지만, &quot;Plain&quot;은 타임존에 대한 어떤 가정도 없다는 것을 명확히 보여준다.
단순하게 날짜와 시간 값 자체만을 표현한다는 의미가 더 직관적으로 드러난다. Temporal의 설계자들 역시 이러한 의도를 가지고 Plain이라는 이름을 선택했다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-16-1&quot;&gt;&lt;a href=&quot;#fn-16&quot;&gt;16&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-17-1&quot;&gt;&lt;a href=&quot;#fn-17&quot;&gt;17&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;temporal-nowyi-bunri&quot;&gt;Temporal.Now의 분리&lt;&#x2F;h3&gt;
&lt;p&gt;Temporal은 &quot;now&quot;를 다루는 방식이 기존의 일반적인 라이브러리와 다르다.
&lt;code&gt;Temporal.Now&lt;&#x2F;code&gt;라는 별도 객체가 존재해서, &lt;code&gt;Temporal.Now.instant()&lt;&#x2F;code&gt;나 &lt;code&gt;Temporal.Now.plainDateTimeISO()&lt;&#x2F;code&gt; 같은 형태로 사용한다.
현재 시각 조회를 별도 API로 분리해서 타임존 정보 손실이 발생할 수 있다는 것을 API 표면에서 명확하게 알려준다.
반면 java.time에서는 &lt;code&gt;LocalDateTime.now()&lt;&#x2F;code&gt;처럼 각 타입에 now 메서드가 붙어 있어 정보 손실이 발생 가능하다는 것이 명확하지 않다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;aemaemohohan-sanghwang-ceori&quot;&gt;애매모호한 상황 처리&lt;&#x2F;h3&gt;
&lt;p&gt;Temporal은 Plain 타입에서 Exact 타입으로 변환할 때 발생하는 모호함을 다루는 방법을 개발자가 선택할 수 있게 한다&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-12-2&quot;&gt;&lt;a href=&quot;#fn-12&quot;&gt;12&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;앞서 제시한 원칙을 따르면 이런 기능이 필요한 상황 자체가 드물어진다.
다만 레거시 데이터 마이그레이션이나 사용자 입력 처리 같은 예외 상황에서는 유용하므로, 어떤 옵션을 제공하는지 알아두면 좋다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;사실 문자열도 그렇게 단순하지는 않다. 유니코드, 인코딩, 정규화 등 고려해야 할 사항이 많다. 이와 관련해서는 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tonsky.me&#x2F;blog&#x2F;unicode&#x2F;&quot;&gt;The Absolute Minimum Every Software Developer Must Know About Unicode in 2023&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;utf8everywhere.org&#x2F;#&quot;&gt;UTF-8 Everywhere&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;yozm.wishket.com&#x2F;magazine&#x2F;detail&#x2F;2836&#x2F;&quot;&gt;아�니 이 글자 왜 들어간 거예요?&lt;&#x2F;a&gt; 같은 글을 읽어보는 걸 추천한다. &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;여기서 다루는 내용과 별개지만, 시간 데이터의 정확성 자체도 완벽하지 않다. 분산 시스템에서 &quot;정확한 시간&quot;을 정의하는 것 자체가 매우 어려운 문제다. 이와 관련해서는 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dataintensive.net&#x2F;&quot;&gt;&quot;Designing Data-Intensive Applications&quot;&lt;&#x2F;a&gt;, Chapter 8: &#x27;Unreliable Clocks&#x27;를 읽어보는 것을 추천한다. &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;OpenJDK, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;openjdk&#x2F;jdk&#x2F;blob&#x2F;jdk-27%2B3&#x2F;src&#x2F;java.base&#x2F;share&#x2F;classes&#x2F;java&#x2F;time&#x2F;LocalDateTime.java#L213&quot;&gt;&quot;LocalDateTime.java source code&quot;&lt;&#x2F;a&gt;, GitHub. &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-4&quot;&gt;
&lt;p&gt;Jackson, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fasterxml.github.io&#x2F;jackson-databind&#x2F;javadoc&#x2F;2.6&#x2F;com&#x2F;fasterxml&#x2F;jackson&#x2F;databind&#x2F;DeserializationFeature.html&quot;&gt;&quot;DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE&quot;&lt;&#x2F;a&gt;, JavaDoc. &lt;a href=&quot;#fr-4-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-5&quot;&gt;
&lt;p&gt;Jackson 3.0.3, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;javadoc.io&#x2F;doc&#x2F;tools.jackson.core&#x2F;jackson-databind&#x2F;latest&#x2F;tools.jackson.databind&#x2F;tools&#x2F;jackson&#x2F;databind&#x2F;cfg&#x2F;DateTimeFeature.html&quot;&gt;&quot;DateTimeFeature&quot;&lt;&#x2F;a&gt;, JavaDoc. &lt;a href=&quot;#fr-5-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-6&quot;&gt;
&lt;p&gt;SQL-92 Standard, Section 4.5 &quot;Datetimes and intervals&quot; - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;modern-sql.com&#x2F;standard&quot;&gt;Modern SQL&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.contrib.andrew.cmu.edu&#x2F;~shadow&#x2F;sql&#x2F;sql1992.txt&quot;&gt;Full Draft&lt;&#x2F;a&gt;. &lt;a href=&quot;#fr-6-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-7&quot;&gt;
&lt;p&gt;PostgreSQL Wiki, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.postgresql.org&#x2F;wiki&#x2F;Don&amp;#x27;t_Do_This#Don&amp;#x27;t_use_timestamp_(without_time_zone)_to_store_UTC_times&quot;&gt;&quot;Don&#x27;t Do This&quot;&lt;&#x2F;a&gt;. &lt;a href=&quot;#fr-7-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-8&quot;&gt;
&lt;p&gt;Hibernate ORM, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hibernate&#x2F;hibernate-orm&#x2F;blob&#x2F;6.0&#x2F;migration-guide.adoc#instant-mapping-changes&quot;&gt;&quot;Instant mapping changes&quot;&lt;&#x2F;a&gt;, Migration Guide, Version 6.0. &lt;a href=&quot;#fr-8-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-9&quot;&gt;
&lt;p&gt;jOOQ GitHub, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jOOQ&#x2F;jOOQ&#x2F;issues&#x2F;11753&quot;&gt;&quot;LocalDateTime param binding handled differently by hibernate&quot;&lt;&#x2F;a&gt;, Issue #11753, 2021. &lt;a href=&quot;#fr-9-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-10&quot;&gt;
&lt;p&gt;Jens Schauder, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.schauderhaft.de&#x2F;2018&#x2F;03&#x2F;14&#x2F;dont-use-localdatetime&#x2F;&quot;&gt;&quot;Don&#x27;t use LocalDateTime&quot;&lt;&#x2F;a&gt;, Schauderhaft Blog, 2018. &lt;a href=&quot;#fr-10-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-11&quot;&gt;
&lt;p&gt;Hibernate ORM Discussion, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hibernate&#x2F;hibernate-orm&#x2F;discussions&#x2F;4201#discussioncomment-1291666&quot;&gt;&quot;Support timestamp with timezone&#x2F;offset&quot;&lt;&#x2F;a&gt;, GitHub. &lt;a href=&quot;#fr-11-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-12&quot;&gt;
&lt;p&gt;TC39, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;tc39.es&#x2F;proposal-temporal&#x2F;docs&#x2F;timezone.html&quot;&gt;&quot;Temporal Time Zones and Resolving Ambiguity&quot;&lt;&#x2F;a&gt;, Temporal Proposal Documentation. &lt;a href=&quot;#fr-12-1&quot;&gt;↩&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-12-2&quot;&gt;↩2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-13&quot;&gt;
&lt;p&gt;Oracle, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;tutorial&#x2F;datetime&#x2F;iso&#x2F;legacy.html&quot;&gt;&quot;Legacy Date-Time Code&quot;&lt;&#x2F;a&gt;, The Java Tutorials. &lt;a href=&quot;#fr-13-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-14&quot;&gt;
&lt;p&gt;Allen Wirfs-Brock, Brendan Eich, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;10.1145&#x2F;3386327&quot;&gt;&quot;JavaScript: The First 20 Years&quot;&lt;&#x2F;a&gt;, Proceedings of the ACM on Programming Languages, Volume 4, June 2020 (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;js-history.vercel.app&#x2F;&quot;&gt;비공식 한국어 번역&lt;&#x2F;a&gt;). &lt;a href=&quot;#fr-14-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-15&quot;&gt;
&lt;p&gt;Oracle, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;8&#x2F;docs&#x2F;technotes&#x2F;guides&#x2F;datetime&#x2F;index.html&quot;&gt;&quot;Java Date Time APIs&quot;&lt;&#x2F;a&gt;, Java Platform, Standard Edition 8; JSR 310 Expert Group, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jcp.org&#x2F;en&#x2F;jsr&#x2F;detail?id=310&quot;&gt;&quot;JSR 310: Date and Time API&quot;&lt;&#x2F;a&gt;, Java Community Process. &lt;a href=&quot;#fr-15-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-16&quot;&gt;
&lt;p&gt;TC39 Temporal Proposal, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tc39&#x2F;proposal-temporal&#x2F;issues&#x2F;707&quot;&gt;&quot;What should be the long-term name of LocalDateTime?&quot;&lt;&#x2F;a&gt;, GitHub Issue #707. &lt;a href=&quot;#fr-16-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-17&quot;&gt;
&lt;p&gt;여러 시간 라이브러리에서 사용되는 &lt;code&gt;Local-&lt;&#x2F;code&gt; 네이밍은 C언어의 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;c&#x2F;chrono&#x2F;localtime.html&quot;&gt;&lt;code&gt;localtime()&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 함수에서 유래했을 것으로 추측한다. 표준처럼 굳어진 용어를 바꾸자는 주장에 마냥 동의하지는 않지만, &lt;code&gt;Local-&lt;&#x2F;code&gt;의 의미가 명확하지 않은 것은 사실이라 이 경우에는 이름을 바꾸는 결정이 합리적이라고 본다. &lt;a href=&quot;#fr-17-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</description>
      </item>
      <item>
          <title>[월간 기록] 2025년 12월</title>
          <pubDate>Wed, 31 Dec 2025 00:00:00 +0000</pubDate>
          <author>Sijun Yang</author>
          <link>https://sijun-yang.com/blog/monthly-log-2025-12/</link>
          <guid>https://sijun-yang.com/blog/monthly-log-2025-12/</guid>
          <description xml:base="https://sijun-yang.com/blog/monthly-log-2025-12/">&lt;p&gt;RDB 기반 큐로 회사 내부에 문제 많던 코드를 개선했는데, 만족스러운 경험이였다.
나중에 기회가 되면 다뤄볼까 한다. 또한 새로운 블로그 글도 작성했는데, 이 두 작업에 이번 달의 대부분을 투자했다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sujib&quot;&gt;수집&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;흥미롭거나 유용했던 자료들&lt;&#x2F;p&gt;&lt;h3 id=&quot;lobsters-haekeonyuseuwa-biseushajiman-codaejero-unyeongdoeneun-keomyuniti-geeknews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;&quot;&gt;Lobsters - 해커뉴스와 비슷하지만 초대제로 운영되는 커뮤니티&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=12178&quot;&gt;GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;기본적으로 해커뉴스를 더 많이 보긴 하는데, 여기에도 재미있거나 유익한 내용이 많다.
업로드 가능한 사람이 제한적이라 그런지 올라오는 글이 해커뉴스와 잘 겹치지 않는 것 같다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sqliteneun-eoddeohge-teseuteudoeneunga-geeknews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sqlite.org&#x2F;testing.html&quot;&gt;SQLite는 어떻게 테스트되는가&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=25168&quot;&gt;GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;SQLite의 테스트 방법론에 대한 공식 문서이다.&lt;&#x2F;p&gt;
&lt;p&gt;SQLite가 최근 서버 쪽에서도 사용하자는 의견이 종종 보여서 찾아보다가 알게 되었다.
로컬에서 돌려도 될 만큼 가볍고, 생각보다 높은 성능과, 수많은 기기에서 쓰일만큼 높은 신뢰도가 마음에 든다.&lt;&#x2F;p&gt;
&lt;p&gt;토이프로젝트에서 서버를 만들어야 한다면 Rust, SQLite를 사용해 만들어보고 싶다는 생각을 하고 있다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=4558&quot;&gt;SQLite의 알려지지 않은 이야기 | GeekNews&lt;&#x2F;a&gt;나 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sqlite.org&#x2F;qmplan.html&quot;&gt;Quality Management&lt;&#x2F;a&gt;도 함께 보면 좋다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;wide-events-rogingyi-saeroun-paereodaim&quot;&gt;Wide Events: 로깅의 새로운 패러다임&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=25239&quot;&gt;Wide Events 소개 | GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;loggingsucks.com&#x2F;&quot;&gt;Logging Sucks - Wide Events 공식 사이트&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=46346796&quot;&gt;HackerNews 토론&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;기존 로깅 방식의 근본적인 문제를 해결하려는 새로운 접근법. 요청당 수십 줄의 분산된 로그 대신, 하나의 포괄적인 구조화된 이벤트를 발행하자는 의견이다.&lt;&#x2F;p&gt;
&lt;p&gt;공감하는 사람들도 많을거라 생각하는데, 서비스의 로그를 분석하다 보면 불편한 상황이 많이 생긴다.
필요한 정보를 주는 로깅이 없다거나, 연결된 로그를 찾기 어렵다거나 등등.&lt;&#x2F;p&gt;
&lt;p&gt;실제 운영을 통한 평가를 받아봐야 확실해지겠지만, 이 기법을 사용한다면 문제 해결이 쉬워지지 않을까 싶다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;nanali-baljeonhagopeun-gaebaljareul-wihan-ai-hwalyongbeob&quot;&gt;나날이 발전하고픈 개발자를 위한 AI 활용법&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;drive.google.com&#x2F;file&#x2F;d&#x2F;1h99VB5Ra5nn78ZpcXzvN8HyJbSmcX-Qn&#x2F;view&quot;&gt;발표 자료 (PDF)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;CAgn60EWDmw?si=IwQRUollHuL11TxA&quot;&gt;유튜브 영상&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;lucas_flatwhite&#x2F;status&#x2F;1962061940815257606&quot;&gt;X&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;관심 가는 거만 메모했다. 빠진부분이 많다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;조언
&lt;ul&gt;
&lt;li&gt;AI는 변화가 빨라서 몇 개월만 지나도 지식이 outdated됨&lt;&#x2F;li&gt;
&lt;li&gt;학습 모드(Study Mode) 등 LLM이 제공하는 새로운 기능들을 시도해봐야 함&lt;&#x2F;li&gt;
&lt;li&gt;여전히 가장 중요한 인사이트(고객, 지식)는 사람으로부터 나온다&lt;&#x2F;li&gt;
&lt;li&gt;AI 관련 무료 공식 자료가 풍부함: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;build-with-claude&#x2F;prompt-engineering&#x2F;overview&quot;&gt;Anthropic Prompt Engineering&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ai.google.dev&#x2F;gemini-api&#x2F;docs&#x2F;prompting-strategies&quot;&gt;Google Prompt Engineering&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;platform.openai.com&#x2F;docs&#x2F;guides&#x2F;prompt-engineering&quot;&gt;OpenAI Prompt Engineering Guide&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;anthropics&#x2F;courses&quot;&gt;Anthropic Courses&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.deeplearning.ai&#x2F;&quot;&gt;deeplearning.ai&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;(메모: 요즘엔 Vercel의 React 프롬프트, Supabase의 PostgreSQL 프롬프트 같이 프롬프트 공유도 많이 하는 듯)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;코딩 관점
&lt;ul&gt;
&lt;li&gt;What + Why를 효과적으로 주는 프롬프팅: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;spilist.notion.site&#x2F;R-STICC-ce9f791017f34f57bfb0a870f2601b57&quot;&gt;STICC&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;여전히 일부 분야에서 How가 필요: CTA(Cognitive Task Analysis, 인지 작업 분석)필요. AI와 반복적인 학습을 통한 이해. AI가 메타 평가.&lt;&#x2F;li&gt;
&lt;li&gt;MCP는 다양한 기능이 있지만 대부분 툴 기능만 사용됨, 켰다 껐다 가능하므로 필요할때만 써서 토큰 아끼기&lt;&#x2F;li&gt;
&lt;li&gt;정적 타입 검사, 린터 등 Validator 활용하기, AI보다 정확함: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;wiki.g15e.com&#x2F;pages&#x2F;Source%20code%20quality%20in%20the%20AI%20era&quot;&gt;AI 시대의 소스코드 품질&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.stdy.blog&#x2F;tag&#x2F;meeting-debugging-experts-kr&#x2F;&quot;&gt;디버깅 마인드셋&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.stdy.blog&#x2F;infcon-2024-debugging-mindset&#x2F;&quot;&gt;인프콘 2014 발표&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Kent Beck의 TDD와 AI 관련 내용: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.stdy.blog&#x2F;xp-tdd-and-vibe-coding-kent-beck-interview-with-programmatic-engineer&#x2F;&quot;&gt;XP, TDD, 그리고 바이브 코딩: Kent Beck의 Programmatic Engineer 인터뷰 일부 번역&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;제품 개발 관점
&lt;ul&gt;
&lt;li&gt;문제 정의(누구를 위해, 왜, 무엇을)에서부터 시작함&lt;&#x2F;li&gt;
&lt;li&gt;LLM&#x2F;에이전트가 항상 정답은 아님: 비용을 지불하는 건 문제 해결이지 AI 자체가 아님&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;brunch.co.kr&#x2F;@shndon0220&#x2F;153&quot;&gt;미국 VC가 언급한 지금 AI로 창업하기 어려운 분야들&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;MVP, MMP, MLP 개념과 올바른 이해: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;startups&#x2F;comments&#x2F;eber4l&#x2F;your_guide_to_mvp_mmp_mlp_mdp_and_map_startup&#x2F;?tl=ko&quot;&gt;MVP, MMP, MLP, MDP, MAP 스타트업 단계 가이드 : r&#x2F;startups&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fixate.it&#x2F;blog&#x2F;minimum-viable-product-minimum-marketable-product-or-minimum-loveable-product-whats-best&quot;&gt;MVP, MMP or MLP. What&#x27;s best?&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;feed&#x2F;update&#x2F;urn:li:activity:7350330223319535620&#x2F;&quot;&gt;MVP에 대한 정확한 해석에 대한 의견&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;geu-oe&quot;&gt;그 외&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ratsplaydoom.com&#x2F;&quot;&gt;시궁쥐(Rat)에게 DOOM 학습시키기&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: 그냥 순수하게 재미있는 프로젝트. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;yolorun_capital&#x2F;status&#x2F;1996632980903620886?s=20&quot;&gt;지금도 진행중인 듯&lt;&#x2F;a&gt;하다.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;containersonaws.com&#x2F;pattern&#x2F;nginx-reverse-proxy-sidecar-ecs-fargate-task&#x2F;&quot;&gt;AWS ECS의 리버스 프록시 사이드카 패턴 | Containers on AWS&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: AWS 직원들이 운영중인 비공식 블로그의 글. 가끔 보이는 패턴인데 명확한 이유를 찾기 어려워 궁금했던 내용. 주요 이점은 작업 분담(압축), 효율적인 트래픽 처리이다.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=2758&quot;&gt;오픈 소스 어플리케이션의 아키텍쳐 | GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: 인사이트 출판사에서 1권 번역본을 샀었는데, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aosabook.org&#x2F;en&#x2F;index.html&quot;&gt;원서&lt;&#x2F;a&gt;는 무료로 공개되어 있다. 많은 오픈소스 프로젝트의 핵심 기여자들이 프로젝트의 설계 철학을 말해준다.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;rust&#x2F;comments&#x2F;1pn6010&#x2F;compio_instead_of_tokio_what_are_the_implications&#x2F;&quot;&gt;Tokio와 Compio의 차이 - 비동기 모델 비교 | Reddit&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;: epoll vs io_uring 기반 비동기 런타임의 차이점. IGGY의 주요 개발자가 답글을 달았는데 쉽게 설명해준다.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=25130&quot;&gt;&lt;strong&gt;&lt;br&gt; 태그로 돌아본 웹의 30년 | GeekNews&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;: 웹 생태계의 진화 과정을 다룬 글. 프론트엔드뿐 아니라 백엔드 개발자도 알면 유익한 내용.  관련 글: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=21170&quot;&gt;JavaScript의 간략한 역사 | GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;jageob&quot;&gt;작업&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;학습, 개발, 실험 등 직접 손댄 것들&lt;&#x2F;p&gt;&lt;h3 id=&quot;rdb-giban-kyureul-sayonghaebogi&quot;&gt;RDB 기반 큐를 사용해보기&lt;&#x2F;h3&gt;
&lt;p&gt;DB의 작업 성공과 함께 사이드이펙트나 추가 처리(알림, 비동기 처리)가 필요한 경우, MQ가 유용하다.
하지만 당장 고트래픽 처리와 확장성이 필요 없다면 DB 기반 스케줄러를 쓰는 게 더 좋다. (90% 이상의 경우 여기에 해당할 것이다.)&lt;&#x2F;p&gt;
&lt;p&gt;회사에서 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kagkarlsson&#x2F;db-scheduler&quot;&gt;db-scheduler&lt;&#x2F;a&gt;를 사용하여 별도 인프라 추가 없이 단계별로 복구 가능한 Task를 만들 수 있었고,
기존의 여러 문제를 해결하는 만족스러운 결과를 얻었다. 이에 대한 건 따로 블로그를 써볼 예정이다.&lt;&#x2F;p&gt;
&lt;p&gt;우아한형제들 기술블로그에서도 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;techblog.woowahan.com&#x2F;23625&#x2F;&quot;&gt;유사한 패턴을 직접 구현한 사례&lt;&#x2F;a&gt;가 있다. (왜 직접 만들었는지는 모르겠지만)&lt;&#x2F;p&gt;
&lt;p&gt;Rust에는 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;apalis-dev&#x2F;apalis&quot;&gt;apalis&lt;&#x2F;a&gt;가 제일 유명한 거 같다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;beulrogeu-geul-donggi-bidonggi-beulroking-nonbeulroking-gaenyeomeun-eodiseobuteo-jalmosdoeeossna-jagseong&quot;&gt;블로그 글 &quot;&lt;a href=&quot;&#x2F;blog&#x2F;blocking-nonblocking-sync-async-misconceptions&#x2F;&quot;&gt;동기&#x2F;비동기, 블로킹&#x2F;논블로킹 개념은 어디서부터 잘못되었나&lt;&#x2F;a&gt;&quot; 작성&lt;&#x2F;h3&gt;
&lt;p&gt;X에서 개발 관련 포스팅을 보면서 시간을 때우곤 하는데, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;finalchildmc&#x2F;status&#x2F;1654007292772376581?s=20&quot;&gt;동기&#x2F;비동기 관련 사분면이 잘못되었다는 글&lt;&#x2F;a&gt;을 보게 되었다.&lt;&#x2F;p&gt;
&lt;p&gt;명확하게 설명은 못했지만 저런 사분면으로 나눠서 설명하는 것이 뭔가 이상하다는 생각을 가지고 있던 터라,
AI를 활용해 여러 자료를 찾아보았다. 이런 사분면 설명은 잘못된 설명이라는 걸 알게 되어 글을 작성했다.&lt;&#x2F;p&gt;
&lt;p&gt;요즘엔 AI를 사용하면 이전에 비해 자료 검색 속도가 말도 안 되게 빨라졌다. 정확한 자료를 빠르게 찾아볼 수 있어서 좋다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jjalbeun-saenggag&quot;&gt;짧은 생각&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;근황과 요즘하는 생각&lt;&#x2F;p&gt;
&lt;p&gt;기존에 오픈소스 기여에 관심을 가지고 더 깊이 있는 부분에 참여하고 싶었지만, 아직 많이 부족함을 느끼고 있다.
기초적인 능력 향상에 집중하기 위해 한동안은 쉴 예정이다.&lt;&#x2F;p&gt;
&lt;p&gt;AI를 개발과 자료조사에 적극 활용하면서, 공식문서나 개념을 쉽게 풀어쓴 블로그 글을 볼 필요가 없어졌다.
이제는 전문성 있는 글이나 개인적인 시선이 담긴 글 위주로 보고, 나도 그런 글을 쓰려고 하고 있다. (어떻게 보면 AI가 저품질 글을 대체했다고 볼 수 있을까?)&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>[월간 기록] 이전 자료 모음</title>
          <pubDate>Sun, 28 Dec 2025 00:00:00 +0000</pubDate>
          <author>Sijun Yang</author>
          <link>https://sijun-yang.com/blog/monthly-log-before/</link>
          <guid>https://sijun-yang.com/blog/monthly-log-before/</guid>
          <description xml:base="https://sijun-yang.com/blog/monthly-log-before/">&lt;p&gt;월간 기록을 시작했는데, 이전에 정리한 자료 중에서도 좋은게 많다.&lt;&#x2F;p&gt;
&lt;p&gt;&quot;월간 기록&quot;이라고 볼 순 없지만 버리기는 아까워, 최근 몇 개월 동안 모아두었던 기록 중에 다시 찾아볼 만한 것들을 정리했다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sujib&quot;&gt;수집&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;흥미롭거나 유용했던 자료들&lt;&#x2F;p&gt;&lt;h3 id=&quot;computer-networks-a-systems-approach-muryo-weonseo&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.systemsapproach.org&#x2F;index.html&quot;&gt;Computer Networks: A Systems Approach (무료 원서)&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;나는 한글 번역본을 책으로 가지고 있는데, 영어 원서는 무료로 공개되어 있다. 네트워크를 제대로 공부하고 싶을 때 참고하면 좋을 듯.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;interactive-sicp-js&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sourceacademy.org&#x2F;sicpjs&#x2F;index&quot;&gt;Interactive SICP JS&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;SICP의 설명을 Scheme 대신 기능이 제한된 JS로 대체한 에디션이다. 인터넷에서 무료로 볼 수 있고 실행 환경을 구축할 필요 없이 웹사이트에서 실습할 수 있다.&lt;&#x2F;p&gt;
&lt;p&gt;원문 또한 검색하면 공식적으로 무료로 풀려있고, 원문과 SICP in JS의 내용을 비교하고 싶다면 여기의 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sicp.sourceacademy.org&#x2F;#&quot;&gt;비교판&lt;&#x2F;a&gt;에서 볼 수 있다.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;SICP(Structure and Interpretation of Computer Programs, 컴퓨터 프로그램의 구조와 해석)는 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.wisdomandwonder.com&#x2F;link&#x2F;2110&#x2F;why-mit-switched-from-scheme-to-python&quot;&gt;전 MIT 입문 프로그래밍 교재&lt;&#x2F;a&gt;로, Scheme(Lisp 방언)을 사용해 추상화, 재귀, 데이터 구조, 인터프리터&#x2F;컴파일러 구현 등 컴퓨팅의 본질적 개념을 다룬다.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;나는 특히 3장에서 substitution model에서 environment model로 전환하는 것과 4장에서 겉보기에는 동일한 언어라도 평가 전략이나 실행 모델과 같은 구현 선택에 따라 동작이 달라질 수 있다는 점이 인상 깊었다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cloudflare-hangugeseoyi-mang-yeondong-munje&quot;&gt;Cloudflare 한국에서의 망 연동 문제&lt;&#x2F;h3&gt;
&lt;p&gt;Cloudflare는 망 사용료로 인한 비용 문제로 CDN 사용 시 국외의 노드와 연결된다.
한국에 ICN(인천) 리전이 있지만, Enterprise 플랜을 사용해야만 고정이 가능하다.&lt;&#x2F;p&gt;
&lt;p&gt;CDN 뿐만 아니라 R2나 다른 기능들에서도 한국 리전이 사용되지 않는 듯 하나 확실하진 않다.&lt;&#x2F;p&gt;
&lt;p&gt;이에 대한 공식적인 내용을 찾아보기는 어렵지만, 사실 상 망 사용료로 인한 문제임이 확실한 것 같다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gameple.co.kr&#x2F;news&#x2F;articleView.html?idxno=208925&quot;&gt;클라우드플레어 임원 &quot;한국 망 사용료가 비슷하다고? 20배 이상 비싸&quot;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;marinesnow34.github.io&#x2F;2023&#x2F;09&#x2F;23&#x2F;s3r2&#x2F;&quot;&gt;관련 블로그 글&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;namu.wiki&#x2F;w&#x2F;Cloudflare#s-4&quot;&gt;나무위키&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gaonwiki.com&#x2F;a&#x2F;s5J&quot;&gt;가온위키(처음 보는 위키인데 내용이 많아서 링크)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;sqlgwa-gwangyehyeong-model&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kihyo-park.github.io&#x2F;blog&#x2F;rdb-intro&#x2F;&quot;&gt;SQL과 관계형 모델&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;관계형 모델의 이론과 RDB를 연관지어 설명한다.&lt;&#x2F;p&gt;
&lt;p&gt;실제 DM 사용 경험이 적다곤 하지만, 이런 관점의 글은 본 적 없고 인상깊었다.&lt;&#x2F;p&gt;
&lt;p&gt;아마 블로그 글 저자가 컴파일러나 언어학에 관심이 있어서 이런 관점의 글이 나온거 같음.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tempeulris-kolbaeg-paeteongwa-seupeuring-teuraenjaegsyeon-gwanri-bangbeob&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;84f6b453b6687491a2b1756498f5ed5f&quot;&gt;템플릿 콜백 패턴과 스프링 트랜잭션 관리 방법&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;고등학교 후배의 포트폴리오 프로젝트 코드를 보다가 궁금해져서 찾아본 내용.
라이브러리 사용자가 Context를 알지 않아도 실행 가능하게 하는 편리한 패턴이라고 생각된다.&lt;&#x2F;p&gt;
&lt;p&gt;전역이 아닌 별도의 생명 주기를 가지는 Context는 어떤 식으로 관리되는지 생각해볼 수 있었다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5jjari-peurompeuteuro-2-418jjari-cwiyagjeom-cajeun-sseol-geeknews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;new-blog.ch4n3.kr&#x2F;llm-found-security-issues-from-django-ko&#x2F;&quot;&gt;$5짜리 프롬프트로 $2,418짜리 취약점 찾은 썰&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=24828&quot;&gt;GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;내용이 좋다. 실제로 LLM을 사용한 긍정적이고 효과적인 방법이라고 볼 수 있을 듯. 오픈소스 기여나 학습 측면에서 이런 시도가 나오고 있다는건 좋은 것 같다.&lt;&#x2F;p&gt;
&lt;p&gt;하지만 이와 반대로 LLM이 오픈소스 생태계 유지에 악영향을 줄 수 있을 것 같아 걱정이다.
FFmpeg, cURL, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;posts&#x2F;snicoll_goodbye-albon-idrizi-httpslnkdin-activity-7405253562458378240-Jxu9&#x2F;&quot;&gt;Spring&lt;&#x2F;a&gt; 같은 여러 오픈소스에서도 AI Slop이 많아져 불만을 표하는 글을 보기도 했고.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sqlite-cangsijaga-jeanhan-crlf-geuman-bonaegi-seoneon-geurigo-ceolhoe-hackernews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fossil-scm.org&#x2F;home&#x2F;ext&#x2F;stop-requiring-crlf.md&quot;&gt;SQLite 창시자가 제안한 &quot;CRLF 그만 보내기&quot; 선언 (그리고 철회)&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=41830717&quot;&gt;HackerNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;이런 역사적 잔재는 생각보다 많다. tty, base64 등. 지금 당연하게 쓰는 관행이 사실은 수십 년 전 하드웨어 제약의 흔적인 경우가 많다.&lt;&#x2F;p&gt;
&lt;p&gt;SQLite 창시자 Richard Hipp이 &quot;이제 CR은 그만 보내자&quot;는 선언문을 작성했다가 철회했다. 주장이 과격했고, 호환성 문제가 있었기 떄문이다. 실제로 SQLite 관련 코드를 수정했다가 다른 서비스나 언어 구현에서 처리가 안 되어 깨지는 사례가 발생했다.&lt;&#x2F;p&gt;
&lt;p&gt;그럼에도 HN 토론에서 많이 언급됐듯이, 이런 레거시는 언젠가 정리해야 한다는 의견에 동의한다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;railway-oriented-programming-rop&quot;&gt;Railway Oriented Programming (ROP)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kciter.so&#x2F;posts&#x2F;railway-oriented-programming&#x2F;&quot;&gt;Railway Oriented Programming (ROP)&lt;&#x2F;a&gt;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;0e.medium.com&#x2F;%EA%B7%B8%EB%9E%98%EC%84%9C-rop%EA%B0%80-%EB%AD%94%EB%8D%B0-%EC%94%B9%EB%8D%95%EC%95%84-railway-oriented-programming-4e8070c04bda&quot;&gt;Railway Oriented Programming이란? (Medium)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rust의 &lt;code&gt;Result&lt;&#x2F;code&gt;, Kotlin의 &lt;code&gt;Result&lt;&#x2F;code&gt; 도 이 패턴을 사용한다. try-catch와 달리 예외 흐름을 선형적으로 처리할 수 있다.&lt;&#x2F;p&gt;
&lt;p&gt;Spring 트랜잭션 같은 기존 패턴과는 잘 맞지 않아서 실무에서 자주 쓰진 않았다.
실패 경로를 명시적으로 다뤄야 할 때 써본 적은 있지만, 돌이켜보면 크고 복잡한 코드의 레거시를 갈아엎지 못하던 상황에서 나온 코드였다.&lt;&#x2F;p&gt;
&lt;p&gt;ROP 자체는 좋다고 생각하지만, JVM 생태계는 프레임워크&#x2F;라이브러리가 예외 기반이라, 제한된 영역이 아니라면 ROP 스타일이 잘 맞지 않아 보인다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;joheun-dijainiran-gesyutalteuwa-mildoro-alabogi&quot;&gt;좋은 디자인이란? - 게슈탈트와 밀도로 알아보기&lt;&#x2F;h3&gt;
&lt;p&gt;색이나 예쁜 걸 말하는 게 아니라 레이아웃이나 어떻게 정보를 전달할 것인가를 다루는 내용들.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;matthewstrom.com&#x2F;writing&#x2F;ui-density&quot;&gt;UI Density (Matthew Ström)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=43925732&quot;&gt;HackerNews 토론&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;brunch.co.kr&#x2F;@artneighbor&#x2F;78&quot;&gt;게슈탈트 심리학과 UI&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;레이아웃을 잘 꾸미고, 서비스 특성에 따라 밀도를 조절하기&lt;&#x2F;p&gt;
&lt;h3 id=&quot;frameworkless-frontend-development-seuteodi&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gdsc-ssu&#x2F;2023-FE-with-no-framework&quot;&gt;Frameworkless Frontend Development 스터디&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;프레임워크 없이 프론트엔드 개발하기. 내용은 괜찮은데 책으로 보면 불편할 듯. 블로그로 원서를 찾아보거나 직접 구현 분석하는 게 더 나을 것 같다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Apress&#x2F;frameworkless-front-end-development&#x2F;tree&#x2F;master&quot;&gt;원본 코드 (GitHub)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;(아래 작업 파트에 누가 스터디한 레포 포크해서 개인적으로 정리한 레포를 적어둠.)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;coejeoghwareul-wihan-algorijeum&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;algorithmsbook.com&#x2F;optimization&#x2F;#download&quot;&gt;최적화를 위한 알고리즘&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.hada.io&#x2F;topic?id=24757&quot;&gt;GeekNews&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;algorithmsbooks&#x2F;algforopt-notebooks&quot;&gt;Jupyter Notebook 버전&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;최적화 문제를 다루는 알고리즘 책. 무료로 공개되어 있고, Julia 언어로 구현되어 있다. (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;namu.wiki&#x2F;w&#x2F;Julia&quot;&gt;Julia&lt;&#x2F;a&gt; 나무위키)&lt;&#x2F;p&gt;
&lt;p&gt;다만 이런 의견도 있음을 주의하고 보기.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;책에 Firefly, Cuckoo Search 같은 메타휴리스틱이 포함된 걸 보고 놀람. 이 알고리즘들은 학계에서 신뢰받지 못하고, ITOR 논문에서도 비판받았음&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;top-github-users-in-south-korea&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gayanvoice&#x2F;top-github-users&#x2F;blob&#x2F;main&#x2F;markdown&#x2F;public_contributions&#x2F;south_korea.md&quot;&gt;Top GitHub Users in South Korea&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;깃헙 유저들 나라 별 기여&#x2F;팔로워 순 순위를 모아놓은 레포에서 한국인끼리 모아둔 페이지.&lt;&#x2F;p&gt;
&lt;p&gt;내리다 보면 아는 사람이나 유명한 블로그 쓰는 사람들이 종종 보인다.&lt;&#x2F;p&gt;
&lt;p&gt;내 계정도 있는데, 팔로워, 기여 수 조건이 있어 아슬아슬하게 들어가있다. 기여는 학교에서 안 공개 프로젝트 덕에 높게 나오는거 같다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;oopyi-35nyeon-silsu-casey-muratori-balpyoyeongsang-in-bsc-2025&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=wo84LFzx5nI&quot;&gt;OOP의 35년 실수 - Casey Muratori 발표영상 In BSC 2025&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;claude.ai&#x2F;share&#x2F;3f5044c9-e393-4f97-a177-f10879c5201c&quot;&gt;Claude AI 요약&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Casey Muratori가 OOP의 구조적 문제점을 지적한 강연. 논쟁적이지만 생각해볼 거리를 많이 던져준다.&lt;&#x2F;p&gt;
&lt;p&gt;ECS, Fat Struct 같은 패턴이 이전부터 있었고, 특정 상황에서는 이게 더 적절하다는 것.&lt;&#x2F;p&gt;
&lt;p&gt;현재의 OOP가 범용 대규모 프로그래밍에 유리하다는 인식과 달리 초기에는 제한된 도메인(분산 시스템)의 소규모 팀에서 탄생한 개념이라는게 인상깊었음.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;seoneonjeog-peurogeuraeminge-daehan-caggaggwa-ohae&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;evan-moon.github.io&#x2F;2025&#x2F;09&#x2F;07&#x2F;declarative-programming-misconceptions-and-essence&#x2F;&quot;&gt;선언적 프로그래밍에 대한 착각과 오해&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;선언형 프로그래밍이 무엇인지, 왜 오해받는지에 대한 깊이 있는 분석.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-every-programmer-should-know-about-memory&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lwn.net&#x2F;Articles&#x2F;250967&#x2F;&quot;&gt;What Every Programmer Should Know About Memory&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;people.freebsd.org&#x2F;~lstewart&#x2F;articles&#x2F;cpumemory.pdf&quot;&gt;공식 PDF (114페이지)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.google.com&#x2F;search?q=ycombinator+%22What+Every+Programmer+Should+Know+About+Memory%22&quot;&gt;구글 검색하기&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;메모리 계층 구조, 캐시, NUMA 등 하드웨어 수준의 메모리 동작 원리를 다룬 유명한 글. 114페이지의 방대한 분량이라 모든 내용을 알아야 하는 건 아니라는 주장이 HN에서 꾸준히 나온다. (오래된 글이라 그런지 인용이 너무 많이 되서 해커뉴스 링크들를 주기보다는 그냥 구글에 검색하는게 나을 정도) 그럼에도 일부 핵심 개념은 성능 최적화를 할 때 중요하므로, 필요할 때 참고하면 좋을 듯.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thread-dump-the-simple-tool-for-debugging-java-applications-in-production-by-gustav-karlsson&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blogg.bekk.no&#x2F;thread-dump-the-simple-tool-for-debugging-java-applications-in-production-1cfed0d0d120&quot;&gt;Thread dump — the simple tool for debugging Java-applications in production | by Gustav Karlsson&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;프로덕션 환경에서 Java 애플리케이션의 성능 문제나 데드락을 진단하는 실용적인 방법. Thread dump를 어떻게 수집하고 분석하는지 단계별로 설명한다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;naega-mandeun-bangeo-yutil-hamsu-5jong-seteu-popeumeosin&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.popekim.com&#x2F;ko&#x2F;2025&#x2F;10&#x2F;11&#x2F;defensive-assertion-utils.html&quot;&gt;내가 만든 방어 유틸 함수 5종 세트 | 포프머신&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;서버에서 유용한 커스텀 Assert 함수 패턴. 로깅, 슬랙 알림, 에러 로그, 심지어 사이렌 등으로 알리고, 중요도에 따라 다르게 구성한다.&lt;&#x2F;p&gt;
&lt;p&gt;코드로써 의미가 명확하고 가독성이 좋다. 테스트까진 아니지만 효율적이고 그에 준하는 효과 (가정이 깨지는 순간 파악, 의도적인 범위&#x2F;제한 명시)를 가진다.&lt;&#x2F;p&gt;
&lt;p&gt;좋아보인다. 도입해볼만한 가치가 있을 듯.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reflections-on-trusting-trust-ken-thompson&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cesarsotovalero.net&#x2F;blog&#x2F;revisiting-ken-thompson-reflection-on-trusting-trust.html&quot;&gt;Reflections on Trusting Trust - Ken Thompson&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;309fe1a139f818284558822277b8ca70&quot;&gt;한국어 AI 번역 (Gist)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ken Thompson의 유명한 튜링상 수상 강연. 컴파일러에 백도어를 심어도 소스 코드 검사만으로는 발견할 수 없다는 걸 보여준 논문.&quot;신뢰를 어디까지 확장할 수 있는가?&quot;라는 근본적인 보안 질문을 던진다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-surprising-truth-about-pixels-and-accessibility&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.joshwcomeau.com&#x2F;css&#x2F;surprising-truth-about-pixels-and-accessibility&#x2F;&quot;&gt;The Surprising Truth About Pixels and Accessibility&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;px, em, rem 단위를 언제 어떻게 사용해야 하는지에 대한 실용적인 가이드. 특히 사용자의 접근성 관점에서 설명함.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;대부분 상황: rem. 사용자 기본 폰트 크기 설정(=사용자가 의도한 크기)에 따라 크기가 바뀌기 떄문&lt;&#x2F;li&gt;
&lt;li&gt;부모&#x2F;자신의 font-size에 비례해야 할 때: em&lt;&#x2F;li&gt;
&lt;li&gt;고정된 크기: px&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;you-no-longer-need-javascript-hackernews&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lyra.horse&#x2F;blog&#x2F;2025&#x2F;08&#x2F;you-dont-need-js&#x2F;&quot;&gt;You no longer need JavaScript&lt;&#x2F;a&gt; | &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=12690842&quot;&gt;HackerNews&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;현대 CSS와 HTML만으로 대부분의 웹 기능을 구현할 수 있다는 점을 보여주는 글.&lt;&#x2F;p&gt;
&lt;p&gt;지금 이 글을 보여주는 개인 블로그를 만들 때 사용한 css 작성 스타일에도 영향을 주었다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hypermedia-systems&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;hypermedia.systems&#x2F;&quot;&gt;Hypermedia Systems&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;htmx 제작자 Carson Gross가 쓴 책이다.
REST 아키텍처의 원래 의도를 설명하고, SPA 프레임워크 없이 hypermedia(HTML) 기반으로 웹 애플리케이션을 구축하는 방법을 다룬다.&lt;&#x2F;p&gt;
&lt;p&gt;무료로 온라인에서 읽을 수 있다.&lt;&#x2F;p&gt;
&lt;p&gt;추가: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;4682b1346fa3eb6316e78f2f37554873&quot;&gt;Single HTML로 만드는 코드 - Gist&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;관련해서 잘 정리된 글: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;parksb.github.io&#x2F;article&#x2F;43.html&quot;&gt;웹은 왜 복잡해졌나? -모던 웹의 복잡성과 하이퍼미디어 시스템&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jageob&quot;&gt;작업&lt;&#x2F;h2&gt;
&lt;p class=&quot;section-description&quot;&gt;학습, 개발, 실험 등 직접 손댄 것들&lt;&#x2F;p&gt;&lt;h3 id=&quot;neteuweokeueseo-macgwa-ipga-bunridoen-iyu&quot;&gt;네트워크에서 MAC과 IP가 분리된 이유&lt;&#x2F;h3&gt;
&lt;p&gt;&quot;Rust in Action&quot; p.345를 보고 궁금해져서 찾아본 내용.&lt;&#x2F;p&gt;
&lt;p&gt;IP와 MAC은 다른 용도를 가지고 서로 다른 단체에 의해 다른 연도에 만들어졌다:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;MAC: LAN 내부 하드웨어의 통신용&lt;&#x2F;li&gt;
&lt;li&gt;IP: 네트워크 간 통신용, 먼저 만들어졌다.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;두 가지를 연결하기 위해 ARP가 등장했다. 참고로 MAC과 IP가 항상 같이 쓰이는 건 아니다. (MAC 주소 개념을 사용하지 않거나, IP 주소 ↔ 링크 주소 매핑이 다른 방식으로 처리되는 경우도 있음)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.perplexity.ai&#x2F;search&#x2F;daeum-naeyongeul-dwisbadcimhan-NuIVwuwVS666X3VvAJEX.A#0&quot;&gt;Perplexity 검색 결과&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;877cc0530c38d056ed988525a2392469&quot;&gt;정리 Gist&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;frameworkless-frontend-development-guhyeon-yeonseub&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;YangSiJun528&#x2F;forked-2023-FE-with-no-framework&quot;&gt;Frameworkless Frontend Development 구현 연습&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gdsc-ssu&#x2F;2023-FE-with-no-framework&quot;&gt;원본 스터디 레포&lt;&#x2F;a&gt;를 fork해서 직접 구현해본 프로젝트. 프레임워크 없이 순수 JavaScript로 프론트엔드 애플리케이션을 만들면서 라우팅, 상태 관리, 컴포넌트 시스템 등의 기본 원리를 학습했다.&lt;&#x2F;p&gt;
&lt;p&gt;프레임워크가 내부적으로 어떻게 동작하는지 이해하고, 실제로 직접 구현해보면서 웹 플랫폼의 기초를 다질 수 있었다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chip-8-emyulreiteo-c-eoneo&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;YangSiJun528&#x2F;c-chip-8&quot;&gt;CHIP-8 에뮬레이터 (C 언어)&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;C 언어로 CHIP-8 에뮬레이터를 구현한 프로젝트.&lt;&#x2F;p&gt;
&lt;p&gt;CPU 명령어 해석, 메모리 관리를 직접 만들면서 이해할 수 있었음.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;awesome-for-me&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;YangSiJun528&#x2F;awesome-for-me&quot;&gt;awesome-for-me&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;개인적으로 유용하다고 생각하는 자료들을 정리한 저장소.&lt;&#x2F;p&gt;
&lt;p&gt;지금은 개인 디스코드나 월간 기록으로 자료 관리 방식을 바꿔서 더 이상 업데이트하지는 않고 있음.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>[월간 기록] 시리즈 소개</title>
          <pubDate>Sun, 28 Dec 2025 00:00:00 +0000</pubDate>
          <author>Sijun Yang</author>
          <link>https://sijun-yang.com/blog/monthly-log-introduction/</link>
          <guid>https://sijun-yang.com/blog/monthly-log-introduction/</guid>
          <description xml:base="https://sijun-yang.com/blog/monthly-log-introduction/">&lt;p&gt;평소 관심 가는 여러 자료를 수집하고 학습하는데, 관심사가 자주 바뀌다 보니 시간이 지나면 흩어지거나 까먹곤 한다.&lt;&#x2F;p&gt;
&lt;p&gt;자잘한 활동을 기록하고 공유도 할 겸 유용한 자료, 회고, 일상, 학습 기록 등을 한곳에 남겨두는 &quot;월간 기록&quot; 시리즈를 만들었다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pomaes&quot;&gt;포맷&lt;&#x2F;h2&gt;
&lt;p&gt;매달 마지막 날을 기준으로 업로드하며, 다음과 같은 구성으로 이루어진다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;수집&lt;&#x2F;strong&gt;: 그 달에 발견한 흥미롭거나 유용했던 자료들&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;작업&lt;&#x2F;strong&gt;: 학습, 개발, 실험 등 직접 손댄 것들&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;짧은 생각&lt;&#x2F;strong&gt;: 근황과 요즘 하는 생각&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;내부 형식은 자유롭게 작성한다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mogjeog&quot;&gt;목적&lt;&#x2F;h2&gt;
&lt;p&gt;월간 기록을 시작한 이유는 활동 기록도 있지만, 자료 선별 목적도 있다.&lt;&#x2F;p&gt;
&lt;p&gt;개인 디스코드 채널에 자료를 모아왔는데, 정리되어있지 않은데다가 3년이 넘으니 찾기 어려워졌다.
그래서 수집 방식은 유지하되, 월말에 참고할 만한 것만 선별해 따로 기록하기로 했다.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>동기&#x2F;비동기, 블로킹&#x2F;논블로킹 개념은 어디서부터 잘못되었나</title>
          <pubDate>Thu, 11 Dec 2025 00:00:00 +0000</pubDate>
          <author>Sijun Yang</author>
          <link>https://sijun-yang.com/blog/blocking-nonblocking-sync-async-misconceptions/</link>
          <guid>https://sijun-yang.com/blog/blocking-nonblocking-sync-async-misconceptions/</guid>
          <description xml:base="https://sijun-yang.com/blog/blocking-nonblocking-sync-async-misconceptions/">&lt;p&gt;여러 개발 관련 글에서 Blocking&#x2F;Non-blocking과 Sync&#x2F;Async를 설명할 때면 항상 등장하는 2x2 매트릭스가 있다. 4개의 조합으로 나누어 설명하는 이 표를 한 번쯤은 보았을 것이다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;sync-async-matrix.png&quot; alt=&quot;Blocking&#x2F;Non-blocking, Sync&#x2F;Async 비교 매트릭스&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;이 매트릭스에서 가장 이해하기 어려운 부분은 Blocking + Async 조합이다. 많은 블로그에서 이 조합을 설명하려고 시도하지만, 나는 대부분 억지스러운 설명이라는 인상을 받았다.&lt;&#x2F;p&gt;
&lt;p&gt;최근 이 개념을 다시 공부하다가 이러한 설명은 올바르지 않다는 사실을 알게 되었다. 우리가 그동안 별 의심없이 받아들였던 이 설명이 잘못된 이유를 말해보고자 한다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jalmosdoen-seolmyeongyi-culceo&quot;&gt;잘못된 설명의 출처&lt;&#x2F;h2&gt;
&lt;p&gt;이러한 매트릭스 기반의 설명의 시작은 IBM Developer의 2006년 글 &quot;Boost application performance using asynchronous I&#x2F;O&quot;인 것으로 보인다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;ibm-io-comparison.png&quot; alt=&quot;원래 글의 비교&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;IBM의 글은 리눅스 커널의 AIO(Asynchronous I&#x2F;O) API를 소개하면서 sync&#x2F;async와 blocking&#x2F;non-blocking을 조합해 4가지로 구분했다.&lt;&#x2F;p&gt;
&lt;p&gt;그러나 이 글의 구분은 POSIX 표준 정의와는 다르다. 이 글에선 &lt;code&gt;select&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;poll&lt;&#x2F;code&gt;를 blocking + async의 조합으로 소개하지만, POSIX 표준 정의에는 이런 조합이 등장할 수 없다.&lt;&#x2F;p&gt;
&lt;p&gt;IBM의 글은 리눅스 커널의 AIO API를 소개하는 글이다. 리눅스 커널은 POSIX 표준을 구현하므로, 커널 레벨 I&#x2F;O를 논한다면 POSIX 정의와 일관되어야 한다. 그러나 IBM의 분류는 POSIX 표준과 일치하지 않는다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;posix-pyojunyi-silje-jeongyi&quot;&gt;POSIX 표준의 실제 정의&lt;&#x2F;h2&gt;
&lt;p&gt;POSIX 표준&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;과 리처드 스티븐스(W. Richard Stevens)의 책 Unix Network Programming&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-4-1&quot;&gt;&lt;a href=&quot;#fn-4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;을 살펴보면 명확한 정의를 찾을 수 있다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Synchronous I&#x2F;O: I&#x2F;O 작업이 완료될 때까지 요청 프로세스가 blocked&lt;&#x2F;li&gt;
&lt;li&gt;Asynchronous I&#x2F;O: 요청 프로세스가 blocked되지 않음&lt;&#x2F;li&gt;
&lt;li&gt;Blocking: 요청한 동작이 완료될 때까지 함수 호출이 대기&lt;&#x2F;li&gt;
&lt;li&gt;Non-blocking: 요청한 동작을 즉시 완료할 수 없으면 지연 없이 반환&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;여기서 중요한 점은 I&#x2F;O 작업 완료의 의미다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;unix-i-o-modelyi-du-dangye&quot;&gt;Unix I&#x2F;O 모델의 두 단계&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x2F;O 작업은 일반적으로 두 단계로 이루어진다:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;데이터 준비 단계 - 디스크에서 데이터를 읽거나 네트워크에서 패킷이 도착하기를 기다린다. 데이터가 준비되면 커널 버퍼로 복사된다.&lt;&#x2F;li&gt;
&lt;li&gt;데이터 복사 단계 - 커널 버퍼에서 애플리케이션 버퍼로 데이터를 복사한다.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;스티븐스는 Unix에서 사용 가능한 5가지 I&#x2F;O 모델을 다음과 같이 구분한다. 이 모델은 커널이 I&#x2F;O 준비와 수행을 어떻게 관여하느냐에 따른 대표적인 분류이다. 상호 배타적인 조합표를 의미하지 않는다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-5-1&quot;&gt;&lt;a href=&quot;#fn-5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-blocking-i-o&quot;&gt;1. Blocking I&#x2F;O&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;blocking-io-model.png&quot; alt=&quot;Blocking I&#x2F;O 모델의 Flow&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;가장 흔한 I&#x2F;O 모델이다. &lt;code&gt;read()&lt;&#x2F;code&gt; 시스템 콜을 호출하면 데이터가 준비되고 복사가 완료될 때까지 프로세스가 block된다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-non-blocking-i-o&quot;&gt;2. Non-blocking I&#x2F;O&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;nonblocking-io-model.png&quot; alt=&quot;Non-blocking I&#x2F;O 모델의 Flow&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;O_NONBLOCK&lt;&#x2F;code&gt; 플래그를 설정하면 데이터가 준비되지 않았을 때 &lt;code&gt;EAGAIN&lt;&#x2F;code&gt; 에러와 함께 즉시 반환한다. 하지만 데이터가 준비되면 복사하는 동안은 여전히 block된다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-i-o-multiplexing&quot;&gt;3. I&#x2F;O Multiplexing&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;io-multiplexing-model.png&quot; alt=&quot;I&#x2F;O Multiplexing 모델의 Flow&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;select()&lt;&#x2F;code&gt;나 &lt;code&gt;poll()&lt;&#x2F;code&gt;을 사용해 여러 file descriptor를 동시에 감시한다. 준비된 fd에 대해 &lt;code&gt;read()&lt;&#x2F;code&gt;를 호출할 때 여전히 block된다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-signal-driven-i-o&quot;&gt;4. Signal-Driven I&#x2F;O&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;signal-driven-io-model.png&quot; alt=&quot;Signal-Driven I&#x2F;O 모델의 Flow&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;SIGIO&lt;&#x2F;code&gt; 신호를 등록하고 데이터가 준비되면 신호를 받는다. 신호를 받은 후 &lt;code&gt;read()&lt;&#x2F;code&gt;를 호출하면 여전히 block된다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5-asynchronous-i-o&quot;&gt;5. Asynchronous I&#x2F;O&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;async-io-model.png&quot; alt=&quot;Asynchronous I&#x2F;O 모델의 Flow&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;진정한 비동기 I&#x2F;O다. &lt;code&gt;aio_read()&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-7-1&quot;&gt;&lt;a href=&quot;#fn-7&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;는 즉시 반환되고, 커널이 백그라운드에서 두 단계를 모두 처리한 후 완료를 통지한다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;synchronous-vs-asynchronousyi-haegsim&quot;&gt;Synchronous vs Asynchronous의 핵심&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog&#x2F;io-models-comparison.png&quot; alt=&quot;5가지 I&#x2F;O 모델의 비교표&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;스티븐스는 Unix Network Programming에서 이 모델들의 동기&#x2F;비동기 여부를 명확하게 구분한다.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;POSIX defines these two terms as follows:&lt;&#x2F;p&gt;
&lt;p&gt;A synchronous I&#x2F;O operation causes the requesting process to be blocked until that I&#x2F;O operation completes.&lt;br &#x2F;&gt;
An asynchronous I&#x2F;O operation does not cause the requesting process to be blocked.&lt;br &#x2F;&gt;
Using these definitions, the first four I&#x2F;O models (blocking, nonblocking, I&#x2F;O multiplexing, and signal-driven I&#x2F;O) are all synchronous because the actual I&#x2F;O operation (recvfrom) blocks the process. Only the asynchronous I&#x2F;O model matches the asynchronous I&#x2F;O definition.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;다음과 같이 번역할 수 있다.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;POSIX는 이 두 용어를 다음과 같이 정의한다:&lt;&#x2F;p&gt;
&lt;p&gt;동기 I&#x2F;O(synchronous I&#x2F;O) 작업은 해당 I&#x2F;O 작업이 완료될 때까지 요청한 프로세스를 블로킹한다.&lt;br &#x2F;&gt;
비동기 I&#x2F;O(asynchronous I&#x2F;O) 작업은 요청한 프로세스를 블로킹하지 않는다.&lt;br &#x2F;&gt;
이 정의에 따르면, 처음 네 가지 I&#x2F;O 모델(블로킹 I&#x2F;O, 논블로킹 I&#x2F;O, I&#x2F;O 멀티플렉싱, 시그널 기반 I&#x2F;O)은 모두 동기 I&#x2F;O에 해당한다. 실제 I&#x2F;O 연산인 &lt;code&gt;recvfrom&lt;&#x2F;code&gt; 호출이 프로세스를 블로킹하기 때문이다.
오직 비동기 I&#x2F;O 모델만이 POSIX에서 정의한 비동기 I&#x2F;O에 해당한다.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;5gaji-i-o-modelyi-donggi-bidonggi-bunryu&quot;&gt;5가지 I&#x2F;O 모델의 동기&#x2F;비동기 분류&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;I&#x2F;O 모델&lt;&#x2F;th&gt;&lt;th&gt;Blocking&#x2F;Non-blocking&lt;&#x2F;th&gt;&lt;th&gt;Sync&#x2F;Async&lt;&#x2F;th&gt;&lt;th&gt;1단계 Block&lt;&#x2F;th&gt;&lt;th&gt;2단계 Block&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Blocking I&#x2F;O&lt;&#x2F;td&gt;&lt;td&gt;Blocking&lt;&#x2F;td&gt;&lt;td&gt;Synchronous&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Non-blocking I&#x2F;O&lt;&#x2F;td&gt;&lt;td&gt;Non-blocking&lt;&#x2F;td&gt;&lt;td&gt;Synchronous&lt;&#x2F;td&gt;&lt;td&gt;No (폴링)&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;I&#x2F;O Multiplexing&lt;&#x2F;td&gt;&lt;td&gt;Blocking&lt;&#x2F;td&gt;&lt;td&gt;Synchronous&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Signal-driven I&#x2F;O&lt;&#x2F;td&gt;&lt;td&gt;Non-blocking&lt;&#x2F;td&gt;&lt;td&gt;Synchronous&lt;&#x2F;td&gt;&lt;td&gt;No (신호)&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Asynchronous I&#x2F;O&lt;&#x2F;td&gt;&lt;td&gt;Non-blocking&lt;&#x2F;td&gt;&lt;td&gt;Asynchronous&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;앞의 네 가지 모델은 모두 데이터 복사 단계(2단계)에서 block된다. 따라서 POSIX 정의상 모두 synchronous다. 오직 asynchronous I&#x2F;O만이 두 단계 모두에서 block되지 않는다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;wae-select-neun-synchronousinga&quot;&gt;왜 &lt;code&gt;select()&lt;&#x2F;code&gt;는 synchronous인가?&lt;&#x2F;h3&gt;
&lt;p&gt;자료조사 과정에서 본 여러 자료에서 &lt;code&gt;select()&lt;&#x2F;code&gt;를 asynchronous로 설명하는 경우를 많이 보았다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;select()&lt;&#x2F;code&gt;는 여러 I&#x2F;O를 동시에 처리할 수 있어서 비동기처럼 보이지만, 실제로는 다음과 같이 동작한다:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;프로세스가 감시할 파일 디스크립터 집합을 준비한다.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;select()&lt;&#x2F;code&gt;는 각 파일 디스크립터가 I&#x2F;O를 수행해도 블로킹되지 않을 상태인지를 알려준다.&lt;&#x2F;li&gt;
&lt;li&gt;준비된 파일 디스크립터에 대해 애플리케이션이 &lt;code&gt;read()&lt;&#x2F;code&gt;를 직접 호출한다.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;이때 &lt;code&gt;read()&lt;&#x2F;code&gt; 호출은 시스템 콜이 완료될 때까지 호출자를 반환하지 않으며, POSIX 정의상 요청한 프로세스를 블로킹하므로 synchronous가 된다.&lt;&#x2F;p&gt;
&lt;p&gt;멀티스레드 환경에서도 마찬가지다. I&#x2F;O를 수행하는 스레드는 시스템 콜이 완료될 때까지 블로킹되며, POSIX 정의에 따르면 이는 동기 I&#x2F;O다.
스레드 분리는 애플리케이션 레벨의 동시성 전략일 뿐이다. 커널의 I&#x2F;O 모델을 바꿀 수는 없다.&lt;&#x2F;p&gt;
&lt;p&gt;Linux man page도 &lt;code&gt;select&lt;&#x2F;code&gt;를 &quot;synchronous I&#x2F;O multiplexing&quot;으로 명시하고 있다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-6-1&quot;&gt;&lt;a href=&quot;#fn-6&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; 반면 &lt;code&gt;io_uring&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-8-1&quot;&gt;&lt;a href=&quot;#fn-8&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;이나 POSIX &lt;code&gt;aio_&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-7-2&quot;&gt;&lt;a href=&quot;#fn-7&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; 함수들은 &quot;Asynchronous I&#x2F;O&quot;로 구분한다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;keoneol-i-o-gaenyeomgwa-peurogeuraeming-modelyi-hondong&quot;&gt;커널 I&#x2F;O 개념과 프로그래밍 모델의 혼동&lt;&#x2F;h2&gt;
&lt;p&gt;IBM의 글은 리눅스 커널 레벨 I&#x2F;O를 다루는 기술 문서다. 커널 레벨에서 이 용어들은 POSIX 표준에 따라 엄밀하게 정의된다.
반면 애플리케이션 레벨에서는 동일한 용어가 더 느슨하고 범용적인 의미로 사용된다.
(커널은 프로세스의 실행 흐름을 정확히 제어해야 하므로 용어가 엄밀하게 정의되지만,
수많은 라이브러리와 프레임워크가 독립적으로 개발되는 애플리케이션 레벨의 라이브러리&#x2F;프레임워크, 언어 등은 용어 통일이 현실적으로 불가능하다.)&lt;&#x2F;p&gt;
&lt;p&gt;하지만 IBM의 글이 널리 인용되면서 두 가지 문제가 발생했다.&lt;&#x2F;p&gt;
&lt;p&gt;첫째, 분류 방식이 POSIX 표준 정의와 정확히 일치하지 않았다. 커널 API를 다루는 글임에도 커널이 따르는 표준과 다른 기준을 사용했고,
이 설명이 반복 인용되면서 표준과 다른 내용이 사실처럼 확산되었다.&lt;br &#x2F;&gt;
둘째, 이후 수많은 블로그와 기술 문서들이 이 2×2 매트릭스를 인용하면서 원래의 맥락을 잃었다.
커널 레벨 I&#x2F;O를 설명하기 위한 용어가 애플리케이션 레벨의 프로그래밍 모델이나 아키텍처의 설명까지 무분별하게 적용되었다.&lt;&#x2F;p&gt;
&lt;p&gt;대표적인 오해는 Node.js + MySQL 드라이버의 예시다.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Node.js + MySQL은 Blocking + Async의 예시다. Node.js는 비동기인데 MySQL 드라이버가 블로킹이라서…”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;이 설명은 서로 다른 레벨의 개념을 혼합한 것이다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Node.js의 비동기: 이벤트 루프 기반의 프로그래밍 모델&lt;&#x2F;li&gt;
&lt;li&gt;MySQL 드라이버의 블로킹: 라이브러리 차원의 API 구현 방식&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;이는 커널 레벨의 I&#x2F;O 동작과는 직접적인 관련이 없으며, 애초에 IBM 문서가 다루던 맥락과도 다르다.
이처럼 추상화 레벨이 다른 개념들을 구분 없이 동일한 용어로 설명하다 보니, 개념적 혼란이 발생할 수밖에 없다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;peurogeuraeming-modelroseoyi-bidonggigwa-naebu-guhyeon&quot;&gt;프로그래밍 모델로서의 비동기과 내부 구현&lt;&#x2F;h2&gt;
&lt;p&gt;많은 비동기 프로그래밍 모델을 제공하는 프레임워크들이 내부 구현에선 동기 시스템 콜을 사용한다.&lt;&#x2F;p&gt;
&lt;p&gt;Netty는 &quot;asynchronous event-driven&quot; 프레임워크를 표방하지만&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-10-1&quot;&gt;&lt;a href=&quot;#fn-10&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, 실제로는 &lt;code&gt;epoll()&lt;&#x2F;code&gt;이나 &lt;code&gt;kqueue&lt;&#x2F;code&gt; 같은 I&#x2F;O multiplexing을 사용한다. 이들은 POSIX 정의상 synchronous다.&lt;br &#x2F;&gt;
Node.js도 마찬가지다. libuv를 통해 플랫폼별로 최적화된 I&#x2F;O multiplexing을 사용하거나, 파일 시스템 작업의 경우 별도 스레드 풀에서 blocking I&#x2F;O를 수행한다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-9-1&quot;&gt;&lt;a href=&quot;#fn-9&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;br &#x2F;&gt;
이것이 잘못된 설명이나 구현은 아니다. 애플리케이션 개발자 입장에서는 비동기 프로그래밍 모델을 제공받는 것이 중요하지, 내부적으로 어떤 시스템 콜을 사용하는지는 중요하지 않다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gyeolron&quot;&gt;결론&lt;&#x2F;h2&gt;
&lt;p&gt;POSIX 표준에 따르면 I&#x2F;O 모델은 본질적으로 세 가지로 구분할 수 있다.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Blocking Synchronous - 전통적인 blocking I&#x2F;O와 I&#x2F;O multiplexing&lt;&#x2F;li&gt;
&lt;li&gt;Non-blocking Synchronous - non-blocking I&#x2F;O와 signal-driven I&#x2F;O&lt;&#x2F;li&gt;
&lt;li&gt;Asynchronous - 진정한 비동기 I&#x2F;O (POSIX aio, io_uring)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;따라서 Blocking + Async라는 조합은 정의상 존재할 수 없다. Asynchronous는 정의상 어떤 단계에서도 block되지 않기 때문이다.&lt;&#x2F;p&gt;
&lt;p&gt;물론 애플리케이션 레벨에서는 이 구분이 덜 엄격하다. 프로그래밍 모델로서의 비동기와 시스템 콜 레벨의 비동기는 다른 개념이며, 이를 명확히 구분해야 한다.
Netty나 Node.js 같은 프레임워크가 비동기를 표방하는 것은 애플리케이션 개발자에게 제공하는 프로그래밍 모델을 지칭하는 것이지, POSIX I&#x2F;O 모델의 정의를 따르는 것이 아니다.&lt;&#x2F;p&gt;
&lt;p&gt;중요한 것은 맥락이다. OS나 커널 레벨의 I&#x2F;O를 논할 때와 애플리케이션 레벨의 프로그래밍 패턴을 논할 때, 같은 용어가 다른 의미를 가질 수 있다. 이러한 차이를 인지하고 명확히 구분해서 사용해야 불필요한 혼란을 피할 수 있다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;naneun-eoddeohge-gubunhaneunga&quot;&gt;나는 어떻게 구분하는가&lt;&#x2F;h2&gt;
&lt;p&gt;커널 I&#x2F;O 레벨에선 표준의 정의를 따른다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;동기 &#x2F; 비동기: I&#x2F;O 작업이 완료될 때까지 요청 프로세스가 블로킹되는지 여부&lt;&#x2F;li&gt;
&lt;li&gt;블로킹 &#x2F; 논블로킹: 요청한 동작을 즉시 완료할 수 없을 때 함수 호출이 대기하는지 여부&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;다만 시스템 레벨 개발을 주로 하지 않기 때문에, 이 용어를 쓸 일은 많지 않다.
이 레벨에서는 추상적인 용어보다 select, epoll, io_uring 같은 구체적인 시스템 콜 이름으로 대화하는 것이 더 명확하다고 생각한다.&lt;&#x2F;p&gt;
&lt;p&gt;어플리케이션 레벨에선 다음 기준으로 구분한다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;동기 &#x2F; 비동기: 애플리케이션 레벨에서의 프로그래밍 모델, 전체 실행 흐름&lt;&#x2F;li&gt;
&lt;li&gt;블로킹 &#x2F; 논블로킹: 함수 호출이나 개별 작업 단위에서의 동작&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;일반적으로 이 관점에서 이야기한다. 이렇게 구분하면 아키텍처를 설명하거나 문제를 분석할 때 명확하게 생각할 수 있다.&lt;br &#x2F;&gt;
예를 들어, “비동기 모델 환경에서 블로킹 호출을 사용해 전체 실행 흐름에 영향을 주었다.”, “동기 환경이더라도 오래 걸리는 I&#x2F;O를 논블로킹으로 처리해 효율을 높일 수 있다.” 와 같이 모델과 동작을 분리해서 생각할 수 있다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;burog&quot;&gt;부록&lt;&#x2F;h2&gt;
&lt;p&gt;&quot;Boost application performance using asynchronous I&#x2F;O&quot; 를 포함한 IBM Developer의 오래된 글이 아카이브되어 원래 작성 시점을 알 수 없었는데, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cyberciti.biz&#x2F;tips&#x2F;linux-boost-application-performance-using-asynchronous-io.html&quot;&gt;저자의 사이트에서 원본 자료가 링크된 글&lt;&#x2F;a&gt;을 보고 2006년 작성되었다고 추정했다.&lt;&#x2F;p&gt;
&lt;p&gt;IBM의 설명이 한국에만 퍼진 이야기는 아닌 듯 하다. 영어, 중국어나 일본어로 작성된 자료에서도 2x2 매트릭스를 사용해 구분하는 글을 찾아볼 수 있었다.&lt;&#x2F;p&gt;
&lt;p&gt;조사 과정에서 참고한 자료들이다. 높은 신뢰성을 가지는 문서는 아니지만 개념을 이해하는 데 도움이 되어 남겨두었다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linuxquestions.org&#x2F;questions&#x2F;programming-9&#x2F;asynchronized-i-o-%3D%3D-multiplexing-i-o-467044&#x2F;&quot;&gt;Asynchronized I&#x2F;O vs Multiplexing I&#x2F;O 토론 - Linux Questions&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.artima.com&#x2F;articles&#x2F;comparing-two-high-performance-io-design-patterns&quot;&gt;Comparing Two High-Performance I&#x2F;O Design Patterns&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;EJNBLD3X2yg&quot;&gt;비동기 프로그래밍, 비동기 I&#x2F;O, 비동기 커뮤니케이션 - 쉬운코드 (YouTube)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;homoefficio.github.io&#x2F;2017&#x2F;02&#x2F;19&#x2F;Blocking-NonBlocking-Synchronous-Asynchronous&#x2F;&quot;&gt;Blocking-NonBlocking-Synchronous-Asynchronous - 뒤태지존의 끄적거림&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;rust&#x2F;comments&#x2F;1pn6010&#x2F;compio_instead_of_tokio_what_are_the_implications&#x2F;&quot;&gt;Tokio와 Compio의 차이: 비동기 모델(epoll vs io_uring) - Reddit&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.inflearn.com&#x2F;course&#x2F;%EA%B8%B0%EC%B4%88%ED%83%84%ED%83%84-%EB%8F%85%ED%95%98%EA%B2%8C-java-part3-2&quot;&gt;기초 탄탄! 독하게 시작하는 Java Part 3(하) : 소켓과 파일 I&#x2F;O 강의 | 널널한 개발자 - 인프런&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;M. Tim Jones, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.ibm.com&#x2F;articles&#x2F;l-async&#x2F;&quot;&gt;&quot;Boost application performance using asynchronous I&#x2F;O&quot;&lt;&#x2F;a&gt;, IBM Developer, 2006. &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;IEEE Std 1003.1-2024, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;9799919799&#x2F;&quot;&gt;&quot;The Open Group Base Specifications Issue 8&quot;&lt;&#x2F;a&gt;, IEEE and The Open Group, 2024. &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;IEEE Std 1003.1-2004, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pubs.opengroup.org&#x2F;onlinepubs&#x2F;009695399&#x2F;&quot;&gt;&quot;The Open Group Base Specifications Issue 6&quot;&lt;&#x2F;a&gt;, IEEE and The Open Group, 2004. &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-4&quot;&gt;
&lt;p&gt;W. Richard Stevens, Bill Fenner, Andrew M. Rudoff, &quot;Unix Network Programming, Volume 1: The Sockets Networking API&quot;, 3rd Edition, Addison-Wesley, 2003. &lt;a href=&quot;#fr-4-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-5&quot;&gt;
&lt;p&gt;예를 들면, I&#x2F;O Multiplexing과 Non-blocking I&#x2F;O 모델을 함께 사용할 수도 있다. &lt;code&gt;select()&lt;&#x2F;code&gt; 함수는 기본적으로 이벤트가 올때까지 wait하는 blocking 함수인데, fb에 &lt;code&gt;O_NONBLOCK&lt;&#x2F;code&gt; 플래그를 활성화 해서 Non-blocking 함수로 동작하게 할 수 있다. 이 경우, 여러 fb를 동시에 감시하면서 데이터의 준비 여부와 무관하게 즉시 반환된다. &lt;a href=&quot;#fr-5-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-7&quot;&gt;
&lt;p&gt;Linux man pages, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man7&#x2F;aio.7.html&quot;&gt;&quot;aio(7) - POSIX asynchronous I&#x2F;O overview&quot;&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-7-1&quot;&gt;↩&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-7-2&quot;&gt;↩2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-6&quot;&gt;
&lt;p&gt;Linux man pages, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man2&#x2F;select.2.html&quot;&gt;&quot;select(2) - synchronous I&#x2F;O multiplexing&quot;&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-6-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-8&quot;&gt;
&lt;p&gt;Linux man pages, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;linux&#x2F;man-pages&#x2F;man7&#x2F;io_uring.7.html&quot;&gt;&quot;io_uring(7) - Asynchronous I&#x2F;O facility&quot;&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-8-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-10&quot;&gt;
&lt;p&gt;Netty Project, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;netty&#x2F;netty&#x2F;blob&#x2F;4.2&#x2F;README.md&quot;&gt;&quot;Netty v4.2 README&quot;&lt;&#x2F;a&gt;, GitHub &lt;a href=&quot;#fr-10-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-9&quot;&gt;
&lt;p&gt;libuv documentation, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.libuv.org&#x2F;en&#x2F;v1.x&#x2F;design.html&quot;&gt;&quot;Design overview&quot;&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-9-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</description>
      </item>
      <item>
          <title>Java 배열 인덱스 접근은 정말 O(1)인가?</title>
          <pubDate>Wed, 21 May 2025 00:00:00 +0000</pubDate>
          <author>Sijun Yang</author>
          <link>https://sijun-yang.com/blog/programming-language-spec-vs-impl/</link>
          <guid>https://sijun-yang.com/blog/programming-language-spec-vs-impl/</guid>
          <description xml:base="https://sijun-yang.com/blog/programming-language-spec-vs-impl/">&lt;p&gt;누군가 개발 커뮤니티에 이런 질문을 올렸다.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Java 배열의 인덱스 접근이 O(1)이라는데, 공식 문서에서 찾을 수가 없어요. 어디서 확인할 수 있나요?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;나도 당연히 O(1)이라고 생각했지만, 막상 &quot;어디에 그렇게 쓰여 있냐&quot;고 물으면 대답하기 어려웠다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;java-baeyeol-indegseu-jeobgeunyi-naebu-dongjag&quot;&gt;Java 배열 인덱스 접근의 내부 동작&lt;&#x2F;h3&gt;
&lt;p&gt;실제로 확인해보자. 다음과 같은 간단한 Java 코드가 있다.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #383A42; background-color: #FAFAFA;&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A626A4;&quot;&gt;public static void&lt;&#x2F;span&gt;&lt;span style=&quot;color: #4078F2;&quot;&gt; array&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C18401;&quot;&gt;    int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E45649;&quot;&gt;[] intArr&lt;&#x2F;span&gt;&lt;span&gt; = {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A626A4;&quot;&gt;    int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E45649;&quot;&gt; intA&lt;&#x2F;span&gt;&lt;span&gt; = intArr[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #A626A4;&quot;&gt;    int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E45649;&quot;&gt; intB&lt;&#x2F;span&gt;&lt;span&gt; = intArr[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #986801;&quot;&gt;9&lt;&#x2F;span&gt;&lt;span&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;자바에서 배열이나 사칙연산 같은 기본 기능은 자바 코드 레벨에서 내부 동작을 확인할 수 없다.
&lt;code&gt;java.util.ArrayList&lt;&#x2F;code&gt; 같이 자바 언어로 구현된 표준 라이브러리와 달리, 언어 사양에 의해 동작이 정의되는 더 저수준의 영역이기 때문이다.
그렇다면 배열의 동작을 확인하기 위해선 무엇을 봐야 할까?&lt;&#x2F;p&gt;
&lt;p&gt;먼저 자바 언어 명세(JLS)의 배열 접근 문서&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;를 확인했다. 배열을 어떻게 사용할 수 있는지만 서술하고 있다.
구체적인 구현 방식이나 시간복잡도에 관한 요구사항은 없다.&lt;&#x2F;p&gt;
&lt;p&gt;다음으로 JVM 명세(JVMS)를 확인했다.
JVMS에서는 배열 인덱스 접근 시 어떤 바이트코드가 사용되는지 명시한다. 실제로 사용되는지 확인해보자.&lt;&#x2F;p&gt;
&lt;p&gt;잠깐 바이트코드에 대해 설명하면, Java는 컴파일 시 바이트코드로 변환되고 JVM이 이를 실행한다.
JVM은 스택 기반 가상 머신으로&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, 값을 스택에 쌓고 명령어가 꺼내 연산하는 방식이다.
따라서 자바 프로그램의 실제 동작을 더 확실하게 알기 위해선 바이트코드를 보아야 한다.&lt;&#x2F;p&gt;
&lt;p&gt;위 자바 코드를 컴파일하면 배열 인덱스 접근은 다음과 같은 바이트코드로 변환된다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #383A42; background-color: #FAFAFA;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; intArr[0] 접근&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ALOAD 0      &#x2F;&#x2F; 배열 참조를 스택에 푸시&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ICONST_0     &#x2F;&#x2F; 정수 0을 스택에 푸시 (인덱스)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;IALOAD       &#x2F;&#x2F; 스택에서 배열과 인덱스를 꺼내 해당 요소를 읽음&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; intArr[9] 접근&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ALOAD 0      &#x2F;&#x2F; 배열 참조를 스택에 푸시&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BIPUSH 9     &#x2F;&#x2F; 정수 9를 스택에 푸시 (인덱스)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;IALOAD       &#x2F;&#x2F; 스택에서 배열과 인덱스를 꺼내 해당 요소를 읽음&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;JVMS의 명령어 문서&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-4-1&quot;&gt;&lt;a href=&quot;#fn-4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;를 보면, &lt;code&gt;IALOAD&lt;&#x2F;code&gt; 명령어는 스택에서 배열 참조와 인덱스를 꺼내 해당 요소를 읽어 스택에 푸시한다고 설명한다.
어떤 스택 조작을 하는지만 서술되어 있다. 어떻게 접근해야 하는지, 시간복잡도가 어떠해야 하는지는 명시하지 않는다.&lt;&#x2F;p&gt;
&lt;p&gt;따라서 JLS와 JVMS 어디에도 &quot;배열 인덱스 접근은 O(1)이어야 한다&quot;는 요구사항은 없다. 이제 남은 건 실제 JVM 구현체를 확인하는 것이다.&lt;&#x2F;p&gt;
&lt;p&gt;OpenJDK를 선택했다. Java SE의 공식 레퍼런스 구현체이며, 대부분의 JVM 구현이 이를 기반으로 하기 때문이다.
OpenJDK는 C++로 구현되어 있다. &lt;code&gt;objArrayOop.hpp&lt;&#x2F;code&gt;와 &lt;code&gt;objArrayOop.inline.hpp&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-5-1&quot;&gt;&lt;a href=&quot;#fn-5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-6-1&quot;&gt;&lt;a href=&quot;#fn-6&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;를 보면 배열 인덱스 접근의 내부 동작을 알 수 있다.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #383A42; background-color: #FAFAFA;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;다음과 같은 순서로 동작한다.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1. base_offset_in_bytes()  -&amp;gt; 배열 헤더 크기&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. sizeof(T) * index       -&amp;gt; 요소 크기 × 인덱스&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. base() + offset         -&amp;gt; 실제 메모리 주소 계산&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. oop_load_at(offset)     -&amp;gt; 해당 주소에서 값 로드&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;핵심은 (여타 CS 책에서 배열의 구현 방식을 설명할 때처럼) 포인터 산술 연산이다. 배열의 시작 주소에 오프셋을 더해 직접 메모리에 접근한다.
요소의 개수와 무관하게 상수 시간에 동작한다. 따라서 OpenJDK에서는 O(1)이 맞다.&lt;&#x2F;p&gt;
&lt;p&gt;그러나 Java 언어 명세(JLS)나 JVM 명세(JVMS) 어디에도 &quot;배열 인덱스 접근은 O(1)이어야 한다&quot;는 요구사항은 없었다.
OpenJDK는 O(1)로 동작하지만, 그건 특정 구현체의 선택일 뿐 언어의 보장이 아니다.
다른 JVM 구현체가 같은 방식을 사용한다는 보장은 명세에 없다.
(물론 현실적으로 다른 방식을 쓸 이유는 없다. 배열의 특성상 거의 모든 구현체가 O(1)일 것이다.)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;myeongsewa-guhyeonyi-gubun&quot;&gt;명세와 구현의 구분&lt;&#x2F;h3&gt;
&lt;p&gt;프로그래밍 언어는 크게 두 레벨로 나뉜다.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;명세(Specification): 언어가 어떻게 동작해야 하는지 정의한 문서. 문법, 타입 시스템, 의미론 등을 규정한다.&lt;&#x2F;li&gt;
&lt;li&gt;구현(Implementation): 명세를 실제로 실행 가능하게 만든 컴파일러나 런타임. 명세가 정의하지 않은 부분은 구현체가 자유롭게 결정한다.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Java의 명세는 JLS(Java Language Specification), JVMS(Java Virtual Machine Specification)이다. 구현은 OpenJDK, Amazon Corretto, Azul Zulu 등이 존재한다. 다양한 JDK 종류의 차이를 알아보려면 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;whichjdk.com&#x2F;&quot;&gt;Which Version of JDK Should I Use?&lt;&#x2F;a&gt;를 참고하자.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-7-1&quot;&gt;&lt;a href=&quot;#fn-7&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;대부분의 성능과 관련된 부분은 명세가 아닌 구현이 결정한다. 흔히 알고리즘 문제에서의 시간 복잡도, 공간 복잡도와 같은 것들은 구현이 결정하게 된다.&lt;&#x2F;p&gt;
&lt;p&gt;프로그래밍 언어의 이러한 점은 Database의 질의형 언어(Query Language)와도 비슷한 점이라고 생각하는데, 내부 구현을 명세에 숨김으로써 자유롭게 기존 동작을 유지하면서 런타임의 최적화를 할 수 있기 때문이다.
예시로 Java는 GC 알고리즘이 계속 발전하고 있으며, Netflix는 Java의 버전을 8에서 17로 업그레이드하면서 약 20%의 CPU 사용률을 향상할 수 있었다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-8-1&quot;&gt;&lt;a href=&quot;#fn-8&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; 또한 언어 명세의 수정 없이 Virtual Thread가 도입되기도 했다.&lt;&#x2F;p&gt;
&lt;p&gt;&quot;(OpenJDK의) Java 배열 인덱스 접근이 O(1)이다&quot; 라는 말에서 OpenJDK나 다른 구현체의 이름이 빠진다면 정확하지 않은 말이다.
하지만 이런 내용을 일일이 지적하는 건 소모적인 일이다.&lt;&#x2F;p&gt;
&lt;p&gt;대부분의 개발자가 표준이나 사실상(de facto) 표준인 구현체를 사용한다. Java 개발자가 OpenJDK 계열을 쓰고, 거의 모든 Python 개발자가 CPython을 쓴다.
따라서 일상적인 상황에서는 암묵적으로 가장 표준에 가까운 구현체를 의미한다고 이해해도 무방할 것이다.&lt;&#x2F;p&gt;
&lt;p&gt;그럼에도 다른 런타임이나 구현체 간 차이를 분석하거나 이해하기 위해선 이러한 사실을 알고 있어야 한다.&lt;&#x2F;p&gt;
&lt;p&gt;C는 이 구분이 특히 중요한 언어다. 다양한 하드웨어에서 동작해야 하고, 수십 개의 컴파일러 구현체가 존재한다.
C 표준은 Undefined Behavior (UB), Unspecified Behavior (UsB), Implementation-defined Behavior (IdB)를 구분한다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-9-1&quot;&gt;&lt;a href=&quot;#fn-9&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
이 때문에 GCC에서 잘 돌던 코드가 Clang에서 다르게 동작하거나, 최적화 옵션에 따라 결과가 달라질 수 있다.
(이처럼 C는 문법에서 많은 함정을 가지고 있는데, 관심이 있다면 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;proofby.ac&#x2F;teaching-c&#x2F;&quot;&gt;C&#x2F;C++를 가르치기 전에 생각해 보기 - finalchild&lt;&#x2F;a&gt;를 한 번 읽어보는걸 추천한다.)&lt;&#x2F;p&gt;
&lt;p&gt;반면 C 이후에 설계된 현대 언어들은 명세가 훨씬 엄격하다. 그래도 여전히 이 구분이 필요한 순간들이 있다.
Node.js의 대항마로 Bun이 등장했을 때, &quot;Bun이 Node.js와 뭐가 다른가?&quot;라는 질문에 답하려면 명세와 구현의 구분이 필요하다.
JavaScript(ECMAScript)는 언어 명세고, Node.js와 Bun은 그 구현체다. 이벤트 루프나 파일 시스템 API는 JavaScript 명세가 아니라 런타임 구현이다. Bun이 빠른 이유는 JavaScript 언어가 달라서가 아니라, 런타임 구현이 다르기 때문이다.&lt;&#x2F;p&gt;
&lt;p&gt;Python도 비슷하다. PyPy는 CPython과 달리 JIT 컴파일을 제공해 CPU Bound 작업에서 유리하다.
심지어 JVM 위에서 실행되는 Jython이라는 런타임도 있다. 이러한 차이는 Python 명세가 실행 환경을 규정하지 않기 때문에 가능하다.
Java의 GraalVM Native Image를 사용하면 JVM 없이 네이티브 바이너리로 컴파일할 수 있다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-10-1&quot;&gt;&lt;a href=&quot;#fn-10&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; 이 경우 JVM의 동작을 전제로 한 코드(리플렉션 등)가 제한될 수 있다는 점을 예측할 수 있고, 실제로도 그렇다.&lt;&#x2F;p&gt;
&lt;p&gt;또한 프로그래밍 언어의 구현체는 OS와 런타임 버전에 따라 동작이 달라질 수 있다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-11-1&quot;&gt;&lt;a href=&quot;#fn-11&quot;&gt;11&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; 보안 취약점 문서나 버그 리포트에서 환경 명시가 필수인 이유다.&lt;&#x2F;p&gt;
&lt;p&gt;이처럼 명세와 구현은 다르다. 프로그래밍 언어와 런타임의 성능&#x2F;특징을 올바르게 논하기 위해서는 이를 이해하는 것이 필요하다.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-12-1&quot;&gt;&lt;a href=&quot;#fn-12&quot;&gt;12&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Oracle, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;specs&#x2F;jls&#x2F;se25&#x2F;html&#x2F;jls-15.html#jls-15.10.3&quot;&gt;&quot;JLS 15.10.3 - Array Access Expressions&quot;&lt;&#x2F;a&gt;, Java Language Specification SE 25 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;Oracle, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;specs&#x2F;jvms&#x2F;se25&#x2F;html&#x2F;jvms-2.html#jvms-2.5&quot;&gt;&quot;JVMS 2.5 - Run-Time Data Areas&quot;&lt;&#x2F;a&gt;, Java Virtual Machine Specification SE 25 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;전체 코드는 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;YangSiJun528&#x2F;3c4210f0709e19ac72070c62a6b7333c&quot;&gt;Gist에 올려두었다&lt;&#x2F;a&gt;. &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-4&quot;&gt;
&lt;p&gt;Oracle, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;specs&#x2F;jvms&#x2F;se25&#x2F;html&#x2F;jvms-6.html#jvms-6.5&quot;&gt;&quot;JVMS 6.5 - Instructions&quot;&lt;&#x2F;a&gt;, Java Virtual Machine Specification SE 25 &lt;a href=&quot;#fr-4-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-5&quot;&gt;
&lt;p&gt;OpenJDK, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;openjdk&#x2F;jdk&#x2F;blob&#x2F;master&#x2F;src&#x2F;hotspot&#x2F;share&#x2F;oops&#x2F;objArrayOop.hpp&quot;&gt;&quot;objArrayOop.hpp&quot;&lt;&#x2F;a&gt; 및 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;openjdk&#x2F;jdk&#x2F;blob&#x2F;master&#x2F;src&#x2F;hotspot&#x2F;share&#x2F;oops&#x2F;objArrayOop.inline.hpp&quot;&gt;&quot;objArrayOop.inline.hpp&quot;&lt;&#x2F;a&gt;, GitHub &lt;a href=&quot;#fr-5-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-6&quot;&gt;
&lt;p&gt;코드에서 &lt;code&gt;oop&lt;&#x2F;code&gt;는 Ordinary Object Pointer의 약자로, &quot;일반적인 객체를 가리키는 포인터&quot;라는 뜻이다. OpenJDK 코드에는 이 설명이 없어서 OpenJDK 개발자였던 Aleksey Shipilëv의 블로그에서 의미를 확인했다. Aleksey Shipilëv, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;shipilev.net&#x2F;jvm&#x2F;anatomy-quarks&#x2F;23-compressed-references&#x2F;#_compressed_references&quot;&gt;&quot;JVM Anatomy Quarks #23: Compressed References&quot;&lt;&#x2F;a&gt; 및 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;shipilev.net&#x2F;jvm&#x2F;objects-inside-out&#x2F;&quot;&gt;&quot;Java Objects Inside Out&quot;&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-6-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-7&quot;&gt;
&lt;p&gt;다양한 JDK 종류의 차이를 알아보려면 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;whichjdk.com&#x2F;&quot;&gt;Which Version of JDK Should I Use?&lt;&#x2F;a&gt;를 참고하자. &lt;a href=&quot;#fr-7-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-8&quot;&gt;
&lt;p&gt;InfoQ, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.infoq.com&#x2F;presentations&#x2F;netflix-java&#x2F;&quot;&gt;&quot;Netflix Adopts Java 17&quot;&lt;&#x2F;a&gt;, InfoQ Presentations &lt;a href=&quot;#fr-8-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-9&quot;&gt;
&lt;p&gt;Stack Overflow, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;2397984&#x2F;undefined-unspecified-and-implementation-defined-behavior&quot;&gt;&quot;Undefined, unspecified and implementation-defined behavior&quot;&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-9-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-10&quot;&gt;
&lt;p&gt;Oracle, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.graalvm.org&#x2F;latest&#x2F;reference-manual&#x2F;native-image&#x2F;&quot;&gt;&quot;GraalVM Native Image&quot;&lt;&#x2F;a&gt;, GraalVM Documentation &lt;a href=&quot;#fr-10-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-11&quot;&gt;
&lt;p&gt;같은 소스코드라도 컴파일러, OS, 런타임에 따라 다른 결과물이 만들어진다. 그리고 컴파일러와 OS 자체도 프로그래밍 언어로 작성된 프로그램이므로 환경마다 구현이 다를 수 있다. &lt;a href=&quot;#fr-11-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-12&quot;&gt;
&lt;p&gt;개인적으로 이런 저수준 동작에 대한 호기심이 있었다. 이 과정에서 간단한 책을 보거나 토이 프로젝트를 진행했었다. 특히 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sourceacademy.org&#x2F;sicpjs&#x2F;&quot;&gt;SICP: JavaScript Edition&lt;&#x2F;a&gt;를 읽으며, 겉보기에는 동일한 언어라도 평가 전략이나 실행 모델과 같은 구현 선택에 따라 동작이 달라질 수 있다는 점이 인상 깊었다. 이런 관점에서 보면 Java 배열 인덱스 접근의 시간복잡도 또한 구현에 의해 결정될 가능성이 크다고 보았고, 이런 실제하는 예시를 통해서 언어의 명세와 구현을 구분하는 시야에 대해서 공유하고 싶었다. &lt;a href=&quot;#fr-12-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</description>
      </item>
      <item>
          <title>Nand to Tetris 강의 수강 후기: 컴퓨터의 근본 원리 이해하기</title>
          <pubDate>Tue, 11 Jun 2024 00:00:00 +0000</pubDate>
          <author>Sijun Yang</author>
          <link>https://sijun-yang.com/blog/nand-to-tetris/</link>
          <guid>https://sijun-yang.com/blog/nand-to-tetris/</guid>
          <description xml:base="https://sijun-yang.com/blog/nand-to-tetris/">&lt;p&gt;몇 달 전에, Nand to Tetris 라는 강의를 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;chijoon-study&#x2F;cs-study&#x2F;wiki&#x2F;Nand2Tetris-%EC%96%91%EC%8B%9C%EC%A4%80&quot;&gt;수강&lt;&#x2F;a&gt; 완료했다. 간단한 소개와 느낀점에 대해 공유해보고자 한다.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;teachyourselfcs.com&#x2F;&quot;&gt;Teach Yourself Computer Science&lt;&#x2F;a&gt;라는 인터넷에서 혼자서 CS를 학습하기 위한 커리큘럼을 소개해주는 사이트에 추천해줘서 수강하게 되었다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;nand-to-tetris-sogae&quot;&gt;Nand to Tetris 소개&lt;&#x2F;h2&gt;
&lt;p&gt;시몬 쇼켄(Simon Schocken) 및 노암 니산(Noam Nisan)이 만들었다.
컴퓨터의 작동원리를 실습을 통해 이해할 수 있는 프로젝트이다.
간단한 논리 연산자인 Nand부터 시작해서 GUI 프로그램을 동작시킬 수 있는 범용 컴퓨터를 만든다.
하드웨어 및 소프트웨어를 순서대로 만들어 보면서 컴퓨터 과학의 주요 지식을 이해할 수 있다.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;jinhaeng-junbimul&quot;&gt;진행 준비물&lt;&#x2F;h3&gt;
&lt;p&gt;The Elements of Computing Systems(한국어 번역본: 밑바닥부터 만드는 컴퓨팅 시스템)이라는 도서와 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.coursera.org&#x2F;courses?query=from%20nand%20to%20tetris&quot;&gt;Coursera&lt;&#x2F;a&gt;에 있는 강의를 함께 들어가면서 진행했다.
나는 &lt;em&gt;밑바닥부터 만드는 컴퓨팅 시스템&lt;&#x2F;em&gt; 과  Coursera 강의를 함꼐 수강하였다.
Coursera에서 실습 과제를 제출하고 평가받을 수 있어 학습에 도움을 준다.
강의나 책 중 하나만 보아도 문제는 없어 보이지만, 둘 다 함께 보는 것을 추천한다.
( Coursera의 강의를 전부 수료하면 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;%EC%8B%9C%EC%A4%80-%EC%96%91-31a91827b&#x2F;details&#x2F;certifications&#x2F;&quot;&gt;수료증&lt;&#x2F;a&gt;도 준다. )&lt;&#x2F;p&gt;
&lt;h2 id=&quot;neugginjeom&quot;&gt;느낀점&lt;&#x2F;h2&gt;
&lt;h4 id=&quot;keompyuteoyi-gibon-weonri-ihae&quot;&gt;컴퓨터의 기본 원리 이해&lt;&#x2F;h4&gt;
&lt;p&gt;강의를 통해 고수준 언어를 컴파일하면서 C++이나 Java에서 다루는 객체지향이 내부적으로 함수와 구조체로 구성된다는 것을 깨달았다.
저수준 언어에서는 명령어를 위에서부터 아래로 순차적으로 실행하며, 가끔 Jump하면서 함수나 분기, 반복문을 구현한다.
CPU와 RAM은 논리 게이트의 집합으로 구성되며, (기본적인) CPU는 생각보다 단순한 역할을 수행한다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;peurogeuraeminge-daehan-deo-yeolrin-sago&quot;&gt;프로그래밍에 대한 더 열린 사고&lt;&#x2F;h4&gt;
&lt;p&gt;모든 프로그래밍 언어는 결국 기계어로 수행된다는 사실을 깨달았다.
각 언어는 해결하고자 하는 문제나 특화된 부분이 다를 수 있지만, 결국 기계어 입장에서는 동일하게 수행된다.
이 사실을 알고 나서, 새로운 것을 받아들이는 데 더 열린 자세를 갖게 되었다.
나는 잘 모르는 분야나 한 번도 해본 적 없는 것들에 대한 묘한 두려움이 있었다.
특히 나에게 익숙한 Java와 Spring을 주로 사용하고, 다른 기술에 대해서는 폐쇄적인 태도를 가지고 있었다.
하지만 열린 사고를 가진 지금은 NodeJS 기반의 서버 개발이나 프론트엔드 개발에도 관심을 가지고 있고,
기존에 사용해보지 않는 기술 스택을 사용해서 토이 프로젝트 개발을 기획하고 있다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;silseubyi-jungyoseong&quot;&gt;실습의 중요성&lt;&#x2F;h4&gt;
&lt;p&gt;강의에서 다루는 많은 내용을 알고는 있었지만, 실제로 이해하지 못하고 있었다는 것을 깨달았다.
단순히 아는 것과 이해하는 것은 다르며, 직접 결과물을 만들어보는 것을 통해 더 잘 이해할 수 있었다.&lt;&#x2F;p&gt;
&lt;p&gt;그래서 자료구조를 더 이해하기 위해 C 언어를 배워서 직접 자료구조를 구현해보고 있다.
이후에는 소켓 네트워크 구현과 같이 CS의 기초적인 부분을 실습해보고 싶다.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aswiun-jeom&quot;&gt;아쉬운 점&lt;&#x2F;h2&gt;
&lt;p&gt;개인적으로 프로젝트를 진행하면서 아쉬운 점은 다음과 같다.
특히 프로젝트의 구현과 실제 구현이 차이가 있는건 납득 가능한 부분이지만, 실제 구현과 비교하지 않는 것은 아쉽다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;inteoreobteue-daehan-seolmyeong-bujae&quot;&gt;인터럽트에 대한 설명 부재&lt;&#x2F;h4&gt;
&lt;p&gt;프로젝트에서 만드는 CPU에서 인터럽트 자체가 없어서 실제 OS나 컴퓨터를 이해하는데 중요한 인터럽트의 설명이 누락되어 있다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;ose-daehan-seolmyeong-bujog&quot;&gt;OS에 대한 설명 부족&lt;&#x2F;h4&gt;
&lt;p&gt;강의는 컴퓨팅 시스템에 대한 이해를 중점으로 한다.
리눅스처럼 현대 OS의 동작을 기대했다면 실망할 수 있다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2bu-silseub-nanido-yeoryeoum&quot;&gt;2부 실습 난이도 여려움&lt;&#x2F;h4&gt;
&lt;p&gt;강의의 2부로 넘어가면서 난이도가 급격히 올라갔다는 느낌을 받았다.
1부까지는 외부 자료를 거의 참고하지 않고 구현할 수 있었는데, 2부 넘어가고부터 내 실력으론 구글링 없이는 문제 해결이 불가능했다.
복잡한 요구사항을 구현해본 경험이 적은 사람에게는 어려울 수 있을 것 같다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;silje-guhyeone-daehan-bigyo-bujog&quot;&gt;실제 구현에 대한 비교 부족&lt;&#x2F;h4&gt;
&lt;p&gt;강의에서 다룬 내용이 실제 구현과 어떤 차이가 있는지 설명해주지 않아 아쉬웠다.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;hangugeo-beonyeog-munje&quot;&gt;한국어 번역 문제&lt;&#x2F;h4&gt;
&lt;p&gt;심각한 부분은 아니지만, 종종 오타&#x2F;오역이 보인다. 원서를 무리없이 읽을 수 있다면, 원서를 보고 진행하는 걸 추천한다. (여타 책들이 다 그렇겠지만)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mamuri&quot;&gt;마무리&lt;&#x2F;h2&gt;
&lt;p&gt;Nand to Tetris 강의를 통해 컴퓨터 시스템, 특히 컴퓨터와 프로그래밍 언어의 동작 원리를 이해할 수 있는 귀중한 경험이였다.
실습을 통해 이론적 지식을 실제로 구현해 보면서 얻은 인사이트는 다른 학습 방법으로 대체할 수 없다고 생각한다.
특히, 새로운 기술에 대한 열린 자세와 프로그래밍에 대한 더 넓은 시각을 얻은게 된 것이 나에게 중요한 성취 중 하나였다.
앞으로는 다양한 분야와 기술에 도전하며, 배운 내용을 바탕으로 더욱 성장해 나갈 것이다.&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
