<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>고은연로그</title>
    <link>https://koeunyeon.tistory.com/</link>
    <description>중년 아저씨. 본명 아님. 거의 20년차 개발자.
커피챗 요청은 언제나 환영합니다.
koeunyeon@gmail.com </description>
    <language>ko</language>
    <pubDate>Wed, 15 Apr 2026 11:14:44 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>고은연</managingEditor>
    <image>
      <title>고은연로그</title>
      <url>https://tistory1.daumcdn.net/tistory/8443170/attach/8a4bf13383794a6193614eac8b09082d</url>
      <link>https://koeunyeon.tistory.com</link>
    </image>
    <item>
      <title>BIG BALL OF MUD 한국어판</title>
      <link>https://koeunyeon.tistory.com/entry/BIG-BALL-OF-MUD-%ED%95%9C%EA%B5%AD%EC%96%B4%ED%8C%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 &lt;span&gt;2025년 10월 27일&lt;/span&gt; 제 벨로그 &lt;a href=&quot;https://velog.io/@koeunyeon/BIG-BALL-OF-MUD-%ED%95%9C%EA%B5%AD%EC%96%B4%ED%8C%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@koeunyeon/BIG-BALL-OF-MUD-%ED%95%9C%EA%B5%AD%EC%96%B4%ED%8C%90&lt;/a&gt;&amp;nbsp;에 썼던 글을 티스토리로 옮긴 것입니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BIG BALL OF MUD 라는 논문이 있습니다. 무려 1997년 (지금으로부터 무려 28년전)에 발표되었고 1999년에 정식으로 책에 수록된 글이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;소프트웨어 개발의 '이상(아름다운 아키텍처)'과 '현실(시장 압박과 기술 부채)' 사이의 괴리&lt;/b&gt;를 다루는 글입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 개인적으로 이 논문을 무척이나 좋아하는데요. 저도 여타 개발자들과 비슷하게 이상주의자와 현실 주의자 사이 어딘가에서 살아가고 있기에, 매 순간 이상을 따를 지 아니면 현실에 순응해야 할 지 고민하기 때문인 듯 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 순간에 어느 정도의 현실에 충실하고, 앞으로 다가올 미래의 기술 부채에 대해서 어떻게 균형을 잡을 것인가에 대해 굉장히 좋은 서사점을 주는 글이라 생각합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 id=&quot;원문&quot;&gt;원문&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원문은 &lt;a href=&quot;http://www.laputan.org/mud/&quot;&gt;http://www.laputan.org/mud/&lt;/a&gt; 에서 보실 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;초록abstract&quot; data-ke-size=&quot;size26&quot;&gt;초록(Abstract)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문은 흔하지만 비난받는 아키텍처 스타일인 &lt;b&gt;거대한 진흙 덩어리(Big Ball of Mud)&lt;/b&gt; 를 탐구합니다. 우리는 이것이 왜 그렇게 흔한지, 그리고 종종 성공적인지를 설명하는 일단의 패턴들을 제시합니다. 이러한 패턴들은 이상적인 소프트웨어 아키텍처라는 개념과, 비용, 일정 압박, 기술, 그리고 개발자들의 기량 부족과 같은 현실 세계의 제약 조건 사이의 긴장을 조명합니다. 이 패턴들은 아키텍처가 어떻게 진화할 수 있는지, 그리고 왜 임시방편적인 구조가 때로는 최선의 선택이 될 수 있는지를 보여줍니다. 우리는 건축가 크리스토퍼 알렉산더의 작업을 참고하여, 이러한 시스템이 종종 나타내는 유기적이고 점진적인 성장 과정을 탐구합니다. 이 논문은 또한 지저분한 시스템을 다루고, 개선하고, 때로는 처음부터 다시 만들어야 할 때를 인식하는 전략을 제시합니다. 이 패턴들은 엔지니어링 실용주의의 가치를 옹호하며, 완벽함의 추구가 어떻게 좋은 것의 적이 될 수 있는지를 보여줍니다.&lt;/p&gt;
