<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Architecture on Kelly Dev</title><link>https://kelly-chui.github.io/tags/architecture/</link><description>Recent content in Architecture on Kelly Dev</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Mon, 17 Aug 2026 23:30:00 +0900</lastBuildDate><atom:link href="https://kelly-chui.github.io/tags/architecture/index.xml" rel="self" type="application/rss+xml"/><item><title>TIL. Aug 17, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-17/</link><pubDate>Mon, 17 Aug 2026 23:30:00 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-17/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PS
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-1563-stone-game-v/"&gt;LeetCode 1563. Stone Game V&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;WWDC
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/wwdc-swift-concurrency-explore-structured-concurrency-in-swift-2/"&gt;Swift Concurrency. Explore Structured Concurrency in Swift (2) - WWDC21&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;마이그레이션
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/cs-algorithm-kadanes-algorithm/"&gt;Algorithm. Kadane&amp;rsquo;s Algorithm&lt;/a&gt; 마이그레이션&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/mibangmurok-dev-log-colorpicker/"&gt;미방문록. 대표 색상 추출 Picker 만들기&lt;/a&gt; 마이그레이션&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="unstructured-task"&gt;Unstructured Task&lt;/h3&gt;
&lt;p&gt;WWDC21 Explore Structured Concurrency in Swift 세션을 정리를 마무리했다.&lt;/p&gt;
&lt;p&gt;1편과 다르게 구조화된 task tree에 속하지 않는 unstructured task와 detached task를 정리했다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Task { ... }&lt;/code&gt;로 만든 unstructured task는 생성한 scope가 끝나도 계속 실행될 수 있다. 생성 지점의 actor, priority, task-local value를 상속한다.&lt;/p&gt;</description></item><item><title>StackDay. UseCase와 Entity는 각각 어디까지 책임져야 할까</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-usecase-entity-responsibilities/</link><pubDate>Fri, 14 Aug 2026 16:31:52 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-usecase-entity-responsibilities/</guid><description>&lt;p&gt;&lt;code&gt;CreateHabitUseCase&lt;/code&gt;를 시작으로 여러 유즈케이스를 구현하면서, 도메인 규칙을 어디에 두어야 할지 계속 고민하게 됐다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Habit&lt;/code&gt;을 생성할 때 이름의 유효성을 누가 검증해야 하는지, &lt;code&gt;Completion&lt;/code&gt;을 남길 때 해당 날짜에 기록할 수 있는지는 누가 판단해야 하는지처럼 비슷한 문제가 반복해서 나타났다.&lt;/p&gt;
&lt;p&gt;처음에는 유즈케이스가 사용자의 작업을 처리하니 이런 검증도 함께 담당하면 된다고 생각할 수 있었다. 하지만 구현을 진행할수록 엔티티가 스스로 보장해야 하는 규칙과 유즈케이스 작업의 흐름을 위해 판단해야 하는 규칙을 구분할 필요가 있었다.&lt;/p&gt;
&lt;p&gt;이 포스트에서는 &lt;code&gt;Habit&lt;/code&gt;의 생성과 &lt;code&gt;Completion&lt;/code&gt; 기록을 중심으로 어떤 고민을 했는지와 어떻게 해결했는지를 정리한다.&lt;/p&gt;</description></item><item><title>StackDay. Repository의 save를 insert와 update로 나누기</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-repository-contracts/</link><pubDate>Fri, 14 Aug 2026 14:15:52 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-repository-contracts/</guid><description>&lt;p&gt;유즈케이스를 구현하면서 &lt;code&gt;Habit&lt;/code&gt;과 &lt;code&gt;Completion&lt;/code&gt;을 저장할 Repository 계약을 좀 정리했다.&lt;/p&gt;
&lt;p&gt;처음에는 create와 update 둘 다 &lt;code&gt;save&lt;/code&gt; 하나로 저장하면 간단해 보였지만, 두 기능이 기대하는 실패 조건이 서로 다르다는 점에서 계약을 나눌 필요가 있었다.&lt;/p&gt;
&lt;h2 id="save는-어떤-동작인가"&gt;save는 어떤 동작인가&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;save&lt;/code&gt;를 upsert로 구현하면 호출하는 쪽은 편하다. ID가 없으면 삽입하고, 이미 있으면 갱신하면 된다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;HabitRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;habit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Habit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="kr"&gt;throws&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;문제는 이 동작이 실패해야 하는 상황까지 조용히 성공으로 바꾼다는 점이다.&lt;/p&gt;
&lt;p&gt;(물론 UUID라 현실적으로 겹칠 일은 없지만) &lt;code&gt;Habit&lt;/code&gt;을 생성하는 작업은 같은 ID가 이미 있으면 실패해야 하고, 보관처럼 기존 &lt;code&gt;Habit&lt;/code&gt;을 바꾸는 작업은 대상이 없으면 실패해야 한다.&lt;/p&gt;</description></item></channel></rss>