&lt;h2 id=&quot;서론-introduction&quot; data-ke-size=&quot;size26&quot;&gt;서론 (Introduction)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 그렇게 많은 시스템이 아키텍처의 관점에서 볼 때 '거대한 진흙 덩어리'일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 이 질문에 오랫동안 흥미를 느껴왔습니다. 우리 둘 다 일리노이 대학교 어바나-샴페인 캠퍼스의 객체 지향 및 재사용 연구 그룹의 일원이었고, 그곳은 건축적으로 순수한 객체 지향 시스템에 대한 열정이 넘치는 곳이었습니다. 우리의 초기 작업은 프레임워크, 패턴, 그리고 객체 지향 기술에 대한 심도 있는 탐구를 포함했습니다. 우리는 깔끔하고, 우아하며, 재사용 가능하고, 확장 가능한 시스템을 만드는 방법에 대해 많은 것을 배웠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 현실 세계로 돌아와 컨설팅을 시작했을 때, 우리는 우리가 배운 이상적인 모습과는 매우 다른 시스템들을 마주했습니다. 우리는 종종 엉망진창이고, 임시방편으로 가득 차 있으며, 구조가 거의 없는 것처럼 보이는 시스템들을 유지보수하고 확장하는 임무를 맡았습니다. 우리는 이런 시스템들을 '거대한 진흙 덩어리'라고 부르기 시작했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 우리는 이런 시스템들을 혐오했습니다. 이것들은 우리가 피해야 한다고 배운 모든 것의 전형이었습니다. 하지만 시간이 지나면서, 우리는 한 가지 불편한 사실을 깨달았습니다. 바로 이런 '진흙 덩어리' 시스템들이 놀라울 정도로 흔하고, 심지어 매우 성공적인 경우가 많다는 것이었습니다. 그들은 시장에서 살아남았고, 돈을 벌고 있었으며, 고객에게 가치를 제공하고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문은 이러한 명백한 모순을 탐구하려는 우리의 시도입니다. 우리는 '거대한 진흙 덩어리'를 단순한 '안티패턴'으로 치부하는 대신, 그것이 왜 그렇게 널리 퍼져 있는지 이해하려고 노력했습니다. 우리는 이것이 단지 나쁜 프로그래밍의 결과가 아니라, 소프트웨어 개발에 작용하는 복잡한 힘들의 결과물일 수 있다는 것을 깨달았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문에서 우리는 '거대한 진흙 덩어리'와 그와 관련된 몇 가지 패턴들을 제시합니다. 이 패턴들은 완벽한 아키텍처에 대한 우리의 열망과, 제한된 시간, 돈, 그리고 기술이라는 현실 사이의 끊임없는 줄다리기를 포착합니다. 이 패턴들은 당신이 이런 시스템을 만났을 때 무엇을 해야 하는지에 대한 명확한 지침을 제공하지는 않을 수 있습니다. 하지만 우리는 이 패턴들이 당신이 처한 상황을 이해하고, 왜 그런 일이 일어났는지 파악하며, 앞으로 나아갈 길을 찾는 데 도움이 되기를 바랍니다.&lt;/p&gt;
&lt;h2 id=&quot;작용하는-힘the-forces&quot; data-ke-size=&quot;size26&quot;&gt;작용하는 힘(The Forces)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 아키텍처는 일련의 기술적, 사회적, 경제적 힘들의 균형을 맞추려는 시도의 결과물입니다. '거대한 진흙 덩어리'를 이해하기 위해서는, 아키텍처를 그러한 형태로 몰아가는 강력한 힘들을 이해해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간 (Time): 아마도 가장 강력한 힘일 것입니다. 시장 출시 시간(Time-to-market)은 종종 다른 모든 고려 사항을 압도합니다. &quot;지금 당장 돌아가는 것&quot;은 &quot;나중에 완벽해질 것&quot;보다 거의 항상 더 가치 있습니다. 이 압박은 설계 단계를 건너뛰고, 임시방편을 사용하며, 기술 부채를 쌓도록 유도합니다.&lt;/li&gt;
&lt;li&gt;비용 (Cost): 소프트웨어 개발은 비쌉니다. 숙련된 아키텍트와 개발자를 고용하는 데는 돈이 듭니다. 충분한 시간을 들여 제대로 설계하고 리팩토링하는 데도 돈이 듭니다. 많은 조직은 이러한 장기적인 투자를 감당할 여유가 없거나, 그 가치를 인식하지 못합니다. &quot;가장 저렴한&quot; 솔루션이 선택되는 경우가 많으며, 이는 종종 가장 지저분한 솔루션이기도 합니다.&lt;/li&gt;
&lt;li&gt;경험 (Experience): 좋은 아키텍처를 설계하는 것은 어려운 기술입니다. 경험이 부족한 개발자나 팀은 최선의 의도를 가지고 있더라도 복잡성을 관리하는 방법을 모를 수 있습니다. 그들은 점진적으로 성장하는 시스템의 구조가 어떻게 부식되는지 인식하지 못하고, 결국 자신들이 만든 진흙탕에 빠지게 됩니다.&lt;/li&gt;
&lt;li&gt;변화 (Change): 소프트웨어의 유일한 상수는 변화입니다. 요구사항은 끊임없이 변하고, 기술은 진화하며, 비즈니스 환경도 바뀝니다. 유연하고 적응 가능한 아키텍처를 만드는 것은 어렵습니다. 변화에 대응하기 위해 계속해서 임시방편을 추가하다 보면, 원래의 깔끔했던 구조는 금세 알아볼 수 없게 됩니다.&lt;/li&gt;
&lt;li&gt;복잡성 (Complexity): 소프트웨어는 본질적으로 복잡합니다. 도메인 자체가 복잡할 수 있고, 해결하려는 문제도 복잡할 수 있습니다. 개발자들은 이 복잡성을 관리하기 위해 노력하지만, 때로는 복잡성의 무게에 짓눌리게 됩니다. 추상화는 깨지고, 경계는 무너지며, 모든 것이 서로 얽히기 시작합니다.&lt;/li&gt;
&lt;li&gt;엔트로피 (Entropy): 물리적 시스템과 마찬가지로, 소프트웨어 시스템도 시간이 지남에 따라 무질서해지려는 자연적인 경향이 있습니다. 질서를 유지하기 위해서는 지속적인 에너지 투입, 즉 리팩토링과 유지보수 노력이 필요합니다. 이러한 노력이 없다면, 시스템은 필연적으로 '거대한 진흙 덩어리'로 퇴화할 것입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 힘들은 종종 공모하여 가장 원칙 있는 아키텍트마저도 타협하게 만듭니다. '거대한 진흙 덩어리'는 단순히 나쁜 결정의 결과가 아니라, 이러한 압도적인 현실의 힘에 대한 합리적인 (비록 이상적이지는 않지만) 대응인 경우가 많습니다.&lt;/p&gt;
&lt;h2 id=&quot;1장-거대한-진흙-덩어리-big-ball-of-mud&quot; data-ke-size=&quot;size26&quot;&gt;1장. 거대한 진흙 덩어리 (Big Ball of Mud)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;거대한 진흙 덩어리(Big Ball of Mud)&lt;/b&gt; 는 마구잡이로 구조화되고, 무분별하게 확장되었으며, 엉성하고, 임시방편으로 가득한 스파게티 코드 정글입니다. 이러한 시스템은 규제되지 않은 성장과 반복적인 임시방편 수리의 흔적을 명백하게 보여줍니다. 정보는 시스템의 멀리 떨어진 요소들 사이에서 무분별하게 공유되며, 종종 시스템의 거의 모든 중요 상태(state)를 코드의 어느 부분에서나 수정할 수 있는 지경에 이릅니다. 전체적인 아키텍처는 명확하게 드러나지 않으며, 이를 파악하려는 시도는 좌절감을 안겨주기 쉽습니다. 코드를 들여다보는 사람은 왜 이 시스템이 이렇게 만들어졌는지, 혹은 어떻게 이런 것이 제대로 작동할 수 있는지 이해하기 어렵습니다. 작동은 하지만, 아슬아슬하게 작동할 뿐입니다. 이 시스템에 대해 잘 아는 사람이 아니라면, 어떻게 수정해야 할지 알아내는 것은 거의 불가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴의 이름은 그 경멸적인 어감 때문에 의도적으로 선택되었습니다. 다른 사람들이 이러한 시스템을 묘사할 때 처음 사용했던 용어이기도 합니다. 하지만 이 패턴은 '안티패턴(anti-pattern)'의 한 예로 볼 수 있습니다. 안티패턴은 문제에 대한 나쁜 해결책을 설명하는 패턴입니다. 그렇다면 왜 우리는 이 패턴을 굳이 문서화해야 할까요? 왜냐하면 이 패턴이 너무나도 흔하게 나타나기 때문입니다. 이것은 사실상의 표준(de facto standard) 아키텍처입니다. 모든 아키텍트, 설계자, 프로그래머는 커리어 초반에 이런 시스템을 적어도 하나는 마주치게 되며, 종종 혐오감을 느끼며 그곳을 떠나게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 이렇게 많은 시스템이 이런 모습일까요? 어쩌면 이 질문에 대한 답은 명백한지도 모릅니다. 비용과 일정 압박이 그 원인일 수 있습니다. 아마도 개발팀에 숙련된 아키텍트가 없었거나, 있었더라도 그들의 말을 아무도 듣지 않았을 수 있습니다. 어쩌면 담당자들이 너무 빨리 교체되어 누구도 프로젝트의 큰 그림에 책임감을 느끼지 않았을 수도 있습니다. 혹은 고객이 프로토타입을 보고는 &quot;좋네요, 바로 출시합시다!&quot;라고 말했을지도 모릅니다. 아니면 뛰어난 개발자가 떠나고, 그를 대체한 평범한 개발자들이 남은 시스템을 유지보수해야 했을 수도 있습니다. 답은 간단합니다: 이 방식이 쉽기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숙련된 객체지향 아키텍트가 처음부터 모든 것을 제대로 설계하고 싶어 하는 동안, 다른 사람들은 이미 코드를 짜고 무언가를 동작시키고 있습니다. 프로젝트 아키텍처 진화의 혼란스러운 초기 단계 동안, 프로토타입은 종종 '거대한 진흙 덩어리'로 시작합니다. 이 혼돈은 새로운 아이디어가 시험되고, 실험이 이루어지고, 버려지는 과정에서 생겨나는 자연스러운 결과물일 수 있습니다. 이것이 바로 가장 저항이 적은 길(the path of least resistance)인 셈입니다. 우리가 이상적으로 생각하는, 신중하고 우아하며 잘 구조화된 시스템을 구축하는 데에는 시간, 기술, 그리고 규율이 필요합니다. 지저분한 것을 만드는 데는 그런 것들이 별로 필요하지 않습니다. 엔트로피의 힘이 언제나 우리를 압박합니다. 시스템은 질서정연하게 유지되려는 경향보다 무질서해지려는 경향이 더 강합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로, '거대한 진흙 덩어리' 패턴에서 가장 눈에 띄는 점 중 하나는, 그 이름에도 불구하고 꽤 인기 있고 성공적인 아키텍처 스타일이라는 역설입니다. 이러한 시스템은 자주 나타나고 오래 살아남습니다. 왜 그럴까요? 제대로 작동하기 때문입니다. 적어도 대부분의 경우에 말이죠. 이 시스템들은 시장 출시 시간(time-to-market)과 개발 비용이라는 두 가지 매우 중요한 요구사항을 충족시킵니다. 이런 시스템을 만드는 개발자들은 아마도 건축가(architects)가 아닐 수도 있고, 그들이 만든 시스템이 아름답지 않을 수도 있습니다. 하지만 그들은 가치를 전달하고 있습니다. 이런 시스템의 생존을 가능하게 하는 특징 중 하나는, 바로 그 시스템을 만든 사람들이 시스템의 작동 방식에 대해 깊이 이해하고 있다는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아키텍처는 설계와 구축의 예술이자 과학입니다. 아키텍처는 공간, 형태, 질감, 재료, 그리고 이들을 하나로 묶는 원칙들 간의 상호작용을 다룹니다. 우리는 도시, 대성당, 심지어 오두막집에서도 아키텍처를 볼 수 있습니다. 그것들은 물리적 힘뿐만 아니라 그것을 만든 사람들의 미학, 문화, 경제, 기술적 역량을 반영합니다. 시스템의 아키텍처는 그 형태를 잡아주는 뼈대와 같습니다. 그것은 시스템의 핵심 추상화와 메커니즘을 구성하는 부품들의 배열입니다. 아키텍처는 부품들이 어떻게 맞춰지고, 어떤 원칙으로 조립되는지를 결정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 다양한 힘들이 종종 공모하여 가장 원칙을 잘 지키는 아키텍트마저도 원칙을 타협하게(cut corners) 만듭니다. 시간은 항상 부족합니다. 우리는 코드를 더 빨리 완성해야 합니다. 우리는 &quot;나중에 고치겠다&quot;고 스스로에게 약속합니다. 그리고 물론, 우리는 재사용할 수 있는 무언가를 만들어야 합니다. 하지만 지금 당장은 이 특별한 경우만 처리하면 됩니다. 점차 시스템의 구조는 부식됩니다. 엔트로피는 다시 한번 그 힘을 발휘합니다.&lt;/p&gt;
&lt;h2 id=&quot;일회용-코드-throwaway-code&quot; data-ke-size=&quot;size26&quot;&gt;일회용 코드 (Throwaway Code)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때로는 가장 좋은 방법이 처음부터 다시 시작하는 것일 때도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 브룩스, 『맨먼스 미신』&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴의 또 다른 이름은 &lt;b&gt;프로토타이핑(Prototyping)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 코드는 임시방편으로 만들어집니다. 프로토타입은 새로운 기능의 타당성을 탐구하거나, 인터페이스를 시연하거나, 특정 기술의 작동 방식을 알아내기 위해 만들어질 수 있습니다. 이러한 코드는 처음부터 버려질 운명으로 태어납니다. 사실, 그것이 버려지지 않는다면 문제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 종류의 코드에 대한 문제는 그것이 너무 자주 살아남는다는 점입니다. 관리자는 프로토타입을 보고 눈이 휘둥그레집니다. &quot;이 정도면 거의 다 됐잖아, 안 그래? 조금만 더 다듬으면 출시할 수 있겠어.&quot; 고객은 데모를 보고 이렇게 말합니다. &quot;좋네요, 바로 출시합시다!&quot;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로토타입은 성공적이었습니다. 문제는 사람들이 그것을 버리려 하지 않는다는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 브룩스, 『맨먼스 미신』&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황은 프로토타입을 만든 프로그래머에게 엄청난 딜레마를 안겨줍니다. 프로그래머는 자신이 짠 코드가 얼마나 엉성하고, 얼마나 많은 임시방편을 사용했는지 알고 있습니다. 코드가 제대로 돌아간다는 사실 자체가 놀라울 정도입니다. 코드는 오류 처리, 견고성, 확장성을 전혀 고려하지 않았습니다. 하지만 이제 고객, 혹은 더 나쁘게는 자신의 상사가 그 코드가 거의 완성되었다고 생각합니다. 어떻게 &quot;아니요&quot;라고 말할 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황을 피하는 한 가지 방법은 프로토타입을 매우 다른 언어나 환경에서 개발하는 것입니다. 예를 들어, Visual Basic으로 프로토타입을 만든 다음 C++로 최종 제품을 개발하는 식입니다. 이렇게 하면 프로토타입 코드가 최종 제품에 몰래 포함될 가능성이 거의 없습니다. 하지만 프로토타입을 버리는 것은 비용이 듭니다. 프로토타입을 만드는 데 걸린 시간은 프로젝트 일정에 추가되어야 합니다. 또한, C++로 다시 작성하는 과정에서 프로토타입이 가지고 있던 미묘한 기능 중 일부가 사라질 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 현실적인 선택지가 C++밖에 없다고 가정해 봅시다. 여기서 딜레마가 생깁니다. 한편으로, 프로토타입을 제대로 설계하면 버려야 할 때 그 비용이 너무 커 보일 수 있습니다. 반면에, 엉성하게 만들면 프로토타입이 결국 제품이 되어버릴 위험이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌면 프로그래머는 그냥 코드를 버려야 할지도 모릅니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;자, 이봐, 이 코드는 진짜 쓰레기야. 나한테 6개월만 더 주면 처음부터 제대로 만들 수 있어.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;안 돼, 시간 없어.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래머가 패배하고, '일회용 코드'가 살아남으면, 그 코드는 새로운 시스템의 핵심이 될 수 있습니다. 종종, 전체 시스템이 이 코드 주위에서 자라나며, 이 코드는 마치 암세포처럼 자신의 부실한 구조를 주변으로 퍼뜨립니다. 원래 '일회용'이었던 설계 결정들이 갑자기 시스템 아키텍처의 일부가 되어버립니다. 이러한 결정 중 일부는 쉽게 바꿀 수 없을 수도 있습니다. 예를 들어, 특정 데이터베이스 스키마나 특정 운영 체제에 대한 의존성 같은 것들 말입니다. 심지어 이런 초기의 설계 결정들이 부적절하다는 것이 밝혀지더라도, 시스템은 운명적으로 그 결정에 묶여 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토타입이 완전한 시스템으로 진화할 때, 초기 코드는 종종 시스템의 유일한 &quot;깨끗한&quot; 부분이 됩니다. 이 코드는 시스템의 핵심이 되는 명확하고 간단한 모델을 가지고 있기 때문입니다. 하지만 시스템이 성장하고, 새로운 요구사항에 적응하면서, 복잡성을 제어하기 위한 노력이 없다면 초기의 우아함은 금세 사라질 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과적으로 '일회용 코드'는 &lt;b&gt;거대한 진흙 덩어리(Big Ball of Mud)&lt;/b&gt;를 낳는 가장 흔한 원인 중 하나입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'일회용 코드'는 단순히 프로토타입에만 국한되지 않습니다. 때로는 어떤 기능이 일시적으로만 필요할 것이라고 생각할 때가 있습니다. 예를 들어, 특정 파일 형식을 변환하는 코드를 작성했지만, 그 파일 형식은 곧 폐기될 예정입니다. 그렇다면 왜 이 코드를 깨끗하고 견고하게 만들어야 할까요? 물론, 그 파일 형식이 20년 후에도 여전히 사용될 것이라고는 아무도 예상하지 못했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 &lt;b&gt;점진적 개발(Incremental Development)&lt;/b&gt;을 실천할 때, 우리는 본질적으로 일련의 '일회용 코드'를 작성하게 됩니다. 각 단계에서 우리는 현재의 요구사항을 충족시키기 위해 최소한의 코드를 작성합니다. 그런 다음 다음 단계로 넘어가면서, 우리는 시스템의 요구사항을 더 잘 이해하게 됨에 따라 코드를 수정하고 확장합니다. 만약 우리가 운이 좋다면, 이전 단계에서 내린 설계 결정들이 다음 단계에서도 여전히 유효할 것입니다. 하지만 그렇지 않다면, 우리는 코드를 다시 작성해야 합니다. 이 과정에서 우리는 이전 코드의 일부 또는 전부를 버리게 됩니다. 점진적 개발은 프로토타이핑과 유사하지만, 각 단계가 더 작고, 코드를 버리는 비용이 덜 든다는 점에서 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴의 핵심은 코드가 버려질 수 있다는 가능성을 인식하는 것입니다. 버려질 코드에 과도하게 투자하지 않는 것과, 그 코드가 살아남을 경우를 대비하는 것 사이에서 균형을 잡아야 합니다.&lt;/p&gt;
&lt;h2 id=&quot;점진적-성장-piecemeal-growth&quot; data-ke-size=&quot;size26&quot;&gt;점진적 성장 (Piecemeal Growth)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그들은 모든 것을 한꺼번에 설계하는 것이 불가능하다는 것을 오래전에 깨달았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 크리스토퍼 알렉산더, 『시간을 초월한 건설의 길』&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴의 또 다른 이름은 &lt;b&gt;점진적 개발(Incremental Development)&lt;/b&gt;, &lt;b&gt;프랙탈 설계(Fractal Design)&lt;/b&gt;, &lt;b&gt;파이 나누기(Pie &amp;agrave; la Mode)&lt;/b&gt;, 혹은 &lt;b&gt;반복적 리파인먼트(Iterative Refinement)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공적인 소프트웨어 시스템은 거의 모두 처음부터 완벽하게 설계되지 않았습니다. 성공적인 시스템은 작동하는 더 단순한 시스템에서 진화한 것입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 시스템을 처음부터 완벽하게 만들 수 있다는 생각을 버려야 합니다. 대신, 우리는 시스템이 성장하고, 변화하고, 끊임없이 개선될 수 있도록 시스템을 만들어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 크리스토퍼 알렉산더, 『시간을 초월한 건설의 길』&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 소프트웨어 설계에 대한 깊은 통찰입니다. 너무나 많은 프로젝트가 야심 찬 목표를 가지고 시작하지만, 결국 실패로 끝납니다. 그 이유는 종종 설계자들이 처음부터 모든 것을 올바르게 만들려고 너무 애쓰기 때문입니다. 하지만 현실은, 우리가 시스템의 요구사항을 미리 완벽하게 예측할 수 없다는 것입니다. 요구사항은 시간이 지남에 따라 변하고, 우리는 시스템을 구축하면서 더 많은 것을 배우게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 가장 좋은 접근 방식은 작게 시작하는 것입니다. 먼저 시스템의 핵심 기능을 구현하는 작은 버전을 만듭니다. 그런 다음, 이 버전을 기반으로 점진적으로 기능을 추가하고 개선해 나갑니다. 각 단계에서 우리는 시스템이 여전히 작동하는지, 그리고 올바른 방향으로 가고 있는지를 확인합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 접근 방식은 건축가 크리스토퍼 알렉산더가 건물과 도시에 대해 제안한 아이디어와 유사합니다. 그는 도시가 하나의 거대한 계획에 따라 한 번에 건설될 때보다, 시간이 지남에 따라 점진적으로 성장하고 변화할 때 더 살아있고, 더 아름답고, 더 기능적이 된다고 주장했습니다. 그는 이 과정을 &lt;b&gt;&quot;점진적 성장(Piecemeal Growth)&quot;&lt;/b&gt;이라고 불렀습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어에서도 같은 원리가 적용됩니다. 시스템은 유기체와 같습니다. 시스템은 시간이 지남에 따라 성장하고 변화해야 합니다. 우리의 역할은 그 성장을 안내하고, 시스템이 건강하고 일관된 구조를 유지하도록 돕는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'점진적 성장'의 한 가지 중요한 측면은 &lt;b&gt;리팩토링(Refactoring)&lt;/b&gt;입니다. 리팩토링은 코드의 외부 동작을 바꾸지 않으면서 내부 구조를 개선하는 과정입니다. 시스템에 새로운 기능을 추가할 때, 우리는 종종 기존 코드를 변경해야 합니다. 이때 리팩토링을 통해 코드의 구조를 정리하고, 중복을 제거하며, 이해하기 쉽게 만들 수 있습니다. 이렇게 함으로써 우리는 시스템이 복잡성의 무게에 짓눌리지 않고 계속해서 성장할 수 있도록 돕습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새로운 기능이 기존 아키텍처에 깔끔하게 들어맞지 않는 경우가 있을 수 있습니다. 이런 경우, 우리는 기존 아키텍처를 약간 수정하여 새로운 기능을 수용해야 할 수도 있습니다. 또는, 새로운 기능이 너무 달라서 별도의 컴포넌트로 분리해야 할 수도 있습니다. 핵심은 아키텍처가 고정된 것이 아니라, 시스템의 요구사항에 따라 진화할 수 있어야 한다는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 아키텍처는 시스템이 성장하고 변화할 수 있도록 허용하는 동시에, 전체적인 일관성과 무결성을 유지하는 역할을 해야 합니다. 이것은 섬세한 균형 잡기입니다. 너무 많은 제약은 성장을 방해할 수 있고, 너무 적은 제약은 혼돈으로 이어질 수 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 시스템을 처음부터 설계하는 것은 본질적으로 오류가 발생하기 쉬운 활동입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 존슨과 푸트, 『객체 지향 시스템 설계』&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향 설계와 프레임워크는 이러한 종류의 점진적 성장을 지원하는 데 특히 효과적입니다. 객체는 잘 정의된 인터페이스 뒤에 복잡성을 숨길 수 있게 해주며, 프레임워크는 재사용 가능한 아키텍처 구조를 제공합니다. 이러한 도구를 사용하면, 우리는 시스템의 다른 부분에 미치는 영향을 최소화하면서 개별 부분을 수정하고 확장할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, 모든 성공적인 대규모 시스템은 작은 시스템에서 시작하여 시간이 지남에 따라 성장하고 진화한 결과물입니다. 그 과정에서 많은 실수와 막다른 골목이 있었을 것입니다. 하지만 각 단계를 통해 시스템은 더 강해지고, 더 견고해지고, 더 유용해졌습니다. 이것이 바로 &lt;b&gt;거대한 진흙 덩어리(Big Ball of Mud)&lt;/b&gt;가 때로는 성공적인 시스템의 불가피한 부산물인 이유입니다. 그것은 완벽한 계획의 결과물이 아니라, 유기적인 성장의 결과물입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 임무는 이 성장을 관리하고, 시스템이 진흙탕에 빠지지 않도록 하는 것입니다. 우리는 깨끗하고, 잘 구조화되고, 이해하기 쉬운 코드를 작성하려고 노력해야 합니다. 하지만 동시에 우리는 완벽함이 좋은 것의 적이 될 수 있다는 것을 인정해야 합니다. 때로는 &quot;그럭저럭 괜찮은(good enough)&quot; 시스템을 만드는 것이 전혀 시스템을 만들지 못하는 것보다 낫습니다.&lt;/p&gt;
&lt;h2 id=&quot;계속-작동하게-하라-keep-it-working&quot; data-ke-size=&quot;size26&quot;&gt;계속 작동하게 하라 (Keep it Working)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 빌드하고, 매일 테스트하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 짐 코플리엔&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴의 또 다른 이름은 &lt;b&gt;매일 빌드하고 스모크 테스트하기(Daily Build and Smoke Test)&lt;/b&gt;, &lt;b&gt;지속적 통합(Continuous Integration)&lt;/b&gt;, 혹은 &lt;b&gt;생명 유지 장치(Life Support)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템을 점진적으로 변경할 때, 가장 중요한 규칙 중 하나는 &lt;b&gt;&quot;시스템을 망가뜨리지 말라&quot;&lt;/b&gt;는 것입니다. 새로운 기능을 추가하거나 기존 코드를 리팩토링하는 과정에서, 시스템이 이전처럼 작동하지 않게 만드는 것은 매우 쉽습니다. 이런 일이 발생하면, 무엇이 잘못되었는지 찾아내고 수정하는 데 많은 시간을 낭비하게 될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 중요한 원칙은 변경을 작은 단위로 나누고, 각 변경 후에 시스템이 여전히 올바르게 작동하는지 확인하는 것입니다. 이렇게 하면, 문제가 발생했을 때 방금 변경한 작은 부분만 살펴보면 되므로 원인을 훨씬 쉽게 찾을 수 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결코 깨진 창문을 내버려 두지 말라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 헌트와 토머스, 『실용주의 프로그래머』&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 원칙을 실천하는 가장 좋은 방법 중 하나는 &lt;b&gt;자동화된 테스트 스위트(automated test suite)&lt;/b&gt;를 갖추는 것입니다. 코드를 변경할 때마다 이 테스트 스위트를 실행하여 시스템의 핵심 기능이 여전히 제대로 작동하는지 확인할 수 있습니다. 테스트가 실패하면, 코드를 커밋하기 전에 문제를 수정해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XP(eXtreme Programming) 커뮤니티는 이 아이디어를 한 단계 더 발전시켜 &lt;b&gt;테스트 주도 개발(Test-Driven Development, TDD)&lt;/b&gt;이라는 개념을 도입했습니다. TDD에서는 실제 코드를 작성하기 전에 먼저 실패하는 테스트 케이스를 작성합니다. 그런 다음, 그 테스트를 통과할 만큼만 코드를 작성합니다. 이 과정을 반복하면서 점진적으로 시스템을 구축해 나갑니다. 이 접근 방식은 항상 작동하는 코드를 유지하는 데 도움이 될 뿐만 아니라, 설계에 대해서도 더 깊이 생각하게 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 프로젝트에서는 여러 개발자가 동시에 코드를 변경하기 때문에 상황이 더 복잡해집니다. 한 개발자의 변경 사항이 다른 개발자의 작업을 망가뜨릴 수 있습니다. 이러한 문제를 해결하기 위해, 많은 팀이 &lt;b&gt;매일 빌드(Daily Build)&lt;/b&gt; 또는 &lt;b&gt;지속적 통합(Continuous Integration)&lt;/b&gt;이라는 관행을 채택합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 접근 방식에서는 모든 개발자가 하루에 최소 한 번 이상 자신의 변경 사항을 중앙 코드 저장소에 통합합니다. 그런 다음, 자동화된 빌드 시스템이 전체 시스템을 처음부터 다시 빌드하고, 모든 테스트를 실행합니다. 만약 빌드나 테스트가 실패하면, 팀 전체에 즉시 알려집니다. 그러면 팀은 다른 작업을 하기 전에 먼저 이 문제를 해결하는 데 집중해야 합니다. &quot;빌드를 고치는 것&quot;이 최우선 순위가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 관행은 시스템이 항상 &quot;건강한&quot; 상태를 유지하도록 보장합니다. 개발자들은 자신의 변경 사항이 전체 시스템에 어떤 영향을 미치는지 즉시 피드백을 받을 수 있으며, 문제가 발생하더라도 초기에 발견하여 쉽게 해결할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;거대한 진흙 덩어리(Big Ball of Mud)&lt;/b&gt;와 같은 복잡한 시스템을 다룰 때, 이 원칙은 특히 더 중요합니다. 시스템의 구조가 명확하지 않고, 변경의 영향을 예측하기 어렵기 때문입니다. 이런 시스템에서는 작은 변경조차도 예상치 못한 부작용을 일으킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황에서 자동화된 테스트와 지속적 통합은 생명줄과도 같습니다. 그것들은 우리가 어둠 속에서 길을 잃지 않도록 도와주는 안전망 역할을 합니다. 우리는 시스템의 복잡한 내부를 완전히 이해하지 못할 수도 있지만, 적어도 우리가 시스템을 망가뜨리지 않았다는 확신을 가질 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 당신이 낡고, 복잡하고, 지저분한 시스템을 유지보수하는 임무를 맡았다면, 가장 먼저 해야 할 일 중 하나는 테스트 스위트를 구축하는 것입니다. 처음에는 어려울 수 있습니다. 코드가 테스트하기 어렵게 작성되었을 수도 있습니다. 하지만 이 노력은 장기적으로 큰 보상을 가져다줄 것입니다. 테스트가 없다면, 당신은 사실상 눈을 가리고 코드를 변경하는 것과 같습니다. 테스트가 있다면, 당신은 자신감을 가지고 시스템을 개선하고 리팩토링할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로, 시스템을 계속 작동하게 유지하는 것은 점진적 개발의 핵심 전제 조건입니다. 그것이 없다면, 점진적 개선은 불가능하며, 시스템은 결국 붕괴될 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;계층-분리하기shearing-layers&quot; data-ke-size=&quot;size26&quot;&gt;계층 분리하기(Shearing Layers)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 변화율이 다른 시스템의 각기 다른 부분들을 분리하는 법을 배워야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 브루스 블레어(Bruce Blair)가 스튜어트 브랜드(Stewart Brand)를 인용한 말&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴의 또 다른 이름은 &lt;b&gt;변화율에 따른 계층화(Layers by Rate of Change)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;건축가 프랭크 더피(Frank Duffy)는 건물이 여러 계층으로 구성되어 있으며, 각 계층은 서로 다른 수명 주기를 가지고 변화한다고 관찰했습니다. 스튜어트 브랜드는 그의 저서 『How Buildings Learn』에서 이 아이디어를 다음과 같이 정교하게 설명합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;부지 (Site):&lt;/b&gt; 영원하다. 지리적인 위치.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구조물 (Structure):&lt;/b&gt; 30년에서 300년. 기초와 뼈대.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외피 (Skin):&lt;/b&gt; 약 20년. 외부 마감재, 창문 등.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서비스 (Services):&lt;/b&gt; 7년에서 15년. 배관, 전기, HVAC(냉난방공조) 시스템.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간 계획 (Space Plan):&lt;/b&gt; 3년. 내부 벽, 천장, 문.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가구 (Stuff):&lt;/b&gt; 매달 또는 매일. 의자, 책상, 램프.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브랜드는 건물에 문제가 생기는 주요 원인 중 하나가, 변화 속도가 다른 계층들이 서로 얽혀있기 때문이라고 지적합니다. 예를 들어, 건물의 구조물 기둥 안에 전기 배선을 집어넣으면, 나중에 전기 시스템을 업그레이드하기가 매우 어려워집니다. 빠르게 변해야 할 '서비스' 계층이 느리게 변하는 '구조물' 계층에 꽉 묶여버리기 때문입니다. 현명한 설계는 이러한 &lt;b&gt;분리 계층(Shearing Layers)&lt;/b&gt;을 인식하고, 각 계층이 독립적으로 유지보수되고 교체될 수 있도록 하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 시스템도 이와 매우 유사한 계층 구조를 가지고 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;플랫폼 (Platform):&lt;/b&gt; 하드웨어, 운영 체제, 데이터베이스 등은 매우 느리게 변합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;핵심 비즈니스 로직 (Core Business Logic):&lt;/b&gt; 비교적 안정적이지만, 비즈니스 환경 변화에 따라 점진적으로 진화합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;애플리케이션 인프라 (Application Infrastructure):&lt;/b&gt; 통신, UI 프레임워크 등은 몇 년 주기로 변할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자 인터페이스 (User Interface):&lt;/b&gt; 가장 자주 변하는 부분 중 하나입니다. 패션처럼 유행이 계속 바뀝니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스크립트 및 설정 (Scripts and Configuration):&lt;/b&gt; 매일 또는 매주 바뀔 수 있는 부분입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;거대한 진흙 덩어리(Big Ball of Mud)&lt;/b&gt;의 주요 문제 중 하나는 이러한 계층들이 서로 뒤엉켜 있다는 것입니다. 예를 들어, 비즈니스 로직 코드 안에 SQL 쿼리가 직접 박혀있거나, UI 코드 안에 비즈니스 규칙이 섞여 있는 경우입니다. 이렇게 되면, 데이터베이스 스키마를 약간 변경하는 것이 전체 시스템에 파급 효과를 일으키거나, 버튼 색깔 하나 바꾸려다가 중요한 비즈니스 로직을 건드리는 실수를 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 훌륭한 아키텍처의 핵심 역할 중 하나는, 변화율이 다른 코드들을 서로 분리하는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 고전적인 예는 &lt;b&gt;모델-뷰-컨트롤러(Model-View-Controller, MVC)&lt;/b&gt; 패턴입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모델 (Model):&lt;/b&gt; 핵심 데이터와 비즈니스 로직을 담당합니다. 비교적 안정적인 계층입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;뷰 (View):&lt;/b&gt; 사용자에게 정보를 보여주는 역할을 합니다. 자주 바뀌는 계층입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컨트롤러 (Controller):&lt;/b&gt; 사용자 입력을 받아 모델이나 뷰를 제어합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MVC는 UI(뷰)의 잦은 변경이 핵심 비즈니스 로직(모델)에 영향을 주지 않도록 분리하는 효과적인 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 접근 계층(Data Access Layer, DAL)을 두는 것도 '분리 계층'의 좋은 예입니다. 비즈니스 로직이 특정 데이터베이스 기술(예: Oracle, MySQL)에 직접 의존하지 않고, 추상화된 데이터 접근 인터페이스를 통해 소통하게 만듭니다. 이렇게 하면 나중에 데이터베이스를 교체하더라도, 비즈니스 로직 코드를 거의 수정하지 않고 데이터 접근 계층만 새로 구현하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 프레임워크는 종종 이러한 '분리 계층' 원칙을 내장하고 있습니다. 프레임워크는 안정적인 기반(구조물)을 제공하고, 개발자는 그 위에서 빠르게 변하는 애플리케이션 로직(공간 계획, 가구)을 구축할 수 있도록 돕습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 완벽한 분리는 현실적으로 어렵습니다. 계층 간의 인터페이스는 여전히 존재하며, 이 인터페이스 자체도 진화해야 할 때가 있습니다. 그럼에도 불구하고, 변화율을 기준으로 시스템을 계층화하려는 노력은 장기적인 유지보수성과 유연성을 크게 향상시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당신이 '거대한 진흙 덩어리'를 마주했다면, 시스템의 어떤 부분이 더 자주 변하고 어떤 부분이 더 안정적인지 식별하는 것부터 시작해 보세요. 그런 다음, 가장 변화가 잦은 부분(예: UI)을 안정적인 부분(예: 비즈니스 로직)으로부터 분리해내는 리팩토링을 시도할 수 있습니다. 이것은 진흙 덩어리를 풀어헤치는 중요한 첫걸음이 될 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;문제를-카펫-밑으로-쓸어넣기-sweeping-it-under-the-rug&quot; data-ke-size=&quot;size26&quot;&gt;문제를 카펫 밑으로 쓸어넣기 (Sweeping it under the Rug)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡성은 신성하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 테드 넬슨, 『컴퓨터 리브/드림 머신』&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴의 또 다른 이름은 &lt;b&gt;유예(Potemkin Village)&lt;/b&gt;, &lt;b&gt;추상화(Abstraction)&lt;/b&gt;, 또는 &lt;b&gt;외관(Fa&amp;ccedil;ade)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 문제가 깔끔하게 해결될 수 있는 것은 아닙니다. 때로는 어떤 부분이 너무 복잡하고, 너무 지저분하고, 너무 다루기 힘들어서 제대로 정리할 엄두가 나지 않을 때가 있습니다. 이 코드는 아마도 오래된 레거시 시스템의 일부이거나, 외부 라이브러리의 지저분한 인터페이스이거나, 혹은 그냥 우리가 아직 완전히 이해하지 못한 부분일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황에서 우리가 할 수 있는 최선의 방법은 그 복잡성을 깔끔한 카펫 밑으로 쓸어넣어 숨기는 것입니다. 즉, 지저분한 코드 덩어리 주위에 잘 정의된, 단순하고 명확한 &lt;b&gt;인터페이스(API)&lt;/b&gt;를 만드는 것입니다. 이 인터페이스는 그 뒤에 숨겨진 혼돈을 가려주는 &lt;b&gt;외관(Fa&amp;ccedil;ade)&lt;/b&gt; 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템의 나머지 부분은 이제 이 깔끔한 외관하고만 상호작용하면 됩니다. 그들은 카펫 밑에 무엇이 있는지 알 필요가 없습니다. 그들은 단지 &quot;이 함수를 호출하면 원하는 결과를 얻을 수 있다&quot;는 사실만 알면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 완벽한 해결책이 아닙니다. 복잡성 자체가 사라진 것은 아니기 때문입니다. 우리는 단지 문제를 한 곳에 격리하고, 그 영향력이 시스템의 다른 부분으로 퍼져나가지 않도록 막은 것뿐입니다. 이것은 일종의 전략적 후퇴이자, 현실과의 타협입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 매우 복잡하고 사용하기 어려운 서드파티 라이브러리를 사용해야 한다고 가정해 봅시다. 이 라이브러리의 함수들을 시스템 곳곳에서 직접 호출하는 대신, 우리는 &lt;b&gt;어댑터(Adapter)&lt;/b&gt; 또는 &lt;b&gt;래퍼(Wrapper)&lt;/b&gt; 클래스를 만들 수 있습니다. 이 클래스는 우리 시스템에 필요한 기능만을 단순하고 일관된 방식으로 노출합니다. 그러면 우리 애플리케이션 코드는 이 복잡한 라이브러리의 세부 사항을 전혀 몰라도 됩니다. 나중에 이 라이브러리를 다른 것으로 교체해야 할 때도, 우리는 이 어댑터 클래스만 수정하면 되므로 변경의 범위가 크게 줄어듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;거대한 진흙 덩어리(Big Ball of Mud)&lt;/b&gt;를 다룰 때 이 전략은 매우 유용합니다. 진흙 덩어리 전체를 한 번에 리팩토링하는 것은 거의 불가능합니다. 대신, 우리는 진흙 덩어리의 특정 부분을 식별하고, 그 주위에 명확한 경계를 설정할 수 있습니다. 즉, 진흙 덩어리의 일부 기능을 노출하는 깔끔한 API를 정의하는 것입니다. 그러면 새로 작성되는 코드는 이 API를 통해 진흙 덩어리와 상호작용하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간이 지남에 따라, 우리는 점차적으로 진흙 덩어리에 의존하는 낡은 코드를 이 새로운 API를 사용하도록 수정할 수 있습니다. 그리고 궁극적으로는, 카펫 밑에 있는 지저분한 코드를 완전히 새로운 구현으로 교체할 수도 있습니다. 이 모든 과정 동안 시스템의 나머지 부분은 아무런 영향을 받지 않습니다. 왜냐하면 그들은 처음부터 안정적인 '외관'하고만 소통해 왔기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 접근 방식의 위험성은, 카펫 밑에 있는 문제가 잊혀질 수 있다는 것입니다. &quot;눈에서 멀어지면, 마음에서도 멀어진다&quot;는 말이 있습니다. 인터페이스가 너무 잘 작동해서 아무도 그 뒤에 있는 끔찍한 코드를 고치려고 하지 않을 수 있습니다. 그 문제는 다음 세대의 불운한 유지보수 개발자에게 그대로 남겨질 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, '외관'이 너무 단순화되어 내부의 중요한 세부 사항이나 유연성을 가려버리는 경우도 있습니다. 때로는 사용자가 카펫 밑을 들여다보고 내부의 복잡성을 직접 다루어야 할 필요가 있을 수 있습니다. 좋은 '외관' 디자인은 이러한 &quot;탈출구(escape hatch)&quot;를 제공하여 필요할 때 더 낮은 수준의 제어를 허용해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론적으로, &quot;문제를 카펫 밑으로 쓸어넣기&quot;는 이상적인 해결책은 아닙니다. 하지만 제한된 시간과 자원 속에서 복잡성을 관리해야 하는 현실 세계에서는 매우 실용적이고 효과적인 전략입니다. 그것은 우리가 완벽함을 추구하다가 아무것도 하지 못하는 상황을 피하고, 대신 점진적으로 시스템을 개선해 나갈 수 있도록 도와줍니다.&lt;/p&gt;
&lt;h2 id=&quot;재건축-reconstruction&quot; data-ke-size=&quot;size26&quot;&gt;재건축 (Reconstruction)&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도시를 한 번에 전부 재건축하려는 계획은 언제나 실패로 끝났다. 성공적인 것은 언제나 점진적인 재건축이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;mdash; 크리스토퍼 알렉산더, 『시간을 초월한 건설의 길』&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴의 또 다른 이름은 &lt;b&gt;빅 리라이트(Big Rewrite)&lt;/b&gt;, &lt;b&gt;갈아엎기(Throw it Away and Start Over)&lt;/b&gt;, 혹은 &lt;b&gt;총체적 리팩토링(Total Refactoring)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때로는 시스템이 너무 낡고, 너무 복잡하고, 너무 엉망진창이 되어서 더 이상 점진적인 개선이 의미가 없는 지점에 도달합니다. 코드는 부서지기 쉽고, 아무도 전체 구조를 이해하지 못하며, 작은 변경 하나가 예측할 수 없는 연쇄적인 실패를 일으킵니다. 기술 부채는 감당할 수 없을 정도로 쌓였고, 이자만 겨우 갚아나가고 있는 실정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황에서 유일한 선택지는 &lt;b&gt;재건축&lt;/b&gt;, 즉 시스템을 처음부터 다시 작성하는 것일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 매우 유혹적인 아이디어입니다. 과거의 모든 실수, 모든 잘못된 결정, 모든 임시방편을 버리고, 우리가 그동안 배운 모든 것을 바탕으로 깨끗하고, 우아하고, 완벽한 시스템을 만들 기회입니다. 더 이상 진흙은 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 '빅 리라이트'는 엄청나게 위험하고 비용이 많이 드는 전략입니다. 많은 프로젝트가 이 길을 선택했다가 장렬하게 실패했습니다. 왜 그럴까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째, 기존 시스템은 겉보기에는 엉망일지 몰라도, &lt;b&gt;작동하고 있습니다.&lt;/b&gt; 그 안에는 수년간의 경험과 시행착오를 통해 축적된 수많은 미묘한 비즈니스 규칙과 예외 처리가 녹아 있습니다. 이 모든 지식을 문서화하거나 새로운 시스템으로 완벽하게 옮기는 것은 거의 불가능합니다. &quot;Second-System Effect(두 번째 시스템 효과)&quot;라는 함정에 빠지기 쉽습니다. 즉, 첫 시스템의 단점을 보완하려다 너무 많은 기능을 넣어서 지나치게 복잡하고 거대한 시스템을 만들게 되는 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째, 재건축 프로젝트는 시간이 매우 오래 걸립니다. 새로운 시스템이 기존 시스템의 모든 기능을 따라잡는 데 몇 년이 걸릴 수도 있습니다. 그동안 기존 시스템은 계속해서 유지보수되고 새로운 기능이 추가되어야 합니다. 이것은 &quot;움직이는 과녁을 맞추려는&quot; 것과 같습니다. 새로운 시스템이 완성될 때쯤이면, 기존 시스템은 이미 저만치 앞서가 있을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋째, 비즈니스 관점에서 볼 때, 재건축은 당장 새로운 가치를 창출하지 않습니다. 회사는 몇 년 동안 막대한 돈을 투자하지만, 결과물은 단지 '기존에 하던 일을 새로운 기술로 다시 하는 것'일 뿐입니다. 경영진이 이 프로젝트를 끝까지 지원해 줄 것이라는 보장은 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 '재건축'은 항상 나쁜 생각일까요? 그렇지는 않습니다. 때로는 그것이 유일한 방법일 수 있습니다. 예를 들어, 시스템이 기반으로 하는 기술(플랫폼, 언어 등)이 완전히 사장되어 더 이상 지원을 받을 수 없을 때, 또는 시스템의 아키텍처가 비즈니스의 근본적인 변화를 도저히 수용할 수 없을 때 재건축이 필요할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공적인 재건축의 핵심은 종종 &lt;b&gt;점진적인 접근&lt;/b&gt;입니다. 전체 시스템을 한 번에 바꾸려고 하는 대신, 시스템의 한 부분을 선택하여 그것을 먼저 재건축합니다. 예를 들어, &lt;b&gt;스트랭글러 패턴(Strangler Fig Pattern)&lt;/b&gt;을 사용할 수 있습니다. 새로운 시스템이 낡은 시스템을 서서히 &quot;휘감아 조르듯이&quot; 대체하는 전략입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 낡은 시스템의 특정 기능에 대한 요청을 가로채는 &lt;b&gt;프록시(Proxy)&lt;/b&gt;나 &lt;b&gt;외관(Fa&amp;ccedil;ade)&lt;/b&gt;을 만듭니다. 처음에는 모든 요청을 그냥 낡은 시스템으로 전달합니다. 그런 다음, 그 기능 중 하나를 새로운 기술로 재구현합니다. 이제 프록시는 해당 기능에 대한 요청은 새로운 시스템으로 보내고, 나머지 요청은 여전히 낡은 시스템으로 보냅니다. 이 과정을 점진적으로 반복하면, 결국 낡은 시스템의 모든 기능이 새로운 시스템으로 대체되고, 낡은 시스템은 안전하게 은퇴시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식은 '빅 리라이트'의 위험을 크게 줄여줍니다. 각 단계마다 작은 성공을 거둘 수 있고, 비즈니스에 가치를 지속적으로 제공할 수 있으며, 만약 문제가 생기더라도 쉽게 이전 상태로 되돌아갈 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'재건축'은 마지막 수단이어야 합니다. 그것은 심각한 질병에 대한 대수술과 같습니다. 위험하고 고통스럽지만, 때로는 생존을 위해 필요합니다. 하지만 가능하면 항상 점진적인 치료와 예방(리팩토링, 좋은 설계)을 통해 대수술을 피하는 것이 현명합니다. 결국, &lt;b&gt;거대한 진흙 덩어리&lt;/b&gt;와 함께 사는 것이, 실패한 재건축 프로젝트의 잿더미 위에 서 있는 것보다 나을 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;conclusion-결론&quot; data-ke-size=&quot;size26&quot;&gt;Conclusion (결론)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 이 논문에서 소프트웨어 아키텍처의 어두운 면, 즉 '거대한 진흙 덩어리'를 탐구했습니다. 우리는 이것이 왜 그렇게 흔하게 나타나는지, 그리고 놀랍게도 왜 종종 효과적인지를 설명하는 일단의 힘과 패턴들을 제시했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;건축가들은 종종 도시를 내려다보는 높은 곳에서, 깨끗하고 잘 계획된 이상적인 도시를 꿈꿉니다. 그러나 거리로 내려오면, 그들은 혼잡하고, 지저분하며, 활기 넘치는 현실의 도시를 마주하게 됩니다. 소프트웨어 아키텍처도 마찬가지입니다. 우리는 우아하고, 일관되며, 잘 구조화된 시스템을 열망하지만, 종종 마감일, 변화하는 요구사항, 그리고 순수한 복잡성의 현실과 씨름하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'거대한 진흙 덩어리'는 이러한 현실에 대한 대응입니다. 그것은 완벽함의 부재를 의미하지만, 실패를 의미하지는 않습니다. 그것은 종종 생존, 성장, 그리고 진화의 증거입니다. 이 논문에서 제시된 패턴들&amp;mdash;일회용 코드, 점진적 성장, 계속 작동하게 하라, 분리 계층, 문제를 카펫 밑으로 쓸어넣기, 재건축&amp;mdash;은 이러한 지저분한 현실을 탐색하기 위한 전략들을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 패턴들은 '거대한 진흙 덩어리'를 만들라고 권장하는 것이 아닙니다. 오히려, 그것들은 우리가 왜 그런 시스템을 만들게 되는지 이해하고, 그 안에서 효과적으로 작업하며, 가능할 때 점진적으로 개선할 수 있는 방법을 제안합니다. 그것들은 실용주의의 가치를 강조합니다. 때로는 '그럭저럭 괜찮은(good enough)' 것이 최선의 선택일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문의 핵심 메시지는 다음과 같습니다. 아키텍처는 중요하지만, 그것이 전부는 아닙니다. 우리는 건축적 순수성을 추구하는 것과, 가치를 전달하고 시스템을 살아있게 유지해야 하는 현실적인 필요 사이에서 균형을 찾아야 합니다. 가장 뛰어난 아키텍트는 가장 아름다운 청사진을 그리는 사람이 아니라, 가장 거센 폭풍우 속에서도 배를 계속 항해하게 할 수 있는 사람일지도 모릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러니 다음에 당신이 '거대한 진흙 덩어리'를 마주하게 되거든, 절망하지 마십시오. 당신은 혼자가 아닙니다. 그것은 단지 소프트웨어 개발이라는 지저분하고, 복잡하며, 끝없이 매력적인 세계의 일부일 뿐입니다.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments-감사의-글&quot; data-ke-size=&quot;size26&quot;&gt;Acknowledgments (감사의 글)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 우리의 동료들에게서 많은 것을 배웠습니다. 특히, 존 브랜트(John Brant), 찰리 헤링(Charlie Herring), 랄프 존슨(Ralph Johnson), 돈 로버츠(Don Roberts), 그리고 빌 오피다이크(Bill Opdyke)를 포함한 일리노이 패턴 그룹(Illinois Patterns Group)의 멤버들은 수년에 걸쳐 우리의 생각에 큰 영향을 주었습니다. 켄 아우어(Ken Auer), 짐 코플리엔(Jim Coplien), 그리고 워드 커닝햄(Ward Cunningham)과의 토론도 많은 도움이 되었습니다. 브루스 블레어(Bruce Blair)는 '분리 계층'이라는 아이디어의 핵심을 우리에게 소개해 주었습니다. 크리스토퍼 알렉산더(Christopher Alexander)의 작업은 이 논문 전반에 걸쳐 깊은 영감을 주었습니다. 마지막으로, 우리는 이 논문의 초기 버전에 대해 귀중한 피드백을 제공해 준 PLoP '97 컨퍼런스의 워크숍 참가자들에게 감사를 표합니다.&lt;/p&gt;
&lt;h2 id=&quot;references-참고-문헌&quot; data-ke-size=&quot;size26&quot;&gt;References (참고 문헌)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문은 여러 중요한 저작에 영감을 받거나 인용하고 있습니다. 주요 참고 문헌은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[Alexander 1977] Christopher Alexander, A Pattern Language: Towns, Buildings, Construction, Oxford University Press, 1977&lt;br /&gt;패턴 언어의 개념을 정립한 건축 분야의 고전입니다. 이 논문의 사상적 기반이 됩니다.&lt;br /&gt;[Alexander 1979] Christopher Alexander, The Timeless Way of Building, Oxford University Press, 1979&lt;br /&gt;'점진적 성장'과 유기적 설계에 대한 철학을 담고 있습니다.&lt;br /&gt;[Brand 1994] Stewart Brand, How Buildings Learn: What Happens After They're Built, Viking Press, 1994&lt;br /&gt;'분리 계층(Shearing Layers)'의 개념을 소개한 책입니다.&lt;br /&gt;[Brooks 1995] Frederick P. Brooks, Jr., The Mythical Man-Month, Anniversary Edition, Addison-Wesley, 1995&lt;br /&gt;'맨먼스 미신'. '일회용 코드'와 '두 번째 시스템 효과'에 대한 고전적인 통찰을 제공합니다.&lt;br /&gt;[Buschmann et al. 1996] Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, and Michael Stal, Pattern-Oriented Software Architecture: A System of Patterns, John Wiley and Sons, 1996&lt;br /&gt;POSA 책으로 알려진 소프트웨어 아키텍처 패턴에 대한 중요 저작입니다.&lt;br /&gt;[Coplien 1995] James O. Coplien, &quot;A Development Process Generative Pattern Language&quot;, In Pattern Languages of Program Design, Addison-Wesley, 1995&lt;br /&gt;'매일 빌드'와 같은 개발 프로세스 패턴에 대해 다룹니다.&lt;br /&gt;[Foote 1988] Brian Foote, &quot;Designing to Facilitate Change with Object-Oriented Frameworks&quot;, Master's Thesis, University of Illinois at Urbana-Champaign, 1988&lt;br /&gt;[Gamma et al. 1995] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995&lt;br /&gt;'디자인 패턴' 또는 'GoF(Gang of Four) 패턴'으로 알려진 필독서입니다. Fa&amp;ccedil;ade, Adapter 등의 패턴을 소개합니다.&lt;br /&gt;[Hunt &amp;amp; Thomas 1999] Andrew Hunt and David Thomas, The Pragmatic Programmer: From Journeyman to Master, Addison-Wesley, 1999&lt;br /&gt;이 논문 출간 이후에 나왔지만, '깨진 창문' 이론 등 이 논문과 철학을 공유하는 실용주의 프로그래밍의 고전입니다. (원문에는 없지만 이해를 위해 추가)&lt;br /&gt;[Johnson &amp;amp; Foote 1988] Ralph E. Johnson and Brian Foote, &quot;Designing Reusable Classes&quot;, Journal of Object-Oriented Programming, June/July 1988&lt;br /&gt;[Vlissides 1998] John Vlissides, Pattern Hatching: Design Patterns Applied, Addison-Wesley, 1998&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;h1 id=&quot;읽기-쉬운-요약-버전&quot;&gt;읽기 쉬운 요약 버전&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 원문이 특별히 길지는 않지만 아무래도 논문이다보니 내용이 좀 어렵다고 느끼실 분들을 위해 간단히 정리된 버전입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;서문&quot; data-ke-size=&quot;size26&quot;&gt;서문&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문은 소프트웨어 아키텍처의 이상과 현실 사이의 괴리를 다룹니다. 개발자들은 모두 잘 설계된 시스템을 만들고 싶어 하지만, 촉박한 마감 시간, 예산의 한계, 끊임없이 변하는 요구사항 같은 현실적인 압박 때문에, 시스템은 종종 의도와 다르게 복잡하고 무질서한 '거대한 진흙 덩어리'가 되어 갑니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 논문은 이런 현상을 단순히 '나쁜 개발'로 치부하지 않습니다. 대신, 이것이 왜 그토록 흔하며 때로는 비즈니스적으로 성공하는지를 분석합니다. 그리고 이런 지저분한 현실 속에서 개발자가 어떻게 시스템의 붕괴를 막고, 점진적으로 개선하며 생존할 수 있는지에 대한 실용적인 전략들을 제시합니다. 즉, 완벽한 청사진을 좇기보다, &lt;b&gt;현실의 제약 속에서 최선의 가치를 만들어내는 실용주의적 지혜&lt;/b&gt;를 강조합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 id=&quot;1-거대한-진흙-덩어리-big-ball-of-mud&quot; data-ke-size=&quot;size26&quot;&gt;1. 거대한 진흙 덩어리 (Big Ball of Mud)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뚜렷한 아키텍처 없이 마구잡이로 성장하여 내부 구조가 뒤엉킨 시스템을 말합니다. 이는 촉박한 일정, 개발자의 잦은 교체, 부족한 경험 등 다양한 현실적 제약 때문에 발생하는 경우가 많습니다. 비록 기술적으로는 경멸의 대상이지만, 놀랍게도 시장 출시 시간을 맞추고 가치를 전달하며 오랫동안 살아남는 성공적인 시스템에서 흔히 발견되는, 사실상의 표준 아키텍처이기도 합니다.&lt;/p&gt;
&lt;h2 id=&quot;2-일회용-코드-throwaway-code&quot; data-ke-size=&quot;size26&quot;&gt;2. 일회용 코드 (Throwaway Code)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타당성 검증 등을 위해 임시로 만든 프로토타입 코드가 버려지지 않고 제품의 기반이 되는 상황입니다. 관리자나 고객이 &quot;이 정도면 거의 다 됐네, 출시하자!&quot;라고 말하는 압박 속에서, 개발자는 코드의 구조적 문제를 알면서도 어쩔 수 없이 제품화를 진행하게 됩니다. 이처럼 단기적인 이익을 위해 내린 결정이 장기적으로는 시스템 전체를 부실하게 만드는 '진흙 덩어리'의 씨앗이 됩니다.&lt;/p&gt;
&lt;h2 id=&quot;3-점진적-성장-piecemeal-growth&quot; data-ke-size=&quot;size26&quot;&gt;3. 점진적 성장 (Piecemeal Growth)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 시스템은 처음부터 완벽하게 설계될 수 없으며, 대부분 작동하는 작은 시스템에서 출발해 점진적으로 성장하고 진화합니다. 이 유기적인 성장 과정은 자연스럽고 효과적이지만, 지속적인 리팩토링과 구조 개선 노력이 없다면 필연적으로 무질서와 복잡성을 낳게 됩니다. '진흙 덩어리'는 이러한 통제되지 않은 성장의 불가피한 결과물일 수 있습니다.&lt;/p&gt;
&lt;h2 id=&quot;4-계속-작동하게-하라-keep-it-working&quot; data-ke-size=&quot;size26&quot;&gt;4. 계속 작동하게 하라 (Keep it Working)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;점진적으로 시스템을 개선할 때 가장 중요한 원칙은, 어떤 변경을 하든 시스템이 깨지지 않고 계속 작동하는 상태를 유지하는 것입니다. 특히 구조가 복잡한 '진흙 덩어리'에서는 작은 수정이 예상치 못한 부작용을 낳기 쉽습니다. 따라서 자동화된 테스트와 지속적 통합(CI)은 우리가 어둠 속에서 길을 잃지 않도록 지켜주는 안전망이자, 시스템을 자신감 있게 개선하기 위한 필수적인 생명 유지 장치입니다.&lt;/p&gt;
&lt;h2 id=&quot;5-분리-계층-shearing-layers&quot; data-ke-size=&quot;size26&quot;&gt;5. 분리 계층 (Shearing Layers)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어의 각 부분은 변화하는 속도가 다릅니다. 자주 바뀌는 UI와 안정적인 비즈니스 로직처럼, 변화율이 다른 부분들을 서로 분리하는 것은 매우 중요합니다. '진흙 덩어리'의 특징은 이런 계층들이 뒤엉켜 있다는 점이며, 이들을 분리하려는 노력은 장기적인 유지보수성과 유연성을 확보하고 시스템을 개선하는 핵심적인 건축 원칙입니다.&lt;/p&gt;
&lt;h2 id=&quot;6-문제를-카펫-밑으로-쓸어넣기-sweeping-it-under-the-rug&quot; data-ke-size=&quot;size26&quot;&gt;6. 문제를 카펫 밑으로 쓸어넣기 (Sweeping it under the Rug)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템의 어떤 부분이 너무 복잡해서 당장 해결하기 어려울 때, 그 복잡성을 깔끔한 API라는 '외관(Fa&amp;ccedil;ade)' 뒤로 숨기는 전략입니다. 이는 근본적인 해결책은 아니지만, 문제의 영향력이 시스템 전체로 퍼져나가는 것을 막는 현실적인 타협안입니다. 당장의 완벽한 해결보다, 복잡성을 한 곳에 격리하고 점진적으로 개선할 기회를 만드는 실용적인 접근법입니다.&lt;/p&gt;
&lt;h2 id=&quot;7-재건축-reconstruction&quot; data-ke-size=&quot;size26&quot;&gt;7. 재건축 (Reconstruction)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템이 더 이상 개선이 불가능할 정도로 낡고 부패했을 때 고려하는 최후의 수단입니다. 하지만 전체 시스템을 한 번에 다시 만드는 '빅 리라이트'는 기존 시스템에 녹아있는 수많은 암묵적 지식을 놓쳐 실패할 위험이 매우 큽니다. 따라서 재건축을 해야만 한다면, 시스템 전체를 한 번에 교체하기보다 특정 기능부터 서서히 새로운 시스템으로 대체해 나가는 점진적인 '스트랭글러(Strangler) 패턴'이 훨씬 더 안전하고 현실적인 선택입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>기술 이야기</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/58</guid>
      <comments>https://koeunyeon.tistory.com/entry/BIG-BALL-OF-MUD-%ED%95%9C%EA%B5%AD%EC%96%B4%ED%8C%90#entry58comment</comments>
      <pubDate>Tue, 14 Apr 2026 11:25:06 +0900</pubDate>
    </item>
    <item>
      <title>암복호화와 쿼리 속도</title>
      <link>https://koeunyeon.tistory.com/entry/%EC%95%94%EB%B3%B5%ED%98%B8%ED%99%94%EC%99%80-%EC%BF%BC%EB%A6%AC-%EC%86%8D%EB%8F%84</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1초만에 실행되던 쿼리가 12초가 됐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 화면, 같은 쿼리인데 주민번호 컬럼에 암호화 함수 하나 씌웠을 뿐이었습니다. 그것만으로 조회 속도가 10배 넘게 느려졌습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;오픈 2주 전&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아시는 분은 아시겠지만, 감리는 최종 감리 외에도 중간 감리가 있는 경우가 있습니다. 그러니까 개발중에 와서 잘 되고 있나 확인하는 거죠.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;아니 개발중인데 당연히 엉망이지 이양반아...&lt;/del&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;당연히 감리분도 그냥 본인 할 일 하는 겁니다. 대부분 공공기관 같은 곳에는 법적으로 강제로 해야 하는 경우가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간감리 지적사항이 떨어졌습니다. 개인정보 암호화 미적용. 주민번호와 계좌번호가 평문으로 저장되어 있다는 내용이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고 있었습니다. 일정이 빠듯해서 나중에 하려고 미뤄둔 것이었는데, 감리가 먼저 잡았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암호화 자체는 어렵지 않았습니다. AES-256 표준 알고리즘을 쓰기로 하고, DB 함수로 &lt;code&gt;ENCRYPT_SSN()&lt;/code&gt;과 &lt;code&gt;DECRYPT_SSN()&lt;/code&gt;을 만들었습니다. 저장할 때 암호화하고 조회할 때 복호화하는 구조였습니다. 쿼리에 함수만 씌우면 됐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이틀 만에 작업을 끝내고 테스트까지 마쳤습니다. 별문제 없어 보였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 오픈했습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;월요일 아침&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전화가 왔습니다. 사용자 검색 화면에서 조회가 안 된다고 하더군요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인해보니 주민번호 뒷자리로 검색하는 기능이었습니다. 예전에는 1초면 결과가 나왔는데, 지금은 12초가 걸렸습니다. 타임아웃 직전이었죠. &lt;s&gt;느려&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;다른 화면들도 마찬가지였습니다. 암호화된 컬럼을 조건으로 쓰는 화면은 전부 느려져 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 계획을 확인했습니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT * FROM user 
WHERE DECRYPT_SSN(ssn) LIKE '%-1234567';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스를 타지 않고 풀 스캔을 하고 있었습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;원인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각해보면 당연한 결과였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;WHERE ssn LIKE&lt;/code&gt;였으면 ssn 컬럼의 인덱스를 탔을 겁니다. 하지만 &lt;code&gt;WHERE DECRYPT_SSN(ssn) LIKE&lt;/code&gt;는 다릅니다. 함수를 먼저 실행해야 하기 때문에, DB는 테이블의 모든 레코드를 하나씩 복호화한 다음 비교하는 수밖에 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블에 100만 건이 있었습니다. 조회 한 번에 100만 번 복호화가 돌아간 셈입니다. 12초가 걸린 게 오히려 빠른 편이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암호화를 적용하는 데는 이틀. 그 대가는 속도가 12배 느려짐.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결책 찾기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 기반 인덱스를 시도했습니다. 복호화된 결과값에 인덱스를 거는 방법이었습니다.&lt;br /&gt;안되더군요. DB 버전이 낮아서 해당 기능을 지원하지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBA에게 물었습니다. DB 버전을 올릴 수 있느냐고요.&lt;br /&gt;안 된다고 했습니다. 고객사 표준 버전이 정해져 있어서 변경하려면 별도 결재가 필요하고, 그 과정만 몇 달이 걸린다고 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 달까지 기다릴 여유는 없었습니다. 오픈이 다음 주였는걸요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타협&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 해시 컬럼을 추가하는 방식으로 타협했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주민번호를 암호화해서 &lt;code&gt;ssn_enc&lt;/code&gt;에 저장하고, 동시에 해시값을 계산해서 &lt;code&gt;ssn_hash&lt;/code&gt;에 따로 저장합니다. 검색할 때는 암호화된 값을 복호화하는 대신 해시로 비교합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT * FROM user 
WHERE ssn_hash = HASH('123456-1234567');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 컬럼에 인덱스를 걸었습니다. 속도가 돌아왔습니다. 다시 1초.&lt;br /&gt;오픈은 예정대로 진행됐습니다.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;꼼수의 왕...&lt;/del&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;찝찝함&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 해결됐는데 찝찝했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시는 단방향입니다. 복호화가 안 되기 때문에 원본을 직접 볼 수는 없습니다. 하지만 같은 값인지 비교는 할 수 있습니다. 그리고 그게 문제였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시도 결국 DB에 저장됩니다. DB가 유출되면 해시값도 같이 유출됩니다. 주민번호는 패턴이 정해져 있기 때문에 레인보우 테이블로 역추적이 가능합니다. 암호화만 했을 때보다 보안이 약해진 셈입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBA가 말했습니다. 그래도 평문보다는 낫지 않느냐고요.&lt;br /&gt;맞는 말입니다. 하지만 최선은 아니었습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설계의 문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;돌이켜보면 애초에 설계 단계에서 고려했어야 할 문제였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;암호화를 나중에 적용하려고 미뤘던 게 화근이었습니다. 일정이 빠듯하니까 일단 평문으로 개발하고, 오픈 전에 암호화하면 되겠지 싶었던거죠. 그래서 쿼리를 평문 기준으로 짰고, 인덱스도 평문 기준으로 걸었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 암호화를 적용하니까 전부 안 맞았습니다. 인덱스 전략을 다시 짜야 했고, 검색 방식을 바꿔야 했고, 결국 해시라는 우회로까지 만들어야 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음부터 암호화를 전제로 설계했으면 달랐을 겁니다. 어떤 컬럼을 암호화할지, 암호화된 컬럼으로 검색이 필요한지, 필요하다면 어떤 방식으로 할지. 이런 것들을 미리 정하고 시작했으면 해시 같은 땜질은 안 해도 되겠죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 안 하면 나중에 비용이 커진다는 걸 모르지 않았습니다. 알면서도 미뤘습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;다른 프로젝트에서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 다른 프로젝트에서는 다른 방식을 썼습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 함수 대신 애플리케이션 레벨에서 암호화를 처리했습니다. Java에서 암호화해서 저장하고, 조회할 때 Java에서 복호화합니다. DB는 그냥 암호화된 값을 저장할 뿐, 함수를 실행하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식은 인덱스 문제가 없습니다. 대신 주민번호로 직접 검색하는 기능 자체를 없앴습니다. UI를 바꿔서 이름이나 ID로 먼저 검색하고, 상세 화면에서 주민번호를 보여주는 방식으로 흐름을 바꿨습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점도 있었습니다. 기존 평문 데이터를 마이그레이션하는 게 힘들었어요. DB에 암복호화 기능이 없으니까 쿼리로 한방에 처리할 수가 없었거든요.&lt;br /&gt;수백만 건을 배치로 돌렸는데 이틀이 걸렸습니다. 서비스 중단 없이 해야 해서 동시성 제어가 복잡했고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느 쪽이든 쉬운 방법은 없었습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;보안과 성능&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 트레이드오프입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안을 강화하면 성능이 떨어집니다. 성능을 유지하려면 보안에서 타협해야 합니다. 둘 다 완벽하게 잡을 수는 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상적으로는 프로젝트 초반에 이 트레이드오프를 논의해야 합니다. 어떤 컬럼을 암호화할지, 암호화된 컬럼에 대한 검색 요구사항이 있는지, 있다면 어떤 방식이 가능한지. 인프라팀, DBA, 개발팀이 같이 앉아서 결정해야 하는 문제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현실에서는 그런 논의가 생략되는 경우가 많습니다.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;단 한번도 제대로 논의하는 걸 본 적이 없죠.&lt;/del&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일정에 쫓기고, 나중에 하면 된다고 생각하고, 감리에서 지적받고, 급하게 적용하고, 문제가 터지고, 땜질합니다. 그렇게 해시 컬럼 같은 것들이 생겨납니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;감리 보고서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감리 보고서에는 한 줄이 적혔습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인정보 암호화 적용 완료.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해시 컬럼을 추가한 건 안 적혔습니다. 성능 문제가 있었다는 것도, 완벽한 해결책이 아니라는 것도 안 적혔습니다.&lt;br /&gt;그냥 &quot;완료&quot;였습니다.&lt;/p&gt;</description>
      <category>프리랜서 개발자의 삶</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/72</guid>
      <comments>https://koeunyeon.tistory.com/entry/%EC%95%94%EB%B3%B5%ED%98%B8%ED%99%94%EC%99%80-%EC%BF%BC%EB%A6%AC-%EC%86%8D%EB%8F%84#entry72comment</comments>
      <pubDate>Mon, 13 Apr 2026 16:55:44 +0900</pubDate>
    </item>
    <item>
      <title>개발자가 좋아하는 기획서 쓰는 법</title>
      <link>https://koeunyeon.tistory.com/entry/%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EC%A2%8B%EC%95%84%ED%95%98%EB%8A%94-%EA%B8%B0%ED%9A%8D%EC%84%9C-%EC%93%B0%EB%8A%94-%EB%B2%95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 &lt;span&gt;2022년 5월 20일&lt;/span&gt; 제 벨로그 &lt;a href=&quot;https://velog.io/@koeunyeon/%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EC%A2%8B%EC%95%84%ED%95%98%EB%8A%94-%EA%B8%B0%ED%9A%8D%EC%84%9C-%EC%93%B0%EB%8A%94-%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@koeunyeon/%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EC%A2%8B%EC%95%84%ED%95%98%EB%8A%94-%EA%B8%B0%ED%9A%8D%EC%84%9C-%EC%93%B0%EB%8A%94-%EB%B2%95&lt;/a&gt;&amp;nbsp;에 썼던 글을 티스토리로 옮긴 것입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h1 id=&quot;1-서설&quot;&gt;1. 서설&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 생각나는대로 계속 업데이트합니다. 현재 최종 버전은 2023.06.08. 입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 제가 좋아하는 타입의 기획서를 나열한 것입니다. 개인 취향일 수도 있으므로 가볍게 읽으셔도 됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발은 뭐라고 하는지 하나도 모르겠고 디자인은 재능이 없는 것 같으니 그나마 (조별발표때 써 봤던) 파워포인트로 문서나 만드는 기획자를 해 볼까? 라고 생각하시는 분들이 만약 있다면, 이 글을 읽고 나면 &quot;차라리 개발이나 디자인을 배워야겠어&quot; 라고 생각하시게 될 겁니다.&lt;br /&gt;그만큼 기획 업무는 전문적이고 골치아프며 어렵습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 파워포인트의 파워 목업을 다루는 법.. 같은 도구를 다루는 방법에 대해서는 전혀 다루지 않습니다. &lt;s&gt;저도 사용할 줄 몰라요&lt;/s&gt;&lt;/p&gt;
&lt;h1 id=&quot;2-개념론&quot;&gt;2. 개념론&lt;/h1&gt;
&lt;h2 id=&quot;21-미사어구를-사용하지-마세요&quot; data-ke-size=&quot;size26&quot;&gt;2.1. 미사어구를 사용하지 마세요.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;엘레강스하고 가독성 좋게&quot; 라는 이야기는 디자이너에게 해 주세요. (&lt;s&gt;디자이너가 이 문구를 싫어합니다.&lt;/s&gt;)&lt;br /&gt;대부분의 개발자는 이런 문구를 보면 &quot;뭘 어쩌라는 거지&quot; 라고 생각할 겁니다.&lt;br /&gt;대신 #fff로 색을 지정해 주세요. 폰트는 나눔고딕입니다. 라고 하면 바로 오케이입니다.&lt;/p&gt;
&lt;h2 id=&quot;22-디자인을-보고-짐작하게-하지-마세요&quot; data-ke-size=&quot;size26&quot;&gt;2.2. 디자인을 보고 짐작하게 하지 마세요.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명확하게 써 주세요.&lt;br /&gt;기획하시는 분은 (본인이 생각하신 것을 문서로 옮긴 것이므로) 당연하다고 생각하는 부분들도 가능하면 자세하게 적어주세요.&lt;br /&gt;우리 모두는 경험도 다르고, 생각하는 방식도 다릅니다. 이건 공감의 문제도 아니고, 상식의 문제도 아닙니다. 기획서는 &quot;의사소통을 위한 문서&quot; 이므로 서로간 의도의 곡해가 없도록 작성하는 것이 몹시 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 모호한 것을 점쟁이처럼 알아맞춘 다음 생각하지 못한 부분까지 커버해줄 수 있는 존재가 아닙니다. &lt;s&gt;그걸 할 줄 알면 여기서 타자나 치고 있을 게 아니라 점집을 차려서...&lt;/s&gt; 정의된 사양을 보고 그걸 구현해내는 사람이죠.&lt;/p&gt;
&lt;h2 id=&quot;23-기획서는-꿈과-희망을-담는-pr-문서가-아니라-설계서입니다&quot; data-ke-size=&quot;size26&quot;&gt;2.3. 기획서는 꿈과 희망을 담는 pr 문서가 아니라 설계서입니다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 극소수의 기획자분들에게 보이는 현상입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기획 문서를 가지고 왔는데 세상의 모든 좋은 기능은 다 붙어있네요. 마치 [페이스북 + 인스타그램 + 카카오톡 + 밴드 + 라인 + 싸이월드(음?)] 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 이런 문서를 보는 순간 &quot;엄청 복잡하네. 이걸 기술적으로 구현 가능하며 일정 내에 소화가 가능할까?&quot; 라는 생각도 할 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 내용으로 &quot;xx와 똑같이요.&quot; 라고 적혀있는 문서도 있습니다. 데드 카피 제품을 만듬으로써 의욕이 떨어지는 것은 두번째 문제고.. 도대체 &quot;xx와 어떤 부분을 똑같이?&quot; 라는 생각부터 들겁니다.&lt;/p&gt;
&lt;h2 id=&quot;24-화면-정의서와-기능-정의서는-다른거에요&quot; data-ke-size=&quot;size26&quot;&gt;2.4. 화면 정의서와 기능 정의서는 다른거에요.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에이전시 출신의 기획자 분들에게 가끔 보이는 현상인데.. 웹 에이전시는 디자인 위주의 사이트를 만드는 곳이기 때문에 디자인에 대해서는 엄청 자세하게 적혀있지만, 기능에 대해서는 &quot;게시판 목록&quot; 이라고 달랑 5글자만 적혀있는 경우를 봤어요.&lt;br /&gt;&quot;게시판 목록&quot;은 기능이 아니에요. 기능은 무엇이 보여지고 어떻게 동작할 것인가에 대한 문제이지 어떻게 보여지느냐의 문제가 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 &quot;게시판 목록&quot; 이라는 표현 대신 아래처럼 작성해 주시는 것을 권장합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게시판 목록은 제목, 내용, 작성일, 작성자 닉네임으로 구성됩니다.&lt;/li&gt;
&lt;li&gt;제목을 클릭하면 게시판 상세 페이지로 이동합니다. (&lt;b&gt;ppt p32 참조&lt;/b&gt;)&lt;/li&gt;
&lt;li&gt;내용은 100글자가 넘어갈 경우 100글자로 한정합니다.&lt;/li&gt;
&lt;li&gt;작성일은 2023-06-08 형식으로 표현합니다. 다만 당일일 경우 &quot;오늘&quot; 이라고 표시하고, 오늘을 기준으로 7일 이내에는 n일 전 (어제였을 경우 1일전) 으로 표기합니다. 만약 7일-14일 이내라면 &quot;일주일 전&quot; 으로 표기해 주세요. 그보다 오래될 경우 2023-06-08 형식으로 표기합니다.&lt;/li&gt;
&lt;li&gt;닉네임은 전체를 표기합니다. 닉네임 클릭시 닉네임에 해당하는 작성자의 프로필 페이지로 이동합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;25-개발을-할-필요는-없지만-배워두는-게-정신건강에-좋습니다&quot; data-ke-size=&quot;size26&quot;&gt;2.5. 개발을 할 필요는 없지만, 배워두는 게 정신건강에 좋습니다.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에 대해서는 많은 기획자 분들이 통감하시고, 따로 시간과 돈을 들여서 수업을 듣는 것을 많이 봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 .. 백엔드는 어려워서 그런지 몰라도 (보이는 것은 코드 뿐..) 프론트엔드를 많이 배우시는데요.&lt;br /&gt;우리가 생각하는 &quot;기능&quot;은 대부분 백엔드에서 구현합니다. 프론트엔드는 백엔드의 데이터를 받아서 보여지는 부분을 담당하는거죠.&lt;br /&gt;그래서 어려워도 데이터베이스 설계나, 최소한의 서버 사이드 어플리케이션들이 어떻게 돌아가는지에 대해서는 기초 서적이라도 몇 권 읽어 두시는 것이 나중에 &quot;잘하는 기획자&quot;라는 호칭으로 돌아옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변화를 싫어하시는 기획자 분들 중에서는 개발을 배우면 본인들의 창의성이 저하된다고 말씀하시는 분들도 있으세요.&lt;br /&gt;개발을 배우라는 것은 &quot;본인의 한계를 제한&quot;하라는 뜻이 아니라, 어떤 것이 가능한지 가늠하고, 커뮤니케이션을 원활하게 하라는 뜻입니다.&lt;br /&gt;개발을 배우면 창의성이 저하된다고 생각한다면, 그냥 기획자를 그만두는 것이 낫다고 생각합니다. 본인이 논리적인 사고가 안되므로 &quot;나는 꿈을 꿀테니 니가 현실로 만들어라&quot;라는 마인드를 증명하는 것 같은 것입니다.&lt;/p&gt;
&lt;h2 id=&quot;26-용어를-명쾌하게-정의해-주세요&quot; data-ke-size=&quot;size26&quot;&gt;2.6. 용어를 명쾌하게 정의해 주세요.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자 용어로 개념을 구분해서 서로 동작이 달라야 하는 것들을 &quot;엔티티(entity)&quot;라고 합니다. 예를 들어서 &quot;게시판&quot;을 구현한다고 하면, &quot;게시글&quot;, &quot;첨부파일&quot;, &quot;작성자&quot; 등이 엔티티가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 구분하는 이유는, 실제로 각 엔티티별로 할 수 있는 일이 다르고, 개발을 할 때는 엔티티별로 쪼개서 속성과 할 수 있는 일을 구현하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 이런 것은 지양하셔야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 개념에 대해서 서로 다른 용어를 쓰는 일 (기획서 37페이지에서는 &quot;작성자&quot;, 45페이지에서는 &quot;글쓴이&quot; 라고 쓴다거나)&lt;/li&gt;
&lt;li&gt;다른 개념에 대해서 서로 같은 용어를 쓰는 일 (로그인한 &quot;회원&quot;은 게시판에 글을 쓸 수 있음. 관리자 &quot;회원&quot;은 다른 사람의 게시글을 삭제할 수 있음).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &quot;사람&quot;은 &quot;문맥&quot;에 따라서 유추라는 것이 가능하지만, 컴퓨터는 그런 것이 불가능하기 때문입니다. 개발자들은 &quot;일을 할 때는 컴퓨터에 가까운 모드로 전환&quot; 되므로, 문맥에 따라 같은 용어가 다른 동작을 한다거나, 다른 용어가 같은 동작을 한다거나.. 하는 식으로 코드가 작성되면 나중에는 본인도 못알아보는 이상한 코드가 되어버리기 때문에 본능적으로 싫어합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기획자의 롤을 벗어나서 PO(Product Owner) 레벨이 되면 용어의 혼선을 막기 위해서 &quot;용어사전&quot; 이라는 것을 만드는 것도 좋은 방법입니다.&lt;/p&gt;
&lt;h2 id=&quot;27-용어엔티티를-개발자가-이해하는-법&quot; data-ke-size=&quot;size26&quot;&gt;2.7. 용어(엔티티)를 개발자가 이해하는 법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 기획서를 읽고, 엔티티를 추출해내고, 이를 코드로 옮깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티는 속성, 이벤트, 상태 전이로 구분됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;속성 : 엔티티를 구성하는 값들. ex. )게시글의 제목, 본문, 댓글 .. 등&lt;/li&gt;
&lt;li&gt;이벤트 : 동작. ex.) 게시글 작성 후 &quot;저장하기&quot; 버튼을 눌렀을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트는 a.)발동 조건과 그에 따른 b.)이펙트가 있습니다. 예를 들면 a.)게시글 작성 후 &quot;저장하기&quot; 버튼을 누르면 b.) 데이터 저장 =&amp;gt; 방금 쓴 글 상세로 이동 .. 이런 식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태 전이는 이벤트가 일어났을 경우 상태가 변화하는가..에 대한 것입니다. 예를 들면 &quot;게시글을 수정해서 비공개로 변경되었을 경우 게시글이 다른 사람에게 보여지지 않는다.&quot; 같은 걸 말합니다.&lt;br /&gt;상태 전이가 중요한 이유는 엔티티의 상태에 따라서 엔티티가 하는 동작이 달라질 수 있기 때문입니다. 예컨데 &quot;운영 정책 위반으로 블라인드 처리된 글&quot; 이 수정이 가능하다면 &quot;블라인드 처리는 어떻게 되어야 하는가..&quot; 라는 문제가 생기기 때문에 개별 엔티티의 상태에 따라 동작이 어떻게 달라지고, 다른 엔티티에 어떤 영향을 미치는가를 늘 고민해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 기획자 분이 엔티티 정의를 기획서에 넣어주시면, 개발자는 곧바로 보고 실제 코드로 옮길 수 있으므로 서로간의 커뮤니케이션 미스가 적어집니다.&lt;br /&gt;&lt;s&gt;하지만 한번도 이런 걸 정의해주는 기획서는 받아본 적이 없습니다...&lt;/s&gt;&lt;/p&gt;
&lt;h2 id=&quot;28-기능-정의를-먼저-하세요&quot; data-ke-size=&quot;size26&quot;&gt;2.8. 기능 정의를 먼저 하세요.&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 개발은 어떤 기능이 있는지 정의가 먼저입니다. 코드가 먼저도 아니고 디자인이 먼저도 아니에요. 이를 기능 명세서라고 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능 명세서는 가능하면 최대한 자세히 작성하세요. 당연하다는 함정에 빠지지 마세요. 같은 디자인이라도 사용자 경험은 전혀 다를 수 있어요.&lt;br /&gt;개인적으로 추천하는 방법은 &quot;앞에 7살짜리가 있다고 생각하고 그 아이가 이해할 수 있는 수준&quot; 으로 작성하는 겁니다.&lt;br /&gt;이 과정이 귀찮고 번거롭다면 본인이 할 일을 남에게 미루는 거에요.&lt;/p&gt;
&lt;h2 id=&quot;29-개발자에게-필요한-기획의-3대-요소&quot; data-ke-size=&quot;size26&quot;&gt;2.9. 개발자에게 필요한 기획의 3대 요소&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무선 청소기를 예로 들어보겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디자인을 중시 여기는 기획자는 &quot;청소기가 어떻게 생겼는지&quot;에 대해서 아주 자세히 이야기합니다. 색은 흰색이어야 하고, 그립감이 좋아야 하며, 가벼워야 한다고 적어놓습니다.&lt;/li&gt;
&lt;li&gt;기능을 중요하게 여기는 기획자는 &quot;청소기가 어떻게 동작해야 하는지&quot;에 대해서 이야기합니다. 전원 버튼을 누르면 동작해야 하고, 파워 모드를 누르면 더 강하게 흡입이 가능해야 하죠.&lt;/li&gt;
&lt;li&gt;스펙을 먼저 보는 기획자는 &quot;청소기가 어떤 스펙을 가지고 있는지&quot;에 집중합니다. 무선 청소기는 모터, 배터리, 충전기, 그리고 껍데기로 이루어지며, 모터는 16v, 배터리는 36A .. 이런 식입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋 다 중요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;디자인&quot;은 디자이너 분의 영역이므로 이 글에서는 패스합니다만, 외관이 구매를 결정하는 요인 중 하나이므로 대단히 중요합니다.&lt;/li&gt;
&lt;li&gt;&quot;기능&quot;은 엔티티 부분에서 언급한 &quot;이벤트&quot;에 해당합니다.&lt;/li&gt;
&lt;li&gt;&quot;스펙&quot;은 엔티티 부분에서 언급한 &quot;속성&quot; 에 해당합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자는 &quot;기능&quot;과 &quot;스펙&quot; 이 있어야 동작하는 제품을 만들 수 있기 때문에 세개 다 필요합니다.&lt;/p&gt;
&lt;h1 id=&quot;3-실전-도전&quot;&gt;3. 실전 도전&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터는 실전 기획서에서 꼭 필요한 항목을 예시로 살펴보겠습니다.&lt;/p&gt;
&lt;h2 id=&quot;31-목록&quot; data-ke-size=&quot;size26&quot;&gt;3.1. 목록&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목록을 정의할 때는 최소한 아래의 항목들이 필요합니다.&lt;/p&gt;
&lt;h3 id=&quot;311-항목의-구분&quot; data-ke-size=&quot;size23&quot;&gt;3.1.1. 항목의 구분&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글 목록 : 개별 글을 모아놓은 목록&lt;/li&gt;
&lt;li&gt;개별 글 : 글 목록의 일부로써 게시글을 요약한 글 하나.&lt;/li&gt;
&lt;li&gt;글쓰기 버튼 : 글쓰기 화면으로 전환할 수 있는 버튼&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;312-글-목록&quot; data-ke-size=&quot;size23&quot;&gt;3.1.2. 글 목록&lt;/h3&gt;
&lt;h4 id=&quot;3121-속성&quot; data-ke-size=&quot;size20&quot;&gt;3.1.2.1. 속성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개별 글&lt;/li&gt;
&lt;li&gt;정렬 : 최신순. &lt;s&gt;오래된 순? 조회수가 많은 순?&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;조건 : 삭제된 글은 보여지지 않는다. 탈퇴한 회원의 글은 보여진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3122-이벤트&quot; data-ke-size=&quot;size20&quot;&gt;3.1.2.2. 이벤트&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈 페이지 처리 : 내용이 하나도 없을 경우 페이지가 없다고 보여진다. or 뒤로 보낸다.&lt;/li&gt;
&lt;li&gt;페이지 네비게이션 처리. : 더보기로 할 것인가 페이지가 변할 것인가. 만약 &amp;gt;&amp;gt; 버튼을 누르면 한번에 몇 페이지를 뛰어넘는가. (1페이지에서 눌렀다면 6페이지로 이동, 2페이지에서 눌렀다면 7페이지로.)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;313-개별-글&quot; data-ke-size=&quot;size23&quot;&gt;3.1.3. 개별 글&lt;/h3&gt;
&lt;h4 id=&quot;3131-속성&quot; data-ke-size=&quot;size20&quot;&gt;3.1.3.1. 속성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글 번호 : 숫자&lt;/li&gt;
&lt;li&gt;글 제목 : 만약 100글자가 넘어가면 말줄임 표시(...) 로 뒷 부분은 생략&lt;/li&gt;
&lt;li&gt;쓴 날짜 : 형식. ex. 2020.05.20. 23:59&lt;/li&gt;
&lt;li&gt;페이지당 글 갯수 : 10개, 15개.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3132-이벤트&quot; data-ke-size=&quot;size20&quot;&gt;3.1.3.2. 이벤트&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글 제목 클릭시 해당 글의 상세 페이지로 이동한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;314-글쓰기-버튼&quot; data-ke-size=&quot;size23&quot;&gt;3.1.4. 글쓰기 버튼&lt;/h3&gt;
&lt;h4 id=&quot;3141-속성&quot; data-ke-size=&quot;size20&quot;&gt;3.1.4.1. 속성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3142-이벤트&quot; data-ke-size=&quot;size20&quot;&gt;3.1.4.2. 이벤트&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글쓰기 버튼 클릭&lt;/li&gt;
&lt;li&gt;조건
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그인이 되어 있어야 함. 아니라면 로그인 페이지로 이동.&lt;/li&gt;
&lt;li&gt;회원 등급은 2등급 이상이어야 함. 아니라면 alert 보인 후 목록으로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;동작&lt;br /&gt;- 글쓰기 페이지로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>기술 이야기</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/57</guid>
      <comments>https://koeunyeon.tistory.com/entry/%EA%B0%9C%EB%B0%9C%EC%9E%90%EA%B0%80-%EC%A2%8B%EC%95%84%ED%95%98%EB%8A%94-%EA%B8%B0%ED%9A%8D%EC%84%9C-%EC%93%B0%EB%8A%94-%EB%B2%95#entry57comment</comments>
      <pubDate>Sat, 11 Apr 2026 11:22:42 +0900</pubDate>
    </item>
    <item>
      <title>어설픈 애자일</title>
      <link>https://koeunyeon.tistory.com/entry/%EC%96%B4%EC%84%A4%ED%94%88-%EC%95%A0%EC%9E%90%EC%9D%BC</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 &lt;span&gt;2022년 5월 20일&lt;/span&gt; 제 벨로그 &lt;a href=&quot;https://velog.io/@koeunyeon/%EC%96%B4%EC%84%A4%ED%94%88-%EC%95%A0%EC%9E%90%EC%9D%BC&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@koeunyeon/%EC%96%B4%EC%84%A4%ED%94%88-%EC%95%A0%EC%9E%90%EC%9D%BC&lt;/a&gt;&amp;nbsp;에 썼던 글을 티스토리로 옮긴 것입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h1 id=&quot;폭포수와-애자일&quot;&gt;폭포수와 애자일&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;모든것을 미리 정해놓고 한번에 개발하자!&quot; 는 폭포수(워터폴) 개발론은 한가지 문제가 있습니다. 너무 큰 걸 만들다보니 &lt;b&gt;고객&lt;/b&gt;들이 만들어진 시스템의 전체 모습을 그리기가 어려워져 버린 것입니다.&lt;br /&gt;그래서 &quot;폭포수를 개울물만큼 쪼개놓고 계속 반복하면서 피드백을 받을 수 있게 하자&quot;라는 애자일이 등장했습니다. 신세계였어요.&lt;/p&gt;
&lt;h1 id=&quot;전체-시스템-생각하기&quot;&gt;전체 시스템 생각하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애자일이 대두되면서, 경험이 많은 개발자들이 미처 예상하지 못한 사태가 발생했습니다. 바로 &lt;b&gt;&quot;실무 개발자들이 전체 시스템을 머리속에 그리는 일&quot;을 잘 못하게 되어버린&lt;/b&gt; 슬픈 현실에 맞닥드리는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애자일이라는 개념 자체를 만든 사람들은 실력도 뛰어나고, 워터폴로 전체 아키텍쳐를 그리는 데 익숙하며, 이미 서비스 완성 경험이 많기 때문에 애자일이라고 해도 다른 부분을 생각하면서 만들어나갈 수 있습니다.&lt;br /&gt;애자일을 받아들여서 도입하신 분들도 마찬가지에요. 이분들은 보통 C레벨, 아키텍트, AA 등으로 불리며 직접 코딩을 하는 것보다는 전체적인 그림을 그리시는 분들이니 수준이 높을 겁니다.&lt;br /&gt;그래서 경험이 많으시고 수준이 높은 분들이 보기에는 당연한 것들이 경험이 적은 실무 개발자들에게는 전혀 모르는 사실로 다가오는 거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 실무진과 설계자간의 괴리로 인해 개별 이터레이션을 담당하는 개발자들은 전체 모습을 그리지 못하게 됩니다. 당장 나에게 떨어진 미션은 눈 앞의 작은 기능을 완성하는 것이 되어 버리기 때문입니다. 머리로는 이해할 수 있을 지라도 직접 해보지 않은 경험은 와닿는 정도가 다른 법이니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폭포수 개발론은 이런 문제가 잘 일어나지 않습니다. 처음에만 전체 그림을 숙지를 해 두면 프로젝트 종료시까지 코드만 열심히 작성하면 됩니다. 어차피 초반에 꼭 필요한 설계는 다 되어 있기 때문에 소소한 것들은 그 때 그 때 찾아보거나 물어보면 되지요.&lt;br /&gt;하지만 &lt;b&gt;어설픈 애자일&lt;/b&gt;에서는 그럴 수 없습니다. 실무진들이 다른 &lt;b&gt;전체 시스템과의 연계를 생각하지 못하&lt;/b&gt;기 때문에 설계는 점점 더 엉망이 되어갑니다. 코드는 파편화되고, 시스템은 중복이 넘쳐나며, 서로 논리적으로 구멍이 생기게 되는 슬픈 현실에 빠져 들죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 바로 잡아줄 수 있는 설계자 분들이 계시다면 행운이겠지만, 모두가 행운을 가지고 살아가는 것은 아니니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 큰 문제는 &quot;주니어가 시간이 지나고 언젠가 시니어가 될 때, 그리고 시니어를 지나 설계자 레벨로 올라섰을 때 &quot;전체 시스템 설계를 (해 본 적이 없으니까) 못하게 된다는&quot; 것입니다.&lt;br /&gt;주니어 개발자의 실력이 늘어야 설계자분들이 여유있게 &lt;s&gt;업무중에 유튜브 시청이라도 하면서..&lt;/s&gt; 본연의 업무에 집중할 수 있는데 말이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 이유 때문에 &quot;요새 애들은 코딩은 잘하는데 설계는 못해&quot;라는 이야기가 빈번하게 들려오는 것 같기도 합니다. &lt;s&gt;아니 해본 적이 없는데 어떻게 잘해..&lt;/s&gt;&lt;/p&gt;
&lt;h1 id=&quot;최종-결정자도-바뀌어야-한다&quot;&gt;최종 결정자도 바뀌어야 한다.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덧붙여서 좋은 설계자가 있다고 해도 최종 결정을 하는 사람이 &lt;b&gt;어설픈 애자일 신봉자&lt;/b&gt;라면 더 큰 문제가 생깁니다.&lt;br /&gt;무엇을 만들 지 결정하는 사람도 애자일이라는 이름 하에 &quot;나중에 생각하지 뭐&quot; 가 당연해 집니다. 청사진 없이 무언가를 만든다는 건, 사실은 자기도 뭐가 필요한 지 모르겠다는 말인 거에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자로 살아가면서 가장 무서운 말 중 하나는 &quot;나중에 생각하지 뭐. 그 때 끼워넣자&quot; 에요. 외부의 시선으로 바라보기에는 단순하게 레고블럭처럼 조립할 수 있다고 생각하실 수 있지만, 역시 인생은 만만하지 않으니까요.&lt;br /&gt;특히 개발할 때 전체 시스템과의 연계를 생각하지 않고 코드를 작성하면, 모든 코드를 다 들어내고 다시 개발해야 하는 &lt;b&gt;강제 리팩토링&lt;/b&gt;이 시작될 가능성도 있어요. 우리는 이런 것을 이렇게 부릅니다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1118&quot; data-origin-height=&quot;1086&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvSln0/dJMcaaqRZSQ/wkGetbwIqXRWKzuwIUnci0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvSln0/dJMcaaqRZSQ/wkGetbwIqXRWKzuwIUnci0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvSln0/dJMcaaqRZSQ/wkGetbwIqXRWKzuwIUnci0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvSln0%2FdJMcaaqRZSQ%2FwkGetbwIqXRWKzuwIUnci0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1118&quot; height=&quot;1086&quot; data-origin-width=&quot;1118&quot; data-origin-height=&quot;1086&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;a href=&quot;https://velog.io/@jayce_k&quot;&gt;출처 - jayce_k(강진석)님 프로필&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;전체-스프린트-그리고-그-사이의-모듈&quot;&gt;전체, 스프린트, 그리고 그 사이의 &quot;모듈&quot;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 현재 속한 조직에서 일하는 방법이 워터폴 방법론이 너무 크고, 애자일의 스프린트가 너무 작다면, 그 중간 단위인 &quot;모듈&quot; 레벨을 두어서 최소한 &quot;모듈&quot; 레벨에서는 서로 연계가 되는 시스템을 설계하고 개발을 시작했으면 좋겠습니다.&lt;br /&gt;즉 스프린트 &amp;sub; 전체 구조가 비합리적이라면 스프린트 &amp;sub; 모듈 &amp;sub; 전체 구조는 어떨까 싶은 거죠.&lt;br /&gt;스프린트 수준에서는 &quot;이터레이션의 주기&quot;를 결정하고, 모듈 레벨에서는 &quot;소규모 시스템 완성&quot;을, 그리고 전체 레벨은 사용자 서비스 관점으로 접근하는 것은 어떨까 한번 생각해 보았어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 시스템이 크다면 스프린트 &amp;sub; 모듈 &amp;sub; 전체 가 아니라 스프린트 &amp;sub; 모듈 &amp;sub; 모듈 &amp;sub; 전체 혹은 스프린트 &amp;sub; 모듈 &amp;sub; 모듈 &amp;sub; 모듈 &amp;sub; 전체 등의 구조도 가능하겠지요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;모듈&quot;은 MSA서 말하는 &quot;바운디드 컨텍스트&quot;와 비슷한 개념으로 느껴질 수도 있습니다만 &quot;바운디드 컨텍스트&quot;가 마이크로 서비스를 엮는 중간 복합자 개념이라면, &quot;모듈&quot;은 하나의 소규모 시스템을 지칭한다는 면에서 조금 다르게 봐 주시면 감사하겠습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>기술 이야기</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/56</guid>
      <comments>https://koeunyeon.tistory.com/entry/%EC%96%B4%EC%84%A4%ED%94%88-%EC%95%A0%EC%9E%90%EC%9D%BC#entry56comment</comments>
      <pubDate>Thu, 9 Apr 2026 11:19:10 +0900</pubDate>
    </item>
    <item>
      <title>FastAPI 써 본 후기</title>
      <link>https://koeunyeon.tistory.com/entry/FastAPI-%EC%8D%A8-%EB%B3%B8-%ED%9B%84%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 &lt;span&gt;2022년 1월 7일&lt;/span&gt; 제 벨로그 &lt;a href=&quot;https://velog.io/@koeunyeon/FastAPI-%EC%8D%A8-%EB%B3%B8-%ED%9B%84%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@koeunyeon/FastAPI-%EC%8D%A8-%EB%B3%B8-%ED%9B%84%EA%B8%B0&lt;/a&gt;&amp;nbsp;에 썼던 글을 티스토리로 옮긴 것입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h1 id=&quot;fastapi&quot;&gt;FastAPI?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬을 이용한 웹 개발 세계에서는 &lt;a href=&quot;https://fastapi.tiangolo.com/ko/&quot;&gt;FastAPI&lt;/a&gt; 가 최근 기술로 각광받고 있는 중입니다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;595&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JoYtt/dJMcabpNx1b/cjvmwYFoj3Ky7RM3egM15k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JoYtt/dJMcabpNx1b/cjvmwYFoj3Ky7RM3egM15k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JoYtt/dJMcabpNx1b/cjvmwYFoj3Ky7RM3egM15k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJoYtt%2FdJMcabpNx1b%2FcjvmwYFoj3Ky7RM3egM15k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1150&quot; height=&quot;595&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;595&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;614&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4vJzi/dJMcabpNx1a/KtmKU87qUKkM95j4sKStGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4vJzi/dJMcabpNx1a/KtmKU87qUKkM95j4sKStGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4vJzi/dJMcabpNx1a/KtmKU87qUKkM95j4sKStGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4vJzi%2FdJMcabpNx1a%2FKtmKU87qUKkM95j4sKStGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1159&quot; height=&quot;614&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;614&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;물론 전통의 풀스택 프레임워크 &lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;Django&lt;/a&gt; 나 마이크로 프레임워크 &lt;a href=&quot;https://flask.palletsprojects.com/en/2.0.x/&quot;&gt;Flask&lt;/a&gt;에 비할 바는 아닙니다만 프레임워크 개발이 &lt;a href=&quot;https://github.com/tiangolo/fastapi/pull/1&quot;&gt;2018년 12월부터 시작되었다&lt;/a&gt;는 점을 감안하면 꽤나 빨리 뜨거운 감자가 된 셈이죠.&lt;br /&gt;그래서 &lt;s&gt;&lt;a href=&quot;https://velog.io/@koeunyeon/%EC%B5%9C%EC%8B%A0-%EA%B8%B0%EC%88%A0%EC%9D%B4-%EC%9A%B0%EB%A6%AC%EB%A5%BC-%EB%A9%8D%EB%93%A4%EA%B2%8C-%ED%95%9C%EB%8B%A4&quot;&gt;뱉은 말&lt;/a&gt;과 다르게&lt;/s&gt; 한번 API 문서를 둘러보고 직접 사용해 보았습니다.&lt;/p&gt;
&lt;h1 id=&quot;엔드포인트-매핑은-플라스크-방식으로&quot;&gt;엔드포인트 매핑은 플라스크 방식으로&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에도 이런 방식이 있었는지는 잘 모르겠습니다만, 저는 플라스크때 처음으로 데코레이터를 이용해 엔드포인트를 정의하는 방식을 봤습니다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;@app.get(&quot;/hello&quot;)
def hello() :&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 방식은 장점도 있고 단점도 있는데요. 장점은 직관적으로 어떤 엔드포인트가 호출되면 어느 함수가 호출될 지 알 수 있다는 겁니다.&lt;br /&gt;단점은 엔드포인트를 찾으려면 파일 하나에서 찾는 대신 ctrl + H(전체검색) 가 필요하다는 정도죠.&lt;br /&gt;여튼 저는 이 방식이 익숙하기 때문에 특별한 불만은 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI는 전체적인 아키텍쳐가 Flask의 영향을 많이 받았는지 개발 결과물의 코딩 스타일이 Flask와 전반적으로 비슷합니다. Flask에는 익숙한 개발자들이 많으므로 스타일이 비슷하다고 해서 특별히 문제가 될만한 것은 없습니다.&lt;/p&gt;
&lt;h1 id=&quot;타입을-적극적으로-이용하는-프레임워크&quot;&gt;타입을 적극적으로 이용하는 프레임워크&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 3.5 버전에서 타입 힌트라는 게 생겼습니다. 동적 자료형 언어에서 무슨 타입인가 싶었지만, 있으면 IDE 자동완성 등 편리한 기능도 있는 것이 사실입니다. name : str = &quot;koeunyeon&quot; 이런 식으로 씁니다.&lt;br /&gt;FastAPI는 타입에 많이 의존합니다. 공식 홈페이지의 소개에 적혀 있는 아래 문구는 모두 타입 의존성으로 인해 얻은 효과입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적은 버그: 사람(개발자)에 의한 에러 약 40% 감소. *&lt;br /&gt;직관적: 훌륭한 편집기 지원. 모든 곳에서 자동완성. 적은 디버깅 시간.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI는 그냥 파이썬의 타입 힌트만 사용하지는 않습니다. 타입 힌트를 지원하는 라이브러리 &lt;a href=&quot;https://pydantic-docs.helpmanual.io/&quot;&gt;pydantic&lt;/a&gt; 과 강하게 묶여 있습니다. 즉 프레임워크 자체가 pydantic에 의존합니다.&lt;br /&gt;pydantic은 파이썬에서 데이터 모델을 제공하기 위한 라이브러리입니다. 멤버 변수의 자료형과 Optional 여부로 자동으로 데이터의 유효성을 검증해주는 편리한 기능을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 혹은 C# 등의 정적 언어를 사용해서 웹 개발을 해 보신 분들은 웹 요청 파라미터를 처리하기 위해 혹은 DB의 데이터를 담기 위한 컨테이너로 DTO(Data Transfer Object)를 만들어서 사용하실 텐데요. FastAPI에서는 pydantic이 DTO 객체의 역할을 한다고 생각하면 편합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://fastapi.tiangolo.com/ko/&quot;&gt;fastapi에서 pydantic을 사용하는 예제&lt;/a&gt;는 아래와 같습니다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float
    is_offer: Optional[bool] = None

@app.put(&quot;/items/{item_id}&quot;)
def update_item(item_id: int, item: Item):
    return {&quot;item_name&quot;: item.name, &quot;item_id&quot;: item_id}    &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입을 사용해서 개발 안정성을 높이는 것은 좋은 아이디어라고 생각합니다. 특별한 경우가 아닌 이상 변수의 자료형이 바뀌는 경우는 많지 않으니까요.&lt;br /&gt;FastAPI에서 내세우는 pydantic 타입 사용의 장점입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동완성.&lt;/li&gt;
&lt;li&gt;타입 검사.&lt;/li&gt;
&lt;li&gt;데이터 검증:&lt;/li&gt;
&lt;li&gt;데이터가 유효하지 않을 때 자동으로 생성하는 명확한 에러.&lt;/li&gt;
&lt;li&gt;중첩된 JSON 객체에 대한 유효성 검사.&lt;/li&gt;
&lt;li&gt;JSON 읽기&lt;/li&gt;
&lt;li&gt;경로(path) 매개변수 읽기.&lt;/li&gt;
&lt;li&gt;쿼리(query string) 매개변수 읽기.&lt;/li&gt;
&lt;li&gt;쿠키 읽기.&lt;/li&gt;
&lt;li&gt;헤더 읽기.&lt;/li&gt;
&lt;li&gt;폼(Forms) 읽기&lt;/li&gt;
&lt;li&gt;파일 읽기.&lt;/li&gt;
&lt;li&gt;파이썬 타입을 json으로 변환 (str, int, float, bool, list, 등).&lt;/li&gt;
&lt;li&gt;datetime 객체도 json으로 변환. (내장 json 모듈은 datetime 모듈을 변환하지 못합니다.)&lt;/li&gt;
&lt;li&gt;UUID 객체 json 변환.&lt;/li&gt;
&lt;li&gt;pydantic 타입의 데이터베이스 모델 변환.&lt;/li&gt;
&lt;li&gt;Swagger UI.&lt;/li&gt;
&lt;li&gt;ReDoc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 얻을 수 있는 수많은 장점에도 불구하고 저는 동적 스크립트 언어에서 객체를 통한 요청 처리 방식을 그다지 좋아하지 않습니다. 이것은 초기 개발 후 요구사항 변경으로 필드가 변경될 때 문제가 있다는 판단 때문인데요.&lt;br /&gt;정적 언어에서는 DTO 객체의 필드명이 바뀌면 빌드 자체가 안되므로 쉽게 DTO 객체의 정의를 변경할 수 있는 반면 동적 언어는 꾸준히 검색의 힘을 빌어야 합니다. 즉, 스크립트 언어의 특성상 (컴파일 타임이 없으니까) 런타임에나 오류가 발생할 텐데 그럴꺼면 굳이 뭔가를 미리 정의해야 하는가 싶은 의구심이 드는 거죠.&lt;/p&gt;
&lt;h1 id=&quot;swaggeropenapi-혹은-redoc-제공은-정말-편리하다&quot;&gt;swagger(openapi) 혹은 redoc 제공은 정말 편리하다.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실은 이것 때문에 FastAPI를 고려해서 테스트해봤던 거였는데요.&lt;br /&gt;저는 회사에서 백엔드 파트를 담당하고 있고, 백엔드는 결국 클라이언트에서 쓸 API를 만드는 일이 대부분이기 때문에 클라이언트 개발자들이 쉽게 볼 수 있는 문서화가 반드시 필요합니다.&lt;br /&gt;따라서 &lt;s&gt;절대 문서를 만들기 귀찮아서가 아니라&lt;/s&gt; 자동화된 문서화를 위하여 &lt;a href=&quot;https://swagger.io/&quot;&gt;스웨거&lt;/a&gt;를 제공하려고 했던 겁니다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c46dQC/dJMcahcrvhp/dbkPAHHKKDUfryzBkNrSLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c46dQC/dJMcahcrvhp/dbkPAHHKKDUfryzBkNrSLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c46dQC/dJMcahcrvhp/dbkPAHHKKDUfryzBkNrSLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc46dQC%2FdJMcahcrvhp%2FdbkPAHHKKDUfryzBkNrSLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;1080&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gw3bv/dJMb99ZOPpX/caqJvMwYFCYz7WkepkNs6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gw3bv/dJMb99ZOPpX/caqJvMwYFCYz7WkepkNs6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gw3bv/dJMb99ZOPpX/caqJvMwYFCYz7WkepkNs6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGw3bv%2FdJMb99ZOPpX%2FcaqJvMwYFCYz7WkepkNs6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;1080&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;정말 너무 좋았습니다.&lt;/p&gt;
&lt;h1 id=&quot;depends는-훌륭하다&quot;&gt;Depends는 훌륭하다.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 주입(Dependency Injection)은 불편하지만 꽤나 유용한 기법입니다.&lt;br /&gt;우리가 개발을 하다 보면 다른 객체를 내부에 가지고 사용하는 경우가 꽤 있는데요. 소위 합성이라고 불리는 형태죠. 이렇게 내부에 가지고 있는 다른 객체의 인스턴스를 클래스 외부에서 생성하고 객체 안으로 밀어넣는 기법을 의존성 주입이라고 부릅니다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Inner:
    def __init__(self):
        self.name = &quot;i am inner class&quot;

    def run(self):
        print(&quot;inner run. name :&quot; , self.name)

class Composit:
    inner : Inner
    def __init__(self, inner):
        self.inner = inner
    
    def run(self):
        self.inner.run()

inner = Inner()
composit = Composit(inner)
composit.run()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대충 이런 식입니다. 스프링은 객체를 생성하는 과정을 자동화해주고 자랑스러워하고 있습니다. 그리고 이 DI를 통해 스프링이 널리 사용될 수 있었죠.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 여기가 없어도 됨.
# inner = Inner()
# composit = Composit(inner)
# composit.run()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI에서는 클래스 단위로 의존성을 주입하기보다는 함수 레벨에서 의존성을 주입시킬 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;async def verify_token(x_token: str = Header(...)):
    ...

async def verify_key(x_key: str = Header(...)):
    ...

@app.get(&quot;/items/&quot;, x_key=Depends(verify_key), dependencies=[Depends(verify_token)])
async def read_items():
    print(x_key)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의존성 주입은 이전에는 데코레이터를 통해 검사하고, 값을 객체 멤버변수를 통해 넣어주던 것을 훨씬 간단하게 해 주었습니다. 예전에는 이렇게 해야 했어요.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;class Items:
    @verify_token
    @verify_key
    async def read_items(self):
        x_key = self.x_key # self.x_key는 @verify_key가 객체에 접근해서 넣어준 멤버변수&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 훌륭한 기능이라고 생각해요.&lt;/p&gt;
&lt;h1 id=&quot;비동기는-생각보다-불편하더라&quot;&gt;비동기는 생각보다 불편하더라.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;저는 노인성 개발 신기술 불감증을 앓고있는 환자이기 때문에 신기술을 받아들이는 것을 좋아하지 않습니다.&lt;/s&gt;&lt;br /&gt;아얘 Node.js 처럼 비동기가 기본이어서 모든 라이브러리가 비동기를 전제로 하고 있다면 오히려 개발은 쉬울 꺼에요.&lt;br /&gt;하지만 기본적으로 파이썬은 동기로 동작하고, 파이썬 3.4 버전이 되어서야 &lt;a href=&quot;https://docs.python.org/ko/3/library/asyncio.html&quot;&gt;asyncio&lt;/a&gt; 를 통한 비동기 처리를 지원하기 시작했어요. 심지어는 파이썬 3.8 버전에는 비동기 관련 이슈가 있어서 사실상 활성화는 파이썬 3.9 버전부터 되었어요.&lt;br /&gt;게다가 파이썬은 GIL(Global Interpreter Lock) 때문에 쓰레드의 사용도 권장되지 않았기 때문에 파이썬 개발자들이나 라이브러리들은 동시성 개발 따위는 전혀 신경도 안쓰고 만들어진 경우가 많죠. 그래서 동시성 처리를 위한 모듈이 없는 경우가 많아요.&lt;br /&gt;단적인 예로 파이썬 ORM계에서는 탑 레벨인 SQLAlchemy도 1.4 버전이 되어서야 &lt;a href=&quot;https://docs.sqlalchemy.org/en/14/orm/extensions/asyncio.html&quot;&gt;비동기를 지원&lt;/a&gt;하기 시작했어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기와 동기 방식이 혼용이 되면서 모듈이 비동기를 지원하게 되었더라도 async 키워드와 await 키워드만으로는 동작하지 않는 경우가 많이 생기더군요. 외부에서 pip를 통해 설치한 모듈이야 단위테스트를 거쳤겠지만, 제가 개인적으로 만드는 라이브러리는 &quot;동기와 비동기를 모두 고려&quot;해서 만들어야 한다는 뜻이 되더라고요.&lt;br /&gt;게다가 개발이 종료된 모듈의 경우 비동기 자체를 지원하지 않는 경우도 많아 더욱 곤란한 상황이 몇몇 있었습니다.&lt;/p&gt;
&lt;h1 id=&quot;데이터베이스-연동은-너무너무너무너무-번거롭다&quot;&gt;데이터베이스 연동은 너무너무너무너무 번거롭다.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 서버가 데이터베이스 연동을 하지 않는 일은 거의 없을 거에요. 그런만큼 데이터베이스 연동은 가장 쉬운 일이어야 한다고 생각합니다.&lt;br /&gt;하지만 공식 홈페이지의 문서 (&lt;a href=&quot;https://fastapi.tiangolo.com/ko/advanced/sql-databases-peewee/&quot;&gt;Peewee를 이용한 동기 방식&lt;/a&gt;, &lt;a href=&quot;https://fastapi.tiangolo.com/ko/advanced/async-sql-databases/&quot;&gt;SQLAlchemy를 이용한 비동기 방식&lt;/a&gt;)를 보면 알 수 있듯이 파이썬에서 데이터베이스를 연동하는 건 그다지 쉬운 일이 아닙니다. 특히 ORM을 연동하는 건요.&lt;br /&gt;물론 복사 붙여넣기로 동작하게 하는 것 자체는 쉽습니다만 다수의 데이터베이스 서버 연동이라거나, active record 방식이 아닌 entity와 repository manager를 이용한 방식 등을 사용하기에는 너무 불편함이 많았어요.&lt;br /&gt;&lt;s&gt;저는 이 글을 읽으시는 분들이 제가 실력 없이 말만 많다는 것을 알고 계실꺼라 생각하기 때문에 &quot;개발을 못하니까 어렵지&quot; 라는 팩트는 절대 뱉지 않을 겁니다.&lt;/s&gt;&lt;/p&gt;
&lt;h1 id=&quot;de-facto-standard-사실상의-표준-방식의-문제점&quot;&gt;de facto standard (사실상의 표준) 방식의 문제점&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상의 표준(de facto standard)은 &quot;무조건 이렇게 만들어야 동작한다는 지침은 없고 A 방법으로 만드는 것을 권유해&quot; 정도를 말합니다.&lt;br /&gt;다시 말하면 개발을 할 때 &quot;코딩 스탠다드&quot;가 없거나 약해서 개발자에 따라 스타일이 굉장히 많이 갈리게 되죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실상의 표준은 좋게 말하면 자유로운 것이고, 나쁘게 말하면 무책임한 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잔소리쟁이 자바 월드의 웹 개발 표준 스프링 프레임워크는 터무니없이 복잡한 규칙을 가지고 있어서 누구나 특정 목적을 위해서는 거의 비슷한 형태의 코드를 작성해야 합니다.&lt;br /&gt;자유로운 영혼의 vanilla PHP로 웹 개발을 하게 된다면 규칙이라고 부를만한 것이 거의 없어서 특정 목적을 달성하는 방법이 천개도 넘을 꺼에요.&lt;br /&gt;이러한 상반된 특성은 특정 우위를 가진다기보다는 개발자의 특성과 프로젝트의 특성에 맞물려 있습니다. 각각 장점과 단점이 있고 서로의 장점이 반대편의 단점이 될 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 FastAPI는 자바처럼 빡빡한 규칙을 가지지만 FastAPI 개발진에서 예상하지 않은 특정 문제에 대해서는 vanilla php처럼 (혹은 &lt;a href=&quot;https://www.python.org/dev/peps/pep-0020/&quot;&gt;python zen&lt;/a&gt;처럼) 능력껏 빠져나가야 합니다. 두가지의 특성이 하나의 프로젝트에 공존한다는 의미이고, 언제 충돌을 일으켜도 이상하지 않다는 뜻이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 우려하는 &quot;사실상의 표준&quot; 문제는 Flask에서도 동일하게 나오는데요.&lt;br /&gt;다만 Flask는 원래부터 Micro Framework를 지향하고 있었고, &lt;a href=&quot;https://flask.palletsprojects.com/en/2.0.x/foreword/#growing-with-flask&quot;&gt;메타 프레임워크로 사용하라는 것이 모토&lt;/a&gt;인만큼 (일부러 그러나 싶을 정도로) 메뉴얼이 어렵고 복잡하게 작성되어 있죠.&lt;br /&gt;하지만 FastAPI는 그렇지 않아요. 공식 메뉴얼은 정말 자세하게 적혀 있고 따라하면 무조건 결과가 나오게 되어 있습니다. 책으로 출판해도 될 만큼 한 줄 한 줄 코드를 설명해 줍니다.&lt;br /&gt;이렇게 하나씩 다 알려주고 이대로 하라고 지침을 주지만 메뉴얼에 없는 예외의 상황에서는 어떻게 해야 할 지 표준이 없다는 게 문제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저도 API 를 하나 만들다가 도저히 풀기 어려운 문제에 부딛히는 바람에.. FastAPI의 사용을 포기하게 되었습니다.&lt;br /&gt;그냥 처음부터 지저분했으면 지저분하면 어때..라고 구현을 할 텐데, 다른 공식 지원 스타일 코드는 깔끔한데 내가 만든 코드는 지저분한 건 잘 못참겠더라고요.&lt;/p&gt;
&lt;h1 id=&quot;이럴꺼면-스프링이나-aspnet-core-mvc로-만드는-게-훨씬-낫지-않나&quot;&gt;이럴꺼면 스프링이나 ASP.NET Core MVC로 만드는 게 훨씬 낫지 않나?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FastAPI 문서를 둘러보고 직접 작은 API 몇개를 개발해 보고 난 후 이런 생각이 들었습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트의 파이썬 버전인가?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 시스템 도입으로 인한 빡빡한 기준, DDD를 하고싶어지는 논리 레이어, 정작 필요할 때는 없는 de facto ..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고 Ruby on rails 처럼 극적으로 코드량이 줄어드는 것도 아닙니다. 샘플 예제에서는 간결해 보이지만 실제로 비즈니스 로직이 들어가는 순간부터는 복잡도가 급격히 상승해 버립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 Flask 처럼 코드를 작성하고 pydantic 부분만 살려서 갈 까도 계속 고민하고 코드를 바꿔 보았는데, 우아한 프레임워크 코드에 참 안어울려서 그만두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 &lt;b&gt;&quot;스크립트 언어는 그 특성을 살려서 가능한 동적으로 기능을 구성하고 코드량을 적게 가져가는 것&quot;&lt;/b&gt;이 가장 큰 장점이라고 생각합니다. 반면 &lt;b&gt;&quot;정적 언어는 코드를 복잡하게 작성하더라도 누가 작성해도 비슷한 코드를 안정적으로 쓰는 것&quot;&lt;/b&gt; 이 그 지향점이라고 생각하고요.&lt;br /&gt;하지만 FastAPI로 작성한 제 코드는 이것도 저것도 아닌, 마치 오토바이인 척 하는 자전거 같다는 생각이 계속 들어서 결국 FastAPI 도입은 안하기로 했습니다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csA0Gc/dJMcahcrvhq/QKm15jO9Tt9FcI6uGlGJu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csA0Gc/dJMcahcrvhq/QKm15jO9Tt9FcI6uGlGJu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csA0Gc/dJMcahcrvhq/QKm15jO9Tt9FcI6uGlGJu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsA0Gc%2FdJMcahcrvhq%2FQKm15jO9Tt9FcI6uGlGJu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;450&quot; height=&quot;768&quot; data-origin-width=&quot;450&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;(&lt;s&gt;내 소중한 2주..&lt;/s&gt;)&lt;/p&gt;
&lt;h1 id=&quot;대안-찾아보기&quot;&gt;대안 찾아보기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 찾기 쉬운 대안은 당연히 Flask였습니다. 거의 비슷하거든요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 뭔가 더 좋은 방안이 있을 거라는 생각에 &lt;a href=&quot;https://www.youtube.com/watch?v=SlVbNM1FMZo&quot;&gt;하루를 헤메다&lt;/a&gt;가 &lt;a href=&quot;https://aws.github.io/chalice/&quot;&gt;AWS CHALICE&lt;/a&gt;를 발견했습니다. &lt;a href=&quot;https://aws.amazon.com/ko/lambda/&quot;&gt;AWS LAMBDA&lt;/a&gt; 위에서 돌아가는 파이썬 웹 프레임워크입니다.&lt;br /&gt;사용법도 간단하고, 그다지 프레임워크 레벨에서 강요하는 것도 없습니다. &lt;s&gt;저는 역시 우아한 프로그래밍보다는 실전 지향 코딩을 더 좋아하는 것 같습니다.&lt;/s&gt;&lt;br /&gt;람다 위에서 실행되므로 서버의 스케일 아웃같은 귀찮은 일을 하지 않아도 되고 사용하지 않으면 돈도 안 냅니다.&lt;br /&gt;물론 일반 서버에 직접 배포해서 실행하는 것은 안되지만 (되기야 하겠지만 AWS에서 권고할 일은 없겠죠.) 반대로 직접 서버를 관리하지 않아도 됩니다. 로그는 클라우드워치에서 보면 되는 거고 서버의 용량이나 트래픽 같은 것도 걱정할 필요 없어요.&lt;br /&gt;그리고 아무리 생각해도 AWS가 망하거나 LAMBDA 서비스를 내릴 확률보다는 제가 개발자를 그만둘 확률이 훨씬 더 높을 것 같아서 그냥 사용하기로 했습니다.&lt;br /&gt;그리고 한달쯤 지났는데 (잘 안되는 것도 있지만 그래도 뭐 이정도면 쓸만은 하네 싶어서) 꽤나 만족하면서 사용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스웨거는 지원하지 않지만, 그냥 손으로 API 문서 작성하던가 하면 됩니다. 기능이 동작 안하는 건 큰 문제지만 문서화는 수작업으로도 가능하니까요.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>기술 이야기</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/55</guid>
      <comments>https://koeunyeon.tistory.com/entry/FastAPI-%EC%8D%A8-%EB%B3%B8-%ED%9B%84%EA%B8%B0#entry55comment</comments>
      <pubDate>Tue, 7 Apr 2026 11:15:30 +0900</pubDate>
    </item>
    <item>
      <title>API 명세서는 희망 사항일 뿐</title>
      <link>https://koeunyeon.tistory.com/entry/API-%EB%AA%85%EC%84%B8%EC%84%9C%EB%8A%94-%ED%9D%AC%EB%A7%9D-%EC%82%AC%ED%95%AD%EC%9D%BC-%EB%BF%90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;결국 우리 둘 다 맞았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상대 시스템 담당자와 전화로 30분을 싸웠습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;명세서대로 보냈어요.&quot;&lt;br /&gt;&quot;아뇨, 이렇게 와요.&quot;&lt;br /&gt;&quot;그럴 리 없어요.&quot;&lt;br /&gt;&quot;캡처 보냈잖아요.&quot;&lt;br /&gt;&quot;저쪽에서 잘못 파싱한 거 아니에요?&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 틀리지 않았습니다. 명세서가 애매했을 뿐입니다.&lt;/p&gt;
&lt;h2 id=&quot;필수&quot; data-ke-size=&quot;size26&quot;&gt;필수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명세서에는 이렇게 적혀 있었습니다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;필드명: customer_id
타입: String
필수: Y&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필수가 Y입니다. 값이 반드시 있어야 합니다. 우리는 그렇게 이해했습니다. null이 오면 에러를 던지게 만들었습니다. 당연한 방어 코드였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상대 시스템에서는 다르게 이해했습니다. 필수니까 필드는 반드시 보낸다. 값이 없을 수도 있지만 필드 자체는 있다. &quot;customer_id&quot;: &quot;&quot; 이렇게. 빈 문자열.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 문자열은 null이 아닙니다. 필드는 있습니다. 그들 기준에서는 &quot;필수&quot;를 지킨 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리 기준에서는 빈 문자열이면 안 됩니다. 값이 있어야 합니다. 필수라며.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명세서 어디에도 &quot;값이 없을 경우&quot;에 대한 정의가 없었습니다. 빈 문자열은 허용인가 불허인가. 공백은? null 문자열은?&lt;/p&gt;
&lt;h2 id=&quot;30분&quot; data-ke-size=&quot;size26&quot;&gt;30분&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전화 통화가 길어졌습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;명세서에 필수라고 했잖아요.&quot;&lt;br /&gt;&quot;네, 그래서 필드 보냈잖아요.&quot;&lt;br /&gt;&quot;값이 없으면 필수가 아닌 거 아니에요?&quot;&lt;br /&gt;&quot;값이 없을 수도 있죠. 필드는 보냈으니까 필수를 지킨 거예요.&quot;&lt;br /&gt;&quot;그럼 필수라는 게 무슨 의미예요?&quot;&lt;br /&gt;&quot;필드가 반드시 존재한다는 의미죠.&quot;&lt;br /&gt;&quot;...&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서로 어이없다는 목소리였습니다. 둘 다 자기가 맞다고 생각했습니다. 둘 다 명세서를 근거로 들었습니다. 같은 문서를 보고 다르게 해석한 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 제가 양보했습니다. 빈 문자열을 허용하기로 했어요. 코드를 고쳤습니다. 30분 싸우고, 10분 만에 수정했습니다. &lt;s&gt;별것도 아닌 것에 시간을 낭비한 것에 대해 뿌듯..아닙니다.&lt;/s&gt;&lt;/p&gt;
&lt;h2 id=&quot;몇가지-더&quot; data-ke-size=&quot;size26&quot;&gt;몇가지 더&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비슷한 일이 몇 번 더 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;날짜 포맷. 명세서에는 yyyyMMdd라고 적혀 있었습니다. 20260115처럼 온다고 생각했죠.&lt;br /&gt;상대 시스템에서는 2026-01-15로 보내왔습니다. 포멧팅이 경우에 따라 다를 수도 있어서 스펙 확인을 부탁했더니 이렇게 답하더군요.&lt;br /&gt;&quot;원래 이렇게 보내요. 명세서가 오래됐나 보네요.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금액 타입. 명세서에는 &quot;Number&quot;라고 적혀 있었습니다. 10000이 오는 줄 알았습니다. 실제로는 &quot;10,000&quot;이 왔습니다. 쉼표가 있는 문자열.&lt;br /&gt;Integer와 String의 차이는 개발의 세계에서는 아프리카와 러시아만큼 멀리 있잖아요.&lt;br /&gt;당연히 파싱 에러가 났습니다. 물었습니다. &quot;아, 그건 표시용 포맷이에요. 알아서 처리하세요.&quot;&lt;br /&gt;&lt;s&gt;아마 이분들은 숫자 구분자를 콤마가 아니라 .이나 공백 등 다른 문자를 쓰는 나라가 있다는 것까지는 생각 못하셨을 겁니다.&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 코드. 명세서에는 &quot;정상: 0, 오류: -1&quot;이라고 적혀 있었습니다. -1이 오면 실패라고 생각했죠.&lt;br /&gt;실제로는 -1이 아니라 &quot;-1&quot;이 왔습니다. 문자열. 그리고 가끔 &quot;ERROR&quot;라는 문자가 오기도 했습니다.&lt;br /&gt;&quot;특수 상황일 때요. 명세서에 없나요? 아, 없네요. 그냥 처리해주세요.&quot;&lt;br /&gt;&lt;s&gt;아 왠지 화가 나는데.... 스펙은 틀릴 수 있지만 그냥 처리해 주세요는 좀 태도가 무책...&lt;/s&gt;&lt;/p&gt;
&lt;h2 id=&quot;명세서는-계약이-아닙니다&quot; data-ke-size=&quot;size26&quot;&gt;명세서는 계약이 아닙니다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때 깨달은 게 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명세서는 법적 구속력이 있는 계약서가 아닙니다. 의도를 전달하는 문서일 뿐입니다.&lt;br /&gt;작성자의 의도와 독자의 해석이 다를 수 있습니다. 그리고 보통은 다릅니다. 인간의 상식이 모두 다르듯이요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고 명세서가 필요 없는 건 아닙니다. 명세서가 없으면 더 힘들어요.&lt;br /&gt;말로만 전달하면 기록이 없습니다. 나중에 &quot;그렇게 말한 적 없는데요&quot;가 되죠. &lt;s&gt;당하면 저혈압약은 불필요...&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명세서는 출발점입니다. 대화의 시작입니다. &quot;이 문서대로 할게요&quot;가 아니라 &quot;이 문서 기준으로 맞춰보죠&quot;입니다.&lt;/p&gt;
&lt;h2 id=&quot;전화기&quot; data-ke-size=&quot;size26&quot;&gt;전화기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연계 개발에서 가장 중요한 도구는 방어 로직이 아닙니다. null 체크, 타입 검증, 예외 처리. 다 중요하지만, 정답은 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 정답에 가까운 건 &lt;b&gt;전화기&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명세서를 읽고 궁금한 게 있으면 전화합니다.&lt;br /&gt;이메일로 물으면 답변이 이틀 걸립니다. 전화하면 5분입니다.&lt;br /&gt;통화하면서 명세서를 같이 봅니다. &quot;여기 필수라고 되어 있는데, 값이 없으면 어떻게 보내세요?&quot;라고 물으면 바로 답이 옵니다.&lt;br /&gt;&lt;s&gt;당연히 어 그런 스펙이 있었나요? 라는 답변이 돌아올 수도 있습니다. 이러지 마 좀...&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 통화 끝나면 메일을 보냅니다. 기록을 남기는 거죠.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방금 통화한 내용 정리합니다.&lt;br /&gt;필수 필드는 빈 문자열 허용.&lt;br /&gt;확인 부탁드립니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명세서를 믿는 게 아닙니다. 사람을 믿습니다. 정확히는, 사람과 확인한 내용을 믿습니다.&lt;/p&gt;
&lt;h2 id=&quot;시간이-지나면&quot; data-ke-size=&quot;size26&quot;&gt;시간이 지나면&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연계가 안정화됐습니다. 에러도 안 나고 조용했어요. &lt;s&gt;아이 행복해.&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6개월 뒤, 상대 시스템이 업데이트됐다는 연락을 받았습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;포맷 좀 바꿨어요. 명세서 보내드릴게요.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;새 명세서를 받았습니다. v2.3. 이전 버전이 뭐였는지도 몰랐어요. 사실은 애시당초 버전관리를 하고 있다는 것도 이번 기회에 알았죠.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;customer_id 필드.&lt;br /&gt;필수: Y.&lt;br /&gt;비고: &quot;값이 없을 경우 빈 문자열(&quot;&quot;)로 전송&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6개월 전에 전화로 싸웠던 내용이 명세서에 &lt;s&gt;드디어&lt;/s&gt;반영되어 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;늦었지만 고마웠습니다. 그리고 동시에 생각했습니다. 이 명세서도 6개월 뒤에는 또 안 맞겠지.&lt;/p&gt;
&lt;h2 id=&quot;그래서&quot; data-ke-size=&quot;size26&quot;&gt;그래서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연계 개발을 시작하면 이렇게 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명세서를 받습니다. 읽습니다. 애매한 부분을 표시합니다. 필수의 정의, 빈 값의 처리, 타입의 범위, 에러 케이스. 명세서에 없거나 해석의 여지가 있는 것들.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전화해서 표시한 부분을 하나씩 묻습니다. 답을 받고 메일로 정리해서 보내 확인받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래도 문제가 생깁니다. 그러면 또 전화합니다. 또 맞춥니다. 또 기록합니다. &lt;s&gt;이것이야말로 우리가 말하는 while loop&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명세서를 믿지 않습니다. 하지만 명세서 없이는 대화가 안 됩니다. 명세서는 대화의 재료입니다. 완성된 답이 아니라, 질문의 시작입니다.&lt;/p&gt;</description>
      <category>프리랜서 개발자의 삶</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/71</guid>
      <comments>https://koeunyeon.tistory.com/entry/API-%EB%AA%85%EC%84%B8%EC%84%9C%EB%8A%94-%ED%9D%AC%EB%A7%9D-%EC%82%AC%ED%95%AD%EC%9D%BC-%EB%BF%90#entry71comment</comments>
      <pubDate>Mon, 6 Apr 2026 16:50:51 +0900</pubDate>
    </item>
    <item>
      <title>최신 기술이 우리를 멍들게 한다.</title>
      <link>https://koeunyeon.tistory.com/entry/%EC%B5%9C%EC%8B%A0-%EA%B8%B0%EC%88%A0%EC%9D%B4-%EC%9A%B0%EB%A6%AC%EB%A5%BC-%EB%A9%8D%EB%93%A4%EA%B2%8C-%ED%95%9C%EB%8B%A4</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 &lt;span&gt;2021년 12월 29일&lt;/span&gt; 제 벨로그 &lt;a href=&quot;https://velog.io/@koeunyeon/%EC%B5%9C%EC%8B%A0-%EA%B8%B0%EC%88%A0%EC%9D%B4-%EC%9A%B0%EB%A6%AC%EB%A5%BC-%EB%A9%8D%EB%93%A4%EA%B2%8C-%ED%95%9C%EB%8B%A4&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@koeunyeon/%EC%B5%9C%EC%8B%A0-%EA%B8%B0%EC%88%A0%EC%9D%B4-%EC%9A%B0%EB%A6%AC%EB%A5%BC-%EB%A9%8D%EB%93%A4%EA%B2%8C-%ED%95%9C%EB%8B%A4&lt;/a&gt;&amp;nbsp;에 썼던 글을 티스토리로 옮긴 것입니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h1 id=&quot;최신-기술&quot;&gt;최신 기술&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아, 이런 식으로 작성하는 코드는 마음에 들지 않는데, 더 좋은 방법이 없을까?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자로 살다보면 이런 경험이 한번쯤은 있을 꺼에요. 그래서 새로운 사상, 사용해보지 않은 언어, 신규 프레임워크를 찾아 헤매게 되죠.&lt;br /&gt;정상이에요. &lt;s&gt;칼퇴근을 위해&lt;/s&gt; 같은 일을 더 효율적으로 하는 것은 엔지니어로서의 본능에 가깝다고 생각해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 개인적으로 기술 스택을 여러번 바꿨어요. 닷넷 개발자로 시작했고, 자바로 전향했어요. PHP를 겸용했으며, 파이썬을 사용하죠. 가끔 노드 코드를 들여다보기도 해요. DBMS도 그래요. MS-SQL도 써 봤고, 오라클도 사용해 보고, MySQL도 다뤄보고 MongoDB도 경험해 봤죠.&lt;br /&gt;시간이 흐르면서 깨달은 건 &lt;b&gt;최신 기술은 과거의 영광 아래 세워졌으며, 기존의 문제는 해결하지만 새로운 문제를 가지고 온다&lt;/b&gt;는 거에요.&lt;br /&gt;그래서 무조건 최신 기술을 탐닉하기보다는, 조금 더 신중해질 필요가 있다고 생각하게 되었어요.&lt;/p&gt;
&lt;h1 id=&quot;시간을-가지고-검증해라&quot;&gt;시간을 가지고 검증해라&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매일 자고 일어나면 새로운 기술이 나와 있어요. 모두 각자의 사상에 의해 새로운 코드를 작성하고 공개하죠. 스스로 필요하기 때문에 만들어낸 결과물이에요.&lt;br /&gt;하지만 시간의 검증을 받아 살아남는 기술은 굉장히 적어요. 필요없어서일 수도 있고, 발견되지 않았을 수도 있고, 컨트리뷰터들이 스스로 지쳐 그만두었을 가능성도 있죠. 한 때 하이브리드앱 세계를 이끌었던 폰갭을 어도비가 포기한 것처럼요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 저는 최신 기술이라고 무작정 도입하기보다는, 반드시 이 기술을 사용해야 할 이유가 있을 때가 바로 기술을 도입할 시기라고 생각해요. &quot;사용하고 싶어서&quot; 가 아니라 &quot;이 기술을 도입했을 때 얻어지는 극적 효과&quot;를 생각해야 해요.&lt;/p&gt;
&lt;h1 id=&quot;모른다고-스트레스-받을-필요-없어요&quot;&gt;모른다고 스트레스 받을 필요 없어요.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자 커뮤니티에는 유난히 타인의 의견을 잘 받아들이지 못하는 일부 사람들이 있어요. 엔지니어링 마인드로 가득한 사람들은 매사 판단을 bool 로 하죠. True가 아니면 무조건 False 라고 생각하더군요.&lt;br /&gt;이분들은 본인이 알고 있는 혹은 본인이 사용하는 기술에 대해 잘 모르거나 본인과 의견이 다르다면 왜 그걸 모르나며 비난하는 경우가 종종 있는데요.&lt;br /&gt;특히 신기술인 경우 먼저 접해봤다는 얼리 아답터 분들은 최신 기술을 사용해서 본인의 문제를 해결했으므로 (혹은 지적 호기심을 만족시켰으므로) 다른 사람들도 모두 사용해야 한다고 생각하시는 것 같아요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 우리네 인생이 늘 그렇듯이 선택은 아주 긴 선 중에 중간쯤 어디일 가능성이 높아요. 다른 사람의 문제를 해결했다고 내 문제를 해결하리라는 보장 같은 건 어디에도 없어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;얼리아답터의 의견은 겸허하게 받아들이되, 비난은 무시하는 게 정신 건강에 이롭습니다.&lt;/p&gt;
&lt;h1 id=&quot;우리에게-죄책감을-가지게-해요&quot;&gt;우리에게 죄책감을 가지게 해요.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 기술 설파자들이 최신 기술을 따르지 않으면 마치 죄를 짓는 것 마냥 상황을 몰아가는 것을 많이 보아 왔어요.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설파자 : 내 기술이 최고에요.&lt;br /&gt;나 : (당신의 현재 상황에는) 그럴수도 있죠.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설파자 : 내 사상을 따르지 않으면 개발 트렌드에 뒤쳐진 데다가 실력이 없는 개발자에요.&lt;br /&gt;나 : 그럴리는 없어요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 다른 사람의 사상에 따르지 않는다고 해서 형편없는 개발자 취급을 받아야 하는지 저는 잘 이해할 수가 없더군요. 합리적인 이유를 가지고 자기 주장을 하는 것이야 얼마든지 가능하지만 동의하지 않으면 죄인이 된다는 건 옳지 않은 일이라고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 기술보다는 개발 사상 논쟁에서 이런 점이 더 도드라지는 경향이 있는데요.&lt;br /&gt;MVC가 유행하기 시작했을 때 MVC 주창자들은 Presentation Logic, Process Logic, Data Logic이 한번에 섞여있는 소위 모델1 형태의 개발자들을 한심한 사람 취급하기 시작했어요. 사실 아주 간단한 페이지에는 굳이 MVC가 필요 없을 가능성이 높은데도요.&lt;br /&gt;MVC를 도입함으로써 프로그래밍은 더 논리적으로 분리되었고 더 큰 규모의 어플리케이션을 구조적으로 구성할 수 있게 되었지만, 알아야 할 것이 더 많아졌고 단순한 HTML 페이지를 만드는데도 무조건 파일이 3개 이상 (실은 중간 레이어들과 미들웨어를 합치면 십여개도 넘을테죠.) 필요한 주객 전도 상황도 만들어졌다는 점에 대해서는 그당시의 강성 MVC 무적론자들은 아직도 입을 다물고 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 사상들도 다들 비슷해요. REST, GraphQL, DDD, ORM ... 본질은 단순한 것을 그럴듯하게 펼쳐놓고 모르면 악당 취급하는 건 나빠요.&lt;/p&gt;
&lt;h1 id=&quot;장단점을-잘-파악하고-도입해요&quot;&gt;장단점을 잘 파악하고 도입해요.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세상에 무조건 장점만 있는 기술 따위는 없어요.&lt;br /&gt;하다 못해 어셈블리어도 &quot;작성하기는 어렵지만 속도는 엄청나게 빠른&quot; 장단점이 있거든요.&lt;br /&gt;동적 타입을 가지는 스크립트 언어들은 개발 속도를 빠르게 해 주지만 디버깅 속도로 개발 속도를 다 잡아먹는다는 단점이 있습니다.&lt;br /&gt;nodejs는 &quot;비동기로 동작함으로써 프로세스 하나에 여러 요청을 처리할 수 있다는 장점이 있지만 사고방식이 비동기로 전환되어야 한다는 치명적인 단점&quot;이 있죠.&lt;br /&gt;DDD는 작은 단위를 잘 개발할 수 있게 해 주지만 애그리게이트 영역끼리의 복합 개념이 섞일 때 혹은 비즈니스 논리가 변경되어서 애그리게이트의 범위가 변경되었을 때는 속수 무책이라는 단점이 가지고 있어요.&lt;br /&gt;복잡하다는 이유로 일부 설정 파일을 제외하고는 JSON에 밀려서 사라져버린 XML도 의미를 추론하지 않고 기술할 수 있는 장점이 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;이런 기술 혹은 방법론은 장점&lt;b&gt;만&lt;/b&gt; 있어요.&quot; 라는 건 세상에 없어요. 이런 주장은 거짓말이거나 혹은 기술을 주장하는 사람이 처한 상황에서만 그럴 겁니다.&lt;/p&gt;
&lt;h1 id=&quot;레퍼런스가-없다는-점은-지독한-약점이-됩니다&quot;&gt;레퍼런스가 없다는 점은 지독한 약점이 됩니다.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신기술이라는 단어는 新기술, 즉 새로운 기술이라는 뜻이죠.&lt;br /&gt;새로운 기술이라는 건 써 본 사람이 상대적으로 적다는 이야기이고, 써 본 사람이 상대적으로 적다는 건 &quot;특정한 문제에 처했을 때 해결해 본 사람이 적다는&quot; 이야기이며, &quot;해결해 본 사람이 적다는 건 찾아볼 참고 자료가 적다는 뜻&quot; 이 되는 것이며, 결론적으로 &quot;신기술을 쓰는 우리도 해결 못할 가능성이 높다&quot;는 의미가 되어요.&lt;br /&gt;신기술을 도입함으로써 생기는 잇점을 레퍼런스 부족이 모두 상쇄하고도 남을 가능성이 꽤 높다고 생각해요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 신기술을 쓰는 사람이 적기 때문에 구인에도 큰 문제가 있을테죠.&lt;/p&gt;
&lt;h1 id=&quot;신기술에-무지하란-이야기가-아닙니다&quot;&gt;신기술에 무지하란 이야기가 아닙니다.&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 신중하라는 이야기에요.&lt;br /&gt;어떤 기술이 나왔는지 매일 지켜볼 필요는 없겠지만 요새 유행하는 게 뭔지 가끔 서점이라도 가서 둘러보세요.&lt;br /&gt;가끔 개발자 커뮤니티라도 가서 어떤게 유행하는지 살펴보는 것도 좋아요.&lt;br /&gt;대신 뭔가를 접할 때는 반드시 필터를 장착하세요. 필터의 기준은 &quot;내가 처한 상황에 어울리는가&quot; 입니다. 그리고 장점과 단점이 무엇인지도 잘 살펴보고요.&lt;/p&gt;
&lt;h1 id=&quot;신기술로-이득을-보는-사람&quot;&gt;신기술로 이득을 보는 사람&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신기술을 도입해서 이득을 보는 사람은 여러분이 아니라 기술을 파는 사람들일 가능성이 높습니다.&lt;br /&gt;책을 팔 수도 있고, 강의를 팔 수도 있으며, 강연을 다닐 수도 있고 기술 자체를 팔 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신기술을 도입하는 사람들은 어떤 이득을 볼까요? 멋진 베타테스터가 될 수 있습니다. &lt;s&gt;써보고 마구 욕할 가능성 농후&lt;/s&gt;&lt;/p&gt;
&lt;h1 id=&quot;설레발-주도-프로그래밍&quot;&gt;설레발 주도 프로그래밍&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실은 최신 기술들 일부를 무턱대고 받아들이는 걸 설명하는 단어가 이미 있어요. &lt;a href=&quot;https://lazygyu.net/blog/hype_driven_development&quot;&gt;설레발 주도 개발 - Hype Driven Development&lt;/a&gt; 이라고 부르죠.&lt;br /&gt;설레발 주도 개발을 피하려면, 베타 테스터가 되기 보다는, 얼리 아답터가 되기 보다는 조금 신중할 필요가 있다고 생각해요.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>기술 이야기</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/54</guid>
      <comments>https://koeunyeon.tistory.com/entry/%EC%B5%9C%EC%8B%A0-%EA%B8%B0%EC%88%A0%EC%9D%B4-%EC%9A%B0%EB%A6%AC%EB%A5%BC-%EB%A9%8D%EB%93%A4%EA%B2%8C-%ED%95%9C%EB%8B%A4#entry54comment</comments>
      <pubDate>Sat, 4 Apr 2026 11:13:48 +0900</pubDate>
    </item>
    <item>
      <title>큰 진흙 공(BBOM) 방식과 DDD</title>
      <link>https://koeunyeon.tistory.com/entry/%ED%81%B0-%EC%A7%84%ED%9D%99-%EA%B3%B5BBOM-%EB%B0%A9%EC%8B%9D%EA%B3%BC-DDD</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 &lt;span&gt;2021년 11월 30일&lt;/span&gt; 제 벨로그 &lt;a href=&quot;https://velog.io/@koeunyeon/%ED%81%B0-%EC%A7%84%ED%9D%99-%EA%B3%B5BBOM-%EB%B0%A9%EC%8B%9D%EA%B3%BC-DDD&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@koeunyeon/%ED%81%B0-%EC%A7%84%ED%9D%99-%EA%B3%B5BBOM-%EB%B0%A9%EC%8B%9D%EA%B3%BC-DDD&lt;/a&gt; &amp;nbsp;에 썼던 글을 티스토리로 옮긴 것입니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 &lt;a href=&quot;http://www.yes24.com/Product/Goods/101818336&quot;&gt;파이썬으로 살펴보는 아키텍처 패턴&lt;/a&gt;이라는 책을 보고 있습니다.&lt;br /&gt;여러가지 좋은 이야기가 나오는데, 그 중에서 &lt;b&gt;BIG BALL OF MUD&lt;/b&gt;(&lt;b&gt;BBOM &lt;/b&gt;- &lt;b&gt;큰 진흙공&lt;/b&gt;) 방식에 대한 이야기가 나옵니다.&lt;br /&gt;간단하게 말하면 큰 진흙공 방식은 &lt;b&gt;아키텍처가 없는 소프트웨어 시스템&lt;/b&gt;을 뜻합니다.&lt;br /&gt;즉, 되는대로 만들어지고, 요구사항에 따라 즉흥적인 코드를 만들고, 설계가 없다는 뜻이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말만 들으면 BBOM은 우리 모두가 지&lt;b&gt;양&lt;/b&gt;해야 할 안티 패턴처럼 보입니다. 그리고 많은 글들에서도 동일하게 나쁘니까 따라하지 말자는 논조를 가지고 이야기하죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 어떤 시스템이 완벽한 설계를 기반으로 이루어질 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리 모두 알아야 할 건, 완벽한 설계 따위는 없다는 겁니다.&lt;br /&gt;크고 단단하고 아름다우며 고결한 프로그램을 작성하겠다는 개발자들의 의욕은 높이 사지만 2021년의 개발은 1990년대 데스크탑 프로그램처럼 디스켓이나 CD-ROM에 담아서 출시하고 나면 2년동안은 업데이트가 불가능한 프로그램을 만드는 것이 아닙니다.&lt;br /&gt;우리는 매일 크고 작은 기능을 수정하고 릴리즈합니다. 굳이 웹 프로그램 뿐만 아니라 데스크탑 프로그램도 마찬가지입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다 만들어진 시스템을 가지고 완벽한 설계를 아쉬워하는 건 쉽습니다. 하지만 만드는 과정에서 완벽한 설계를 한다는 건 불가능에 가깝다고 생각합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약에 &quot;모든 설계가 완벽해지는&quot; 순간이 만약 온다고 하면 일부 &quot;설계자&quot;와 &quot;코더&quot;가 분리될 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;http://www.yes24.com/Product/Goods/96264038&quot;&gt;생계형 개발자, SI에서 살아남기&lt;/a&gt; 에서 저자는 이렇게 말합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멋진 설계는 AA가 합니다.&lt;br /&gt;업무 협의는 PM이 합니다.&lt;br /&gt;일반 개발자는 PM이 협의하고 AA가 설계한 시스템을 그대로 만들어냅니다.&lt;br /&gt;이런 의미에서의 개발자는 기능공에 가깝습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설계자는 AA일테고, 기능공은 개발자(코더)가 되는거죠.&lt;br /&gt;AA에게 불행한 점은 절대로 이런 순간은 오지 않는다는 것이고, AA에게 행복한 점은 이런 순간이 절대 오지 않으므로 본인의 업무를 개발자들에게 미룰 수 있다는 점이 될테죠.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DDD(Domain Driven Design - 도메인 주도 설계)를 한번 살펴봅시다.&lt;br /&gt;도메인 주도 설계에서는 업무 도메인을 나누고, 나눈 도메인을 aggregate로 묶고, 도메인 혹은 애그리거트 단위로 개발을 하는 것을 중요하게 여깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;업무 도메인&quot;은 &quot;현장의 업무&quot;를 반영해야 하고, 적어도 작은 단위의 개발, 즉 &quot;도메인&quot;은 현업과 완벽하게 일치하는 것을 최대한 지&lt;b&gt;향&lt;/b&gt;한다는 거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 단위의 완벽한 시스템을 만들 수는 없으니 작은 단위의 시스템이라도 완벽하게 만들고 서로 끼워넣자..라는 것이 DDD의 핵심입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데.. 작은 단위의 시스템이라고 해서 완벽 같은 게 가능할까요?&lt;br /&gt;물론 비행기를 만드는 일보다는 종이컵을 만들어내는 일이 더 쉬울수는 있습니다만, 그렇다고 종이컵을 만드는 과정이 더 완벽하리라는 보장이 어디 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오해하지 마세요. 저는 DDD가 나쁘다고 말하는 것이 아닙니다.&lt;br /&gt;DDD는 굉장히 현명한 접근이고, 최근에 MSA의 추세와 맞물려서 엄청나게 각광받고 있습니다. 작은 도메인들을 작은 서비스로 만들고 서비스들끼리의 연결을 통해 큰 서비스를 만들어나간다는 거죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지 단점은, 사실 단일 개발은 그다지 어려울 게 없다는 점입니다. 시스템을 만들 때 어려운 점은 대부분 두가지 이상의 복합 개념이 섞이는 시점에 등장하는데, 아직 여기에 대한 명쾌한 해법은 없네요.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 저는 처음부터 &lt;b&gt;DDD&lt;/b&gt;에 따라 업무 도메인을 &lt;b&gt;나누지 말고&lt;/b&gt;, &lt;b&gt;BBOM&lt;/b&gt;에 따라 일단 동작을 구현한 다음, 업무 도메인을 분리하는 리팩토링을 하는 것이 더 좋다고 생각합니다.&lt;br /&gt;일단 동작이 구현된 상태에서는 업무 도메인이 더 명확하게 보이고, 프로덕트의 출시일이 밀릴 이유도 없으며 사용자의 반응에 따라 쓸모없는 업무 도메인이 도출될 가능성이 높기 때문이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 &lt;s&gt;현실은 시궁창이기 때문에&lt;/s&gt; BBOM으로 일단 만들어놓고 나면 더이상 도메인을 분리할 여유가 없는 경우가 다반사이기는 합니다만.. 이부분은 각 회사의 분위기나 상황에 따라 다르기 때문에 열심히 경영진을 설득하라고밖에 말씀을 못드리겠네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;성장하는 개발자가 되고 싶다면 리팩토링은 꿈도 꾸지 말라는 회사는 가능한 빨리 도망치세요.&lt;/s&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>기술 이야기</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/53</guid>
      <comments>https://koeunyeon.tistory.com/entry/%ED%81%B0-%EC%A7%84%ED%9D%99-%EA%B3%B5BBOM-%EB%B0%A9%EC%8B%9D%EA%B3%BC-DDD#entry53comment</comments>
      <pubDate>Thu, 2 Apr 2026 11:12:26 +0900</pubDate>
    </item>
    <item>
      <title>강제 MSA 후기</title>
      <link>https://koeunyeon.tistory.com/entry/%EA%B0%95%EC%A0%9C-MSA-%ED%9B%84%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 &lt;span&gt;2021년 10월 29일&lt;/span&gt; 제 벨로그 &lt;a href=&quot;https://velog.io/@koeunyeon/%EA%B0%95%EC%A0%9C-MSA-%ED%9B%84%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@koeunyeon/%EA%B0%95%EC%A0%9C-MSA-%ED%9B%84%EA%B8%B0&lt;/a&gt; &amp;nbsp;에 썼던 글을 티스토리로 옮긴 것입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h1 id=&quot;근황&quot;&gt;근황&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇달 전 새로운 회사로 이직을 했습니다. (그래서 몇달동안은 &lt;s&gt;눈치보느라&lt;/s&gt; 적응하느라 글을 못 썼어요.)&lt;br /&gt;작은 스타트업이고, 제가 할 수 있는 일이 많을 것 같아서 (&lt;s&gt;그리고 제 마음대로 할 수 있을 것 같아서&lt;/s&gt;) 여러 회사 중 현재 회사를 선택했죠.&lt;br /&gt;결론적으로 후회하지는 않습니다만, 아쉬운 점이 몇 가지 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 회사는 회사 크기에 비해 업력이 짧지는 않습니다. 보통 스타트업이라고 생각하면 창업한 지 1-2년 내의 회사를 떠올리는 경우가 많은데, 그것보다는 조금 오래되었어요.&lt;br /&gt;그러다보니 많은 개발자가 거쳐갔고, 개발자의 흔적들이 여러 군데에 남아있습니다.&lt;br /&gt;이런 건 어디서든 볼 수 있는 현상이기 때문에 그런가보다 하고 받아들일 수 있습니다.&lt;/p&gt;
&lt;h1 id=&quot;백엔드의-구성&quot;&gt;백엔드의 구성&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는, &lt;b&gt;각 시스템이 각각 다른 언어와 프레임워크로 작성되어 있다&lt;/b&gt;는 거에요.&lt;br /&gt;현재 저희 회사 백엔드 기술 스택은 대충 다음과 같이 이루어져 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 - 스프링부트&lt;/li&gt;
&lt;li&gt;파이썬 - flask&lt;/li&gt;
&lt;li&gt;파이썬 - AWS 람다&lt;/li&gt;
&lt;li&gt;파이썬 - vanilla python&lt;/li&gt;
&lt;li&gt;노드JS - express&lt;/li&gt;
&lt;li&gt;php - 코드이그나이터3&lt;/li&gt;
&lt;li&gt;php - vanilla php&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이걸 저 혼자 다 관리하고 개발한다는 것이 아이러니..)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;겉보기에는 단순한 편에 속하는 제품을 만들고 있기 때문에, 도대체 뭐가 이렇게 많은가 싶었죠.&lt;br /&gt;단순히 여러 언어로 된 시스템이 많은 거면 그럴수도 있겠구나.. 싶겠지만, 이 시스템들은 서로 연결되어 있습니다.&lt;br /&gt;단순히 데이터베이스를 공유하는 것이 아니라 &quot;A 시스템에서 B시스템의 API를 호출하고, 다시 C를 호출한 다음, C가 A의 다른 API를 호출하고 그 다른 API는 다시 B의 ...&quot; 이런 식으로 되어 있습니다.&lt;br /&gt;그래서 &lt;b&gt;전체를 다 알지 못하면 아무것도 고칠 수가 없어요.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약에 모놀리딕 아키텍쳐로 구성되어 있다면 단순히 F3 키를 눌러서 메소드가 어떻게 구성되어 있는지 확인할 수 있는 것도, 뭔가를 찾기 위해서 &lt;b&gt;&quot;다른 프로젝트를 열고, API 엔드포인트를 확인하고, 그제서야 내용이 어떻게 구성되어 있는지 확인&quot;&lt;/b&gt; 하는 과정을 &lt;b&gt;여러 번&lt;/b&gt; 거쳐야지만 간신히 전체를 끼워맞출 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇습니다. 사실 이런 구성은 Micro Service Architecture에서 지향하는 시스템은 분산되어 있지만 전체는 하나의 구성처럼 움직이는 구조가 아니라, 그저 여러 시스템이 제 멋대로 난립되어 있는 형태에 가까워요.&lt;br /&gt;그래서 저는 저희 회사 시스템을 Micro Service Architecture가 아니라 &lt;b&gt;Mad&lt;/b&gt; Service Architecture 라고 멋대로 개명해 부르고 있습니다.&lt;/p&gt;
&lt;h1 id=&quot;추가적인-이슈&quot;&gt;추가적인 이슈&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 언어를 오가다보면 문법이나 라이브러리의 사용법이 다르기 때문에 &quot;문제에 집중하는 것이 아니라 코드를 해석하는 데 집중&quot;하게 되요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설상가상으로 이 회사를 거쳐갔던 수많은 개발자들도 저처럼 &quot;내 마음대로 할 수 있을 꺼야&quot;라는 개발자의 로망을 맘껏 실현시키신 분들이 많아서.. 도대체 왜 이런식으로 구성해 놓았는지 잘 이해가 안가는 경우도 좀 있고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신기술을 도입하고 이것 저것 해 보고 복잡함에 압도되어 퇴사하고, 다음 사람은 이미 복잡한 시스템 위에 또 새로운 복잡함을 추가하고..의 반복이었을 것으로 예상됩니다.&lt;/p&gt;
&lt;h2 id=&quot;깨달은-점&quot; data-ke-size=&quot;size26&quot;&gt;깨달은 점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;스타트업은 헬이야! &amp;lt;- 아닙니다.&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실은 저도 MSA에 로망이 있었어요.&lt;br /&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=YR_bZbQN79A&quot;&gt;쿠팡의 MSA 사례를 유튜브에서 보면서&lt;/a&gt; 이거 잘 사용하면 멋지겠는데? 라는 생각도 많이 했었고, &lt;a href=&quot;http://www.yes24.com/Product/Goods/95593443?OzSrank=2&quot;&gt;스프링으로 하는 마이크로서비스 구축&lt;/a&gt; 같은 책을 보면서 &quot;&lt;s&gt;뭐라고 하는지는 모르겠지만&lt;/s&gt; 멋진걸?&quot; 이라는 환상을 품기도 했었으니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MSA 자체가 나쁜 것은 아닙니다. 분명히 넷플릭스 같은 시스템을 만들때는 MSA가 아니라면 빌드하다가 밤을 새는 일도 허다할 테니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 만약 MSA를 도입하려면, &lt;b&gt;전체 아키텍쳐를 잘 꿰고 있는 사람, 문서, 혹은 시스템이 반드시 필요할 것&lt;/b&gt; 같습니다. 그저 개발을 잘하는 사람 말고, 비즈니스와 개별 시스템의 연결고리를 잘 알고 있는 사람이요.&lt;br /&gt;이 사람이 퇴사한다면 이 회사도 퇴출이야! 정도의 사람이 반드시 필요하다는 생각이 들었어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;넌 제대로 된 MSA를 경험해 보지 못했어!&quot; 라고 하신다면 할 말은 없습니다. 오히려 &quot;도대체 된 MSA가 뭔데?&quot; 라고 물어보는 방법밖에요. Spring Cloud를 도입하신 분들은 이런 복잡한 문제가 없는지도 궁금합니다.&lt;br /&gt;게다가 뭔가 오류가 났을 때 도대체 디버깅은 어떻게 하는지 (API를 하나씩 따라가보는 방법밖에 없는지), 간단한 기능 하나를 도입하려고 했을 때 서버 종단간의 아키텍쳐까지 고려서 개발을 하시는지도 궁금하고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 지금 사실 Micro도 아닌, Mini 정도 되는 아키텍쳐의 구성인데도 복잡함에 압도되고 있어요.&lt;br /&gt;저도 개발 경력이 10년이 넘었기 때문에 왠만한 구조나 크기에는 놀라지 않습니다만, 이번 회사는 코드를 볼 때마다 매일 놀라고 있습니다.&lt;/p&gt;
&lt;h1 id=&quot;지금-다시-구성하라면&quot;&gt;지금 다시 구성하라면&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;시간을 줄 테니 회사의 모든 아키텍쳐를 재구성해주시겠어요?&quot; 라고 제안해 주신다면 저는 지체없이 모놀리딕 아키텍쳐를 선택할 겁니다.&lt;br /&gt;&lt;b&gt;스타트업에 있어서는&lt;/b&gt; 무한대의 확장을 위한 MSA보다 특별한 고민 없이 일단 만들고 배포할 수 있는 속도가 더 중요하다고 생각하기 때문이에요.&lt;br /&gt;백엔드 개발자는 달랑 한명인데 도대체 왜 서비스를 분산해야 하는지에 대한 답을 아직도 찾지 못했기 때문이기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 좋아하는 개발자 중 하나인 DHH의 &lt;a href=&quot;https://m.signalvnoise.com/the-majestic-monolith/&quot;&gt;The Majestic Monolith&lt;/a&gt; 를 보면 , Basecamp 정도되는 시스템도 모놀리딕으로 잘 실행됩니다.&lt;br /&gt;물론 이건 ROR이 훌륭해서라기보다는 Basecamp가 37signals일 때부터 CTO였던 DHH의 힘이 더 크다고 생각하지만, 다른 스타트업이라고 해서 DHH처럼 기술의 중심을 잡아줄 수 있는 CTO가 없는 것은 아니니까요.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>기술 이야기</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/52</guid>
      <comments>https://koeunyeon.tistory.com/entry/%EA%B0%95%EC%A0%9C-MSA-%ED%9B%84%EA%B8%B0#entry52comment</comments>
      <pubDate>Tue, 31 Mar 2026 11:10:58 +0900</pubDate>
    </item>
    <item>
      <title>석기시대 개발</title>
      <link>https://koeunyeon.tistory.com/entry/%EC%84%9D%EA%B8%B0%EC%8B%9C%EB%8C%80-%EA%B0%9C%EB%B0%9C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 농담인 줄 알았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;인터넷 안 돼요.&quot;&lt;br /&gt;고객사 담당자가 말했습니다. 개발 환경을 세팅하러 온 첫날이었습니다.&lt;br /&gt;&quot;보안 때문에 외부망 차단되어 있어요. 필요한 거 있으면 반입 신청하세요.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2025년에 인터넷 없이 개발하라고?&lt;/p&gt;
&lt;h2 id=&quot;반입-절차&quot; data-ke-size=&quot;size26&quot;&gt;반입 절차&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라이브러리 하나 받는 과정이 이랬습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 반입 신청서를 씁니다. 어떤 파일인지, 왜 필요한지, 출처가 어디인지. 양식에 맞춰 작성합니다. 팀장 결재, 고객사 담당자 결재, 보안팀 검토. 3단계입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안팀에서 파일을 검사합니다. 바이러스 검사, 악성코드 검사. 며칠 걸립니다. 통과하면 USB에 담아서 전달받습니다. 그걸 폐쇄망 서버에 옮깁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;maven 패키지 하나 받는 데 일주일.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 답답해 죽는 줄 알았습니다.&lt;/p&gt;
&lt;h2 id=&quot;첫-번째-에러&quot; data-ke-size=&quot;size26&quot;&gt;첫 번째 에러&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 시작한 지 이틀째, 에러가 터졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택트레이스를 보니 본 적 없는 메시지였습니다. 반사적으로 브라우저를 열었습니다. 구글에 에러 메시지를 붙여넣으려고 했습니다. 안 돼죠. 인터넷이 안되니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택오버플로우도 없습니다. 공식 문서도 없습니다. 깃허브 이슈도 못 봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면 앞에서 멍해졌습니다. 뭘 어떻게 해야 하지?&lt;/p&gt;
&lt;h2 id=&quot;석기시대-개발&quot; data-ke-size=&quot;size26&quot;&gt;석기시대 개발&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 예전 방식으로 돌아갔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 메시지를 읽었습니다. 진짜로 읽었습니다. &lt;s&gt;아오 귀찮...&lt;/s&gt;&lt;br /&gt;예전에는 에러 나면 복붙해서 검색했습니다. 메시지 자체를 읽은 적이 별로 없었습니다. 이번에는 읽을 수밖에 없었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 따라갔습니다. 에러가 난 라인부터 역추적했습니다. 호출 스택을 하나씩 올라갔습니다. 어디서 뭐가 잘못됐는지 직접 찾았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서를 미리 받아뒀습니다. PDF로. 오프라인에서 읽었습니다. 예전에는 필요할 때 검색했는데, 이제는 미리 읽어둬야 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;느렸습니다. 답답했습니다. 하지만 해결은 됐습니다.&lt;/p&gt;
&lt;h2 id=&quot;이상한-깨달음&quot; data-ke-size=&quot;size26&quot;&gt;이상한 깨달음&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몇 주가 지나니까 이상한 일이 생겼습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 해결 속도가 빨라졌습니다. 처음에는 하루 종일 걸렸는데, 나중에는 몇 시간이면 됐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유를 생각해 봅니다.&lt;br /&gt;예전에는 에러가 나면 바로 검색했습니다.&lt;br /&gt;스택오버플로우에서 비슷한 질문을 찾은 뒤 답변을 복붙했습니다. 되면 끝. 안 되면 다른 답변을 시도했죠.&lt;br /&gt;왜 되는지, 왜 안 되는지 깊이 생각하지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폐쇄망에서는 그게 안 됐습니다. 직접 이해해야 했습니다. 에러 메시지가 뭘 말하는지, 코드가 어떻게 흘러가는지, 어디서 뭐가 틀어졌는지. 시간은 더 걸렸지만, 이해는 더 깊어졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음에 비슷한 에러가 나면 검색 없이도 해결할 수 있었습니다. 이미 이해하고 있으니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 시대에도 마찬가지입니다. AI가 자동으로 오류를 수정까지 해 준다고 해도, 결국 이 코드를 이해해야 하는 건 개발자죠.&lt;/p&gt;
&lt;h2 id=&quot;한계&quot; data-ke-size=&quot;size26&quot;&gt;한계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미화하려는 건 아닙니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진짜 모르는 건 못 합니다. 처음 보는 프레임워크, 경험 없는 도메인. 폐쇄망에서는 학습 곡선이 가파릅니다. 삽질 시간이 배로 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최신 정보를 못 얻습니다. 보안 취약점이 발표돼도 모릅니다. 새 버전이 나와도 모릅니다. 세상과 단절된 채 개발합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;협업도 어렵습니다. 슬랙이 안 됩니다. 깃허브가 안 됩니다. 파일 공유하려면 공유 폴더에 올린 후 승인을 받고 다시 내려받아야 합니다.2025년에.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폐쇄망 개발이 좋다는 게 아닙니다. 그냥 생존하다 보니 부산물이 생긴 겁니다.&lt;/p&gt;
&lt;h2 id=&quot;왜-폐쇄망인가&quot; data-ke-size=&quot;size26&quot;&gt;왜 폐쇄망인가&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 이해가 안 됐습니다. 왜 이렇게까지 하나.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나중에 알았습니다.&lt;br /&gt;금융권, 공공기관. 데이터가 민감합니다. 주민번호, 계좌번호, 의료정보. 유출되면 사고입니다. 뉴스에 나옵니다. 누군가 책임을 집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부망이 열려 있으면 위험합니다. 악성코드가 들어올 수 있습니다. 데이터가 나갈 수 있습니다. 완벽한 보안은 없지만, 폐쇄망은 최소한의 방어선입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 사건 사고가 몇 번 있다 보니 법적으로 강제하는 부분도 있습니다. 예외 케이스를 만들어 두긴 했지만, 법이라는 게 늘 그렇듯 코에 걸면 코걸이, 귀에 걸면 귀걸이라 큰 의미는 없으므로....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불편하지만 이유가 있습니다. 그 이유를 이해하니까 덜 답답했습니다&lt;s&gt;였으면 좋겠지만&lt;/s&gt; 여전히 답답하긴 합니다.&lt;/p&gt;
&lt;h2 id=&quot;적응&quot; data-ke-size=&quot;size26&quot;&gt;적응&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6개월이 지나니까 적응됐습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 시작 전에 필요한 라이브러리를 다 정리합니다. 한꺼번에 반입 신청합니다. 개발 시작 전에 다 받아둡니다. 중간에 추가로 필요하면 일정에 일주일을 더합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오프라인 문서를 모아둡니다. 자주 쓰는 프레임워크 공식 문서, 에러 해결 사례 모음, 제가 겪은 이슈 정리. 나만의 오프라인 스택오버플로우입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색 없이 문제 푸는 습관이 생겼습니다.&lt;br /&gt;일단 직접 해봅니다. 안 되면 코드를 읽습니다. 그래도 안 되면 동료에게 묻습니다. 검색은 선택지에 없으니까요.&lt;/p&gt;
&lt;h2 id=&quot;다시-외부망으로&quot; data-ke-size=&quot;size26&quot;&gt;다시 외부망으로&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 프로젝트가 끝나고 외부망 되는 곳으로 갔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러가 났습니다. 반사적으로 코드를 읽기 시작했습니다. 읽다가 생각났습니다. 아, 검색하면 되지.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색했습니다. 스택오버플로우 답변을 찾았습니다. 복붙했습니다. 되더라고요. &lt;s&gt;우왕&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근데 뭔가 찝찝했습니다. 왜 되는지 모르고 넘어가는 게 좀 그렇더라고요. 예전에는 그게 당연했는데. 폐쇄망에서 6개월 보내고 나니까 찜찜했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때 알았습니다. 폐쇄망이 저한테 뭔가를 가르친 거구나.&lt;/p&gt;
&lt;h2 id=&quot;질문-하나&quot; data-ke-size=&quot;size26&quot;&gt;질문 하나&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색 없이 에러를 해결해본 적이 언제인가요?&lt;br /&gt;에러 메시지를 처음부터 끝까지 읽어본 적이 언제인가요?&lt;br /&gt;코드를 따라가면서 흐름을 이해해본 적이 언제인가요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;폐쇄망이 아니어도 해볼 수 있는 일입니다. 한 번쯤 시도해보시면 좋겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 저도 외부망에서는 바로 검색합니다. 그게 빠르니까요. 효율적으로 일해야죠. 물론 아주 가끔은 기본기를 쌓는다는 면이 아쉽지만요.&lt;/p&gt;</description>
      <category>프리랜서 개발자의 삶</category>
      <author>고은연</author>
      <guid isPermaLink="true">https://koeunyeon.tistory.com/70</guid>
      <comments>https://koeunyeon.tistory.com/entry/%EC%84%9D%EA%B8%B0%EC%8B%9C%EB%8C%80-%EA%B0%9C%EB%B0%9C#entry70comment</comments>
      <pubDate>Mon, 30 Mar 2026 16:47:38 +0900</pubDate>
    </item>
  </channel>
</rss>