<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>elile-e.log</title>
        <link>https://velog.io/</link>
        <description>애플을 좋아한다. 그래서 iOS 개발을 한다. @Kurly</description>
        <lastBuildDate>Sat, 30 Oct 2021 05:42:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>elile-e.log</title>
            <url>https://images.velog.io/images/elile-e/profile/42fd405c-297b-40fc-9f70-348f46b6e2a5/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. elile-e.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/elile-e" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Tuist 도입하기]]></title>
            <link>https://velog.io/@elile-e/Tuist-%EB%8F%84%EC%9E%85%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@elile-e/Tuist-%EB%8F%84%EC%9E%85%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 30 Oct 2021 05:42:02 GMT</pubDate>
            <description><![CDATA[<p>iOS Project를 함께 협업한다면 merge시 늘 우리를 괴롭히는 프로젝트 파일이 있습니다.
Project 설정 파일로 잘못 건들어 읽을 수 없다면 프로젝트가 열리지 않습니다...
(아마 어느정도 규모있게 작업하셨던 분들이라면 많이 공감하실 수 있을 것 같아요)</p>
<p>당연히 merge, rebase 상황에서 굉장히 위험한 작업들을 해야되죠.
<img src="https://images.velog.io/images/elile-e/post/a62dbab4-8881-436a-a069-094bbac89651/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-10-30%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.33.08.png" alt=""></p>
<p>컬리에서는 iOS 개발자들이 늘어나고 있습니다.
새로운 iOS 개발자가 계속해서 합류하면서 자연스럽게 branch가 늘어나고 merge 될 때마다 이 .pbxproj 파일이 점점 더 우리를 괴롭히는 것은 당연한 미래라고 느껴졌습니다.</p>
<p>관련한 문제를 해결하기 위해서 솔루션을 찾아야만 했습니다.
당연히 우리의 고민을 먼저 마주친 조직들이 있었습니다.</p>
<p><a href="https://github.com/yonaskolb/XcodeGen">XcodeGen</a>, <a href="https://tuist.io/">Tuist</a>
위의 해법들이 가장 많이 찾게되는 방법들이라고 생각되었습니다.
Xcode project를 관리하는 도구들이죠.
그 중 우리의 main 언어인 Swift로 관리되어질 수 있는 Tuist를 선택할 수 있었습니다.
(Ruby로 관리 되는 Xcode</p>
<p>Tuist 2.x 버전을 기준으로 작성이 되었습니다.
자세한 내용은 <a href="https://docs.tuist.io/tutorial/get-started/">Official document</a>를 참조하세요.</p>
<h3 id="1-tuist-설치">1. Tuist 설치</h3>
<pre><code>curl -Ls https://install.tuist.io | bash</code></pre><h3 id="2-tuist-init">2. Tuist init</h3>
<pre><code>tuist init --platform ios</code></pre><p>위의 설치와 init은 한번만 해주시면 됩니다.</p>
<p>아래부터는 앞으로 계속해서 사용하게 될 명령어 입니다.</p>
<h3 id="3-tuist-edit">3. Tuist edit</h3>
<p>위의 명령어로 프로젝트를 수정할 Manifests 프로젝트가 실행됩니다.</p>
<pre><code>tuist edit</code></pre><h3 id="4-project-구성">4. Project 구성</h3>
<p>각각의 프로젝트의 세팅값들을 찾아서 구성합니다.
여러분들이 여태 project 창에서 수정하시거나 변경했던 내용들을 모두 반영해주셔야 합니다.</p>
<pre><code class="language-Swift">let baseSettings: [String: SettingValue] = [
  &quot;ENABLE_BITCODE&quot;: &quot;NO&quot;,
  &quot;SWIFT_OBJC_BRIDGING_HEADER&quot;: &quot;Bridging-Header.h&quot;,
  &quot;CURRENT_PROJECT_VERSION&quot;: &quot;100&quot;,
  &quot;MARKETING_VERSION&quot;: &quot;1.0.0&quot;,
  &quot;CODE_SIGN_ENTITLEMENTS&quot;: &quot;-&quot;,
  &quot;CODE_SIGN_IDENTITY&quot;: &quot;-&quot;,
  &quot;DEVELOPMENT_TEAM&quot;: &quot;-&quot;
]

let releaseSetting: [String: SettingValue] =  [
  &quot;PROVISIONING_PROFILE_SPECIFIER&quot;: &quot;&quot;,
  &quot;CODE_SIGN_STYLE&quot;: &quot;Manual&quot;
]

let adhocSetting: [String: SettingValue] =  [
  &quot;PROVISIONING_PROFILE_SPECIFIER&quot;: &quot;&quot;,
  &quot;CODE_SIGN_STYLE&quot;: &quot;Manual&quot;
]

let settings = Settings.settings(
  base: baseSettings,
  configurations: [
    .release(
      name: &quot;Release&quot;,
      settings: releaseSetting
    ),
    .release(
      name: &quot;AdHoc&quot;,
      settings: adhocSetting
    )
  ],
  defaultSettings: .recommended
)

let newProject = Target(
  name: &quot;-&quot;,
  platform: .iOS,
  product: .app,
  bundleId: &quot;-&quot;,
  deploymentTarget: .iOS(
    targetVersion: &quot;-&quot;,
    devices: [.iphone, .ipad]
  ),
  infoPlist: &quot;Info.plist&quot;,
  sources: [
    &quot;ProjectRoot/**&quot;
  ],
  resources: [&quot;ProjectRoot/Resource/**&quot;],
  entitlements: &quot;ProjectRoot/Project.entitlements&quot;,
  scripts: scripts,
  dependencies: [
    .sdk(name: &quot;AdSupport.framework&quot;)
    .target(name: &quot;SomeFrameWorkProject&quot;)
  ],
  settings: settings
)

let projectSettings = Settings.settings(
  configurations: [
    .debug(name: &quot;Debug&quot;)
  ]
)

let schemes = [
  Scheme(
    name: &quot;-&quot;,
    shared: true,
    buildAction: .buildAction(targets: [&quot;-&quot;]),
    runAction: .runAction(configuration: &quot;Debug&quot;),
    archiveAction: .archiveAction(configuration: &quot;Release&quot;),
    profileAction: .profileAction(configuration: &quot;Debug&quot;),
    analyzeAction: .analyzeAction(configuration: &quot;Debug&quot;)
  )
]

let project = Project(
  name: &quot;ProjectName&quot;,
  organizationName: &quot;com.project&quot;,
  settings: projectSettings,
  targets: [
    newProject
  ],
  schemes: schemes,
  additionalFiles: [
  ]
)</code></pre>
<h3 id="5-tuist-generate">5. Tuist generate</h3>
<pre><code>tuist generate</code></pre><p>위의 명령으로 프로젝트 파일을 생성해주셔야합니다.</p>
<h3 id="6-gitignore">6. Gitignore</h3>
<p>*.xcodeproj
*.xcworkspace</p>
<p>더 이상 git으로 트래킹해주지 않도록 합니다.</p>
<h3 id="7-각종-환경-문제들을-해결">7. 각종 환경 문제들을 해결</h3>
<h4 id="a-cocoapods의-미지원">a. Cocoapods의 미지원</h4>
<p><a href="https://github.com/tuist/tuist/releases/tag/2.0.0">https://github.com/tuist/tuist/releases/tag/2.0.0</a>
위의 배포사항으로 Cocoapods가 더 이상지원되지 않았습니다.
항상 tuist generate 이후에 bundle exec pod install을 해주도록 했습니다.
아래의 script를 생성해두고 계속 사용하도록 합시다.</p>
<pre><code>tuist generate &amp;&amp; bundle exec pod install</code></pre><h4 id="b-bitrise-대응">b. Bitrise 대응</h4>
<p>저희는 CI/CD로 Bitrise를 사용하게 됩니다. 
당연히 가상빌드환경에서도 tuist를 설치 및 생성해주는 script를 추가해주어야합니다.</p>
<h4 id="c-rswift-대응">c. R.swift 대응</h4>
<p>리소스 파일을 관리하는 도구로 R.swift를 해줍니다. 그러나 R.swift는 변동이 매번 발생하는 파일이므로 .gitignore처리가 되어있습니다. 
그러므로 최초 빌드시 tuist project에는 존재하지 않습니다. 매번 tuist generate 전 touch R.generated.swift 파일을 추가해주어야합니다.</p>
<h4 id="d-기타-옵션-제거">d. 기타 옵션 제거</h4>
<p>Tuist에서는 그 외의 리소스 관리등의 기능들을 제공합니다.
사용하고 사용할 Tuist에 대한 세팅들을 아래 Config.swift를 통해서 관리해줄 수 있습니다.
<a href="https://docs.tuist.io/manifests/config">https://docs.tuist.io/manifests/config</a></p>
<p>조금의 작업과 수고스러움은 생겼지만 이렇게 해주니 앞으로의 프로젝트 파일 추가, 삭제 등의 과정에서 더 이상 conflict의 과정을 마주치지 않을 수 있습니다.
또 앞으로 모듈레벨의 분리의 관리에서도 더욱 편리하게 프로젝트를 관리할 수 있을 것으로도 기대하고 있습니다.</p>
<p>읽어주셔서 감사합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 - 계층구조]]></title>
            <link>https://velog.io/@elile-e/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B3%84%EC%B8%B5%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@elile-e/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B3%84%EC%B8%B5%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Mon, 17 May 2021 08:02:24 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>사실 클라 개발자다 보니
네트워크 자체에 대한 학습을 넓게 해본 적은 없었다. 
(CS 자체도 마찬가지이니)</p>
<p>관련해서 내용자체를 넓게 학습해보려 한다.</p>
<h2 id="protocol에-대하여">Protocol에 대하여</h2>
<p>일단 네트워크라는 것은 통신으로 이루어집니다.
통신시에 서로 약속한 포맷에 맞추어 통신을 하게되는데,
그런 약속들을 프로토콜이라고 합니다.</p>
<p>웹을 주고받는 것은 HTT<strong>P</strong>
이메일을 주고받는 것은 SMT<strong>P</strong>(발신), POP3(수신)
파일을 주고받는 것은 FT<strong>P</strong> (초등학교 때 한번 써본 것 같은...)
음성 주고받는거 VOI<strong>P</strong> (보이스톡)</p>
<p>뒤에 모든게 <strong>Protocol의 P</strong>이다.</p>
<h2 id="계층구조">계층구조</h2>
<p>컴퓨터와 컴퓨터가 서로 통신하기 위해서는 단 한개의 Protocol로만 이루어질 수 없다.</p>
<ol>
<li>0101 인 숫자를 보낼텐데 이건 어떤 패턴인가요?</li>
<li>IP로 목적지를 찾으면 되나요?</li>
<li>실행할 때 어떤 앱으로 실행해야하나요? (ppt, html etc..)
etc..
등과 같이 약속하고 규정해야할게 한두가지가 아니다.</li>
</ol>
<p>이런 프로토콜은 또 순차적으로 이루어져야 한다.
순차적으로 </p>
<p>보내는 컴퓨터: 데이터를 수정해서 바꾸고 보내고
받는 컴퓨터: 순차적으로 데이터를 바꿔서 데이터를 처리</p>
<p><img src="https://images.velog.io/images/elile-e/post/d0e4d1aa-da23-46c0-9e19-350eab2f6796/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-05-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.03.54.png" alt=""></p>
<p>이런 계층적인 구조가 크게 OSI 7과 TCP/IP 방식이 있다.
이것들을 각각 설명해보자.</p>
<h2 id="osi-7">OSI 7</h2>
<p>OSI 7은 위의 계층 구조를 7가지로 구성한 산업 표준 참조 모델이라고 한다.
옛날 옛적에는 IBM, Apple 이런 컴퓨터마다 각각 달랐기에 통합적으로 관리되기 위해서 이런 표준이 필요했던 것 같다.
하나하나 좀 보자.</p>
<p>모든 계층마다 데이터를 다루는 단위라는게 존재한다. 
PDU라고 하며 한 단계단계를 거쳐가며 PDU가 다음 계층을 거쳐 최하위 단계에서 Bit가 된다.</p>
<h4 id="1-물리계층-physical-layer">1. 물리계층 (Physical Layer)</h4>
<p>최하위 계층에 속하며 010101인 전기적인 신호를 전송하는 역할을 한다.
기계어를 전기적 신호로 바꿔주는 것.</p>
<p>PDU: Bit</p>
<h4 id="2-링크계층-link-layer">2. 링크계층 (Link Layer)</h4>
<p>네트워크 기기들(컴퓨터겠지) 사이의 데이터 전송을 한다.
이런 것에는 이더넷, LAN, WIFI 같은 것들이 있다. </p>
<p>PDU: Frame</p>
<h4 id="3-네트워크계층-network-layer">3. 네트워크계층 (Network Layer)</h4>
<p>데이터가 가는 경로를 설정해주는 역할을 한다. 당연히 예시로는 IP가 있겠고 해당 주소로 가는 최적의 경로로 전송한다.</p>
<p>PDU: 패킷</p>
<h4 id="4-전송계층-transport-layer">4. 전송계층 (Transport Layer)</h4>
<p>이 과정에서는 목적지까지 보내는 데이터들을 제어하고 에러를 관리한다.
보낸 데이터가 유효한지, 실패했는지, 순서가 맞는지등 신뢰성들을 관리한다.
TCP와 UDP 같은것들이 이곳에 해당한다.</p>
<p>PDU: 세그먼트</p>
<h4 id="5-세션계층session-layer">5. 세션계층(Session Layer)</h4>
<p>송수신 하는 사용자 사이에서 연결정보를 설정, 유지, 해제하는 역할을 한다.
뭐 로그인해서 보안적인 내용들과 단방향, 반이중, 전이중 방식등의 대화방식에 대한 것도 관리를 한다.</p>
<p>예시로는 SSH, TLS라는 것이 있다고 한다.</p>
<h4 id="6-표현-계층presentation-layer">6. 표현 계층(Presentation Layer)</h4>
<p>이 계층은 송수신측에서 사용하는 데이터 타입을 정한다. PNG, JPG 등등...
올바른 표현 방식으로 변환</p>
<p>프로토콜: JPG, HTML 등등</p>
<h4 id="7-응용계층-application-layer">7. 응용계층 (Application Layer)</h4>
<p>실제 우리가 사용하는 앱들과 연결해주는 프로토콜등이다.</p>
<p>메일이면 SMTP, 파일이면 FTP, 웹이면 HTTP이다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/8f8e153f-f79f-4bb9-9dd6-aa88507c72b0/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-05-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.49.50.png" alt=""></p>
<p>위처럼 Bit인 데이터를 단계단계를 거쳐 원래 유저가 사용하는 목표 데이터 형태로 만들어준다.</p>
<h2 id="tcpip">TCP/IP</h2>
<p>결국 OSI 7 Layer이다.
하지만 우리는 보통 사용하는게 TCP와 IP라는 것을 이용해 통신을 만든 것.
어떻게 보면 OSI 7에서 가장 흔히 사용하는 꿀 조합을 묶어 놓은 것 정도라고 생각을 하면 좋을 것 같다.</p>
<p>데이터의 정확성은  TCP가
목적지까지 전송하는 일은 IP로 크게 나누어 본다.</p>
<p>아래의 대칭되는 방식이므로 따로 자세하게 설명하진 않는다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/dfef9753-6065-4110-99b0-e2b864db251c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-05-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.52.45.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Reactor Kit을 이용해 모작 개발기]]></title>
            <link>https://velog.io/@elile-e/Reactor-Kit%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%B4-%EB%AA%A8%EC%9E%91-%EA%B0%9C%EB%B0%9C%EA%B8%B0</link>
            <guid>https://velog.io/@elile-e/Reactor-Kit%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%B4-%EB%AA%A8%EC%9E%91-%EA%B0%9C%EB%B0%9C%EA%B8%B0</guid>
            <pubDate>Sat, 20 Feb 2021 07:33:41 GMT</pubDate>
            <description><![CDATA[<p>그동안 입사 이후 시간이 조금 생겨 이런저런 공부를 했다.
Swift를 한번 톺아보기도 했고 클린 아키텍처를 읽어보기도 했다.</p>
<p>그를 바탕으로 회사의 몇몇기능을 따라서 구현하는 것이다.
목적은 이번 앱에서 구현한 내용과 구조를 바탕으로 현재 앱에 조금씩 이관하는 것을 목적으로 한다.</p>
<p>먼저 디자인패턴과 관련해서는 Reactor Kit을 채택했다.</p>
<p>지난 에코모드를 개편한 부분에 있어서 MVVM으로 작업을 했었는데 몇가지 아쉽고 부족한 부분이 있었다.</p>
<ol>
<li>이 부분에서 아직 내가 RxSwift에 완벽하게 적응하지 못했다는 점. </li>
<li>Status의 기본값을 위해 Relay와 Subject를 많이 사용한다는 점. (그리 권장하지 않는다고 한다. 또한 사용하면서도 이렇게 만드는게 맞는가?에 대한 고민을 했다.)</li>
<li>MVVM에 어색해 VM에 있어야하는 코드인가? V에 있어야하는 코드인가? 등을 고민했다. (역할 분담의 어색함.)</li>
</ol>
<p>이런 부분을 고민하다보니 Reactor Kit을 알게되었으며, 국내의 개발자분이 만드셨다고 한다.
아무래도 커뮤니티에서 한국어로 물어볼 수도 있기도해서 이부분이 좋았다.</p>
<p>토스, 하이퍼커넥트, 라인페이 등 많은 조직들에서 채택하기도 해서 신뢰가 가는부분도 있었다.</p>
<p>가장 중요한 점은 나처럼 Rx가 어색한 사람들, 디자인 패턴에 어색한 사람들에게 어느정도 프레임워크 수준에서의 제약이 생겨 그것대로 따라하기 쉬워 적응을 하기에 적합하다는 생각을 했다.</p>
<p><a href="https://github.com/ReactorKit/ReactorKit">Reactor Kit Git</a></p>
<p>사용한 라이브러리들은 아래와 같다.</p>
<pre><code># UI
  pod &#39;SnapKit&#39;
  pod &#39;RxKeyboard&#39;

# Networking
  pod &#39;Moya/RxSwift&#39;

# Misc.
  pod &#39;RxSwift&#39;
  pod &#39;RxCocoa&#39;
  pod &#39;RxViewController&#39;
  pod &#39;R.swift&#39;
  pod &#39;Then&#39;
  pod &#39;ReactorKit&#39;
  pod &#39;SwiftLint&#39;
  pod &#39;ReusableKit/RxSwift&#39;</code></pre><h4 id="ui">UI</h4>
<p>SnapKit으로 모두 작업을 했다. 
StoryBoard를 사용하지 않는 이유는  <a href="https://velog.io/@elile-e/Layout">해당 게시글</a>에 작성해두었다.</p>
<h4 id="networking">Networking</h4>
<p>Moya로 작업이 되었다.
좀 복잡하게 내가 Networking Manager 같은 것을 만들어도 되지 않고, enum으로 깔끔하게 인터페이스를 정의할 수 있다. </p>
<h4 id="etc">ETC</h4>
<p>lint: SwiftLint로 default option들을 따랐다. 몇몇 자동생성 파일들은 제거하고 모두 따르도록 설정을 했다.
then: UI Components 들을 선언해서 옵션들을 곧바로 설정하기에 좋다. 그외에도 여러부분에서 init 코드들을 간결하게 정의할 수 있어서 사용했다.
r.swift: 이 라이브러리에 대한 설명은 <a href="https://velog.io/@elile-e/R.Swift">요기</a>에 있다.</p>
<p>뭐 간단한 구조는 아래와 같다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/d69a9329-f101-4096-bfc1-c9074e43fec4/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-20%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%204.08.23.png" alt=""></p>
<h2 id="service-code">Service Code</h2>
<p>Reactor에서 의존하게 될 Service의 기본적인 구조는 아래와 같다. </p>
<pre><code class="language-swift">// 한번 감싸주기 위한 Protocol
protocol CartService: class {
  func getItems() -&gt; Observable&lt;[OrderProduct]&gt;
  func setItem(_ item: Product, _ count: Int) -&gt; Observable&lt;OrderProduct?&gt;
}

// Protocol의 구현부
final class CartServiceImpl: CartService {
  // MARK: Implimentaion
  func getItems() -&gt; Observable&lt;[OrderProduct]&gt; {
    return 값
  }

  func setItem(_ item: Product, _ count: Int) -&gt; Observable&lt;OrderProduct?&gt; {
      return 값
  }
}</code></pre>
<h2 id="viewcontroller">ViewController</h2>
<pre><code class="language-swift">// BaseVC와 ReactorKit의 View를 따름
final class MainVC: BaseVC, View {
    // Mark: UI Components
    private let testView = UIView().then {
        $0.backgroundColor = .black
    }

    // MARK: LifeCycle
    override func viewDidLoad() {
        super.viewDidLoad()
        self.addView()
    }

    // MARK: Layout
    override func makeConstraints() {
        super.makeConstraints()

        //SnapKit을 이용해 Layout Code
    }

    private func addView() {
        //view들을 addSubView 해주는 부분
    }

    // MARK: Binding
    func bind(reactor: MainReactor) {
        // Action 유저의 행동에 의해 발생하는 코드

        // State의 값들을 bind해주는 코드
    }
}</code></pre>
<h2 id="reactor">Reactor</h2>
<pre><code class="language-swift">class MainReactor: Reactor {
  // 유저 액션을 정의
  enum Action {
    case viewWillAppear
  }

  // state를 변경되는 것을 정의
  enum Mutation {
    case setFollowing(Bool)
  }

  // View에서 보여줄 데이터들을 정의
  struct State {
    var isFollowing: Bool = false
  }

  let initialState: State = State()

  func mutate(action: Action) -&gt; Observable&lt;Mutation&gt; {
      switch action {
    case .viewWillAppear
    }
  }

  func reduce(state: State, mutation: Mutation) -&gt; State {
      var state = state
    switch mutation {

    }

    return state
  }
}</code></pre>
<p>크게 소개하면 위의 내용들로 코드들을 구성했다.</p>
<h2 id="평가">평가</h2>
<p>긍정적인 측면</p>
<ol>
<li>확실히 구조나 코드의 목적의 분리가 확실히 잘되었다.</li>
<li>굉장히 심플하다. 유저 액션 &gt; 받고 서비스나 데이터 생성 &gt; 데이터를 반영 &gt; 뷰에 바인딩 단방향으로 굉장히 쉬워졌다.</li>
<li>Rx를 아직 접하지 않은 나에게도 Rx를 어느정도 잘 사용해볼 수 있었다.</li>
</ol>
<p>아쉬운 측면</p>
<ol>
<li>여전히 아직 Rx가 자유자제는 아니라는 점</li>
<li>View의 Segue를 어떻게 다룰까 고민된다는 것. reactor에서 행동해주는게 좋을 것 같은데 View 코드이다 보니. 좀 찾아보니 오른쪽의 RxFlow라는 라이브러리가 있는듯하다. 다음 작업에서 사용해보도록 해야겠다. <a href="https://github.com/RxSwiftCommunity/RxFlow">RxSwiftCommunity/RxFlow</a></li>
<li>MVVM에서 VM은 다른 View와 재사용이 가능할듯 했는데 Reactor Kit은 1:1 매칭으로 화면마다 하나씩 따라다녀야한다는 부분이 있는 것 같다. (view에서 사용하는 action이 정의돼 있다보니)</li>
</ol>
<p>개선</p>
<ol>
<li>RxSwift는 계속 사용을 하면서 시간이 해결하리라 믿는다.</li>
<li>RxFlow를 사용해본다.</li>
<li>RIBs나 Viper등의 아키텍쳐의 관점을 더 고민해야할듯 하다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Object Oriented Programing (feat. 추상화와 다형성)]]></title>
            <link>https://velog.io/@elile-e/Object-Oriented-Programing</link>
            <guid>https://velog.io/@elile-e/Object-Oriented-Programing</guid>
            <pubDate>Thu, 18 Feb 2021 08:25:29 GMT</pubDate>
            <description><![CDATA[<p>내가 주로 사용하게 되는 언어 Swift는 객체지향의 언어이다.</p>
<p>딱히 그 개념에 대해 공부시간을 가져본 적이 없는 것 같아, 이번 클린아키텍처를 공부하고 별도로 다뤄보기로 했다.</p>
<h2 id="oop-background">OOP Background</h2>
<p>먼저 생겨난 배경부터 생각을 해 보자.</p>
<p>나는 C언어를 다뤄보진 않았지만 C언어가 주류인 시절이 있었다고 한다.
C언어는 기본적으로 절차지향적. 위에서 아래로 내려가며 코드의 분기는 goto문으로 이루어 졌다고 한다.</p>
<p>ex) 10번째 줄에 있었다면 30라인으로 이동 등...</p>
<p>이로인해 규칙성 없이 goto문 만을 난무하게 되면 흐름이 없이 코드가 얽혀 유지보수성이나 재활용성 많은 부분에서 떨어진다고 한다.</p>
<p>이러한 문제들을 해결하기 위해 객체지향언어가 도입되기 시작되었다고 한다.</p>
<h2 id="oop의-목적">OOP의 목적</h2>
<ul>
<li>코드를 유연하고 변경이 쉽도록 한다.</li>
<li>직관적인 코드 분석이 가능하도록 한다.</li>
</ul>
<p>위를 목적으로 Strong Cohesion Weak Coupling을 지향하는 컨셉을 지니게 되었다.</p>
<h3 id="strong-cohesion">Strong Cohesion</h3>
<p>한개의 모듈/클래스 내에 존재하는 요소들의 관계의 정도를 나타내는 의미.
한개의 모듈이 한개의 목적을 지향하면서 모든 요소들이 같은 목적을 바라보는 것이 좋은 코드라는 의미이다.</p>
<h3 id="weak-coupling">Weak Coupling</h3>
<p>Coupling은 모듈과 모듈 사이의 의존, 결합정도를 의미한다.
Coupling이 모듈이 다른 모듈에 의존할 때 의존의 정도가 낮아져야 코드를 쉽게 변경 가능할 수 있다는 의미.</p>
<h2 id="oop의-특성">OOP의 특성</h2>
<p>OOP는 위와 같은 배경과 목적을 가지고 아래와 같은 특성들을 만들어 해결하고자 했다.</p>
<h3 id="캡슐화">캡슐화</h3>
<ul>
<li>객체 스스로가 자신의 목적에 따라 필요한 요소들(변수/함수)을 함께 묶는 것</li>
<li>다른 외부 객체에서 자신의 내부 요소들에 대한 접근을 선택적으로 해. 안정성을 높이는 것</li>
</ul>
<h3 id="상속성">상속성</h3>
<ul>
<li>부모 클래스의 속성과 기능을 상속받아 그대로 사용가능한 기능.</li>
<li>부모 클래스의 기능을 활용해 재사용이 가능한 코드를 만들 수 있다.</li>
</ul>
<h3 id="다형성">다형성</h3>
<ul>
<li>한 행동을 정의하고 그것을 사용하는 클래스마다  다르게 구현 할 수 있도록 하는 것.</li>
<li>한 개의 기능을 가지고 상황에 따라 다른 행동들과 목적에 맞는 다른 행위들을 수행할 수 있다.</li>
</ul>
<h3 id="추상화">추상화</h3>
<ul>
<li>한 개의 기능의 특성을 일반화하고 제거해 가장 단순한 것으로 만든다.</li>
<li>가장 단순하고 핵심적인 것과 디테일하고 상세적인 것을 분리하면서 재사용성, 의존성들의 문제들을 해결 할 수 있다.</li>
</ul>
<h1 id="class-vs-object-vs-instance">Class vs Object vs Instance</h1>
<p>사실 그 동안 느낌적으로만 알았던 내용인데 리드의 피드백을 듣고 한번 정리를 해보았다.</p>
<p>어떻게 보면 다 비슷한 놈 할 수도 있다고하나(모니터의 그 문서를 본다면 다 같은걸 말하겠지만), 실제 컴퓨터 내부에선 다 다른 것을 의미를 가진다.</p>
<p>막상 글로 정리하려니 정말 적당한 표현이나 딱 이해가 가능한 말들이 없다.</p>
<p>옛날에 내가 문서를 읽어봤을때 왜 이렇게 밖에 설명 못해? 라고 생각했는데 진짜 그렇게 밖에 설명 못하는 내용 같다.</p>
<p>그래도 내가 나름 이해한 설명이나 단어들로 정의를 해본다.</p>
<h2 id="class">Class</h2>
<p>어떠한 요소와 기능들을 구현한 구상도. </p>
<p>그냥 단일 Class 파일이나 Class의 괄호 묶음정도로 생각을 하면 되겠다.</p>
<h2 id="instance">Instance</h2>
<p>위의 Class 등이 실제 구현되어 메모리에 올라가 컴퓨터 내부의 실체를 가르킨다.</p>
<h2 id="object">Object</h2>
<p>Class의 Instance로 생각을 하면 되며, 코드를 보고 이야기 할 때 이용하는게 맞을 듯 하다.</p>
<p>ex) 여기서 이 객체는 초기화 되고... (뭐 이런식?)</p>
<pre><code class="language-swift">//아래 놈은 Class
class Person {
    var age: Int
    var name: String
}

let person = Person()

//person은 객체가 된다.

//Instance는? 저 코드가 돌아서 메모리에 올라가서 실제 접근할 수 있게 될 때의 녀석을 메모리라 한다.</code></pre>
<h1 id="abstract-class-vs-interface-vs-protocol">Abstract class vs Interface vs Protocol</h1>
<p><a href="https://brunch.co.kr/@kd4/6">자바의 추상 클래스와 인터페이스</a></p>
<p><a href="https://dongkyprogramming.tistory.com/11">Swift 프로토콜(protocol)과 Java 인터페이스(interface) 차이</a></p>
<p>각각 기능들에 대한 특징을 나열해 가며 실제 목적과 쓰임의 차이에 대해서 알아보고자 한다.</p>
<h2 id="abstract-class-java">Abstract Class (Java)</h2>
<ol>
<li>미완성의 클래스 &gt; 스스로 인스턴스가 될 수 없다.</li>
<li>추상메소드와 일반메소드를 가질 수 있다. (추상 메소드는 이름만 정의가 되어있는 메소드)</li>
<li>자바의 특징으로 다중상속이 불가능하다.</li>
</ol>
<p>위의 특징들로 보아 추상 클래스의 목적은 공통 또는 반복되는 메소드나 변수들을 기반으로 반복되는 코드들을 줄일 수 있으며, 어느정도의 기능을 보장한다.</p>
<p>그러면서 클래스의 한 종류로 상속을 통해 기능의 확장이 가능하다.</p>
<p>또한 수평적인 확장보단 수직적인 확장에 집중되어 있는 클래스이다.</p>
<h2 id="interface-java">Interface (Java)</h2>
<ol>
<li>역시 미완성이며 스스로 인스턴스가 될 수 없다.</li>
<li>추상메소드만을 가질 수 있다. &gt; 구현에 대한 제한이 더 강력해졌다. 하지만 기본적인 디폴트 값등은 구현할 수 있다.</li>
<li>한개의  클래스에서 여러개의 Inteface를 Implementation 할 수 있다.</li>
</ol>
<p>한 클래스가 인터페이스를 따르면서 해당 기능을 수행하는 것에 대해서 보장을 한다.</p>
<p>구현은 어렵게 해두었다. 추상클래스와 비교해서 상속을 해 수직적인 확장을 이루는 것이 아니라 해당 인터페이스를 따라 기능을 보장하며 다중적인 인터페이스 따름이 가능해 수평적인 기능의 확장을 목표로 한다.</p>
<h2 id="protocol-swift">Protocol (Swift)</h2>
<ol>
<li>이 역시 미완성 스스로 인스턴스 불가능.</li>
<li>다중 Interface implementation이 가능하다.</li>
<li>Property의 기본값을 가질 수 없다.</li>
<li>optional 한 function을 선언 할 수 있다.</li>
<li>단순히 Class만 따를 수 있는 것이 아니라. struct, enum에 까지 프로토콜을 따를 수 있다.</li>
</ol>
<p>전체적인 컨셉과 목적은 Interface와 유사하지만 크게 다른점은 두가지가 있는 것 같다.</p>
<p>Interface에선 그래도 어느정도의 구현은 가능하지만 Protocol은 어떠한 구현도 불가능하다는 것.</p>
<p>Class 뿐만 아니라 열거형, 구조체에서도 프로토콜을 따르게 하면서 더 넓은 사용성을 가졌다는 것.</p>
<p>위와 같은 차이가 있으며, Swift는 기존의 다른 언어들을 통해 보여졌던 인터페이스와 같은 기능들을 조금 더 극대화 시켜 강한 추상화와 그 추상화에 대한 기능확장(struct, enum)을 통해 코드 전반적에서 안정성을 확보하려 했던 것 같다. (Swift 에서 추구하는 Safety를 여기서도 볼 수 있는 것 같은 느낌?, 아직 확실치는 않다...)</p>
<h1 id="delegation-pattern">Delegation Pattern</h1>
<p>리드가 피드백을 준대로 처음 OOP를 접했을 때, 코드를 줄이거나 재사용을 위해 사용하는 기능으로 상속을 쉽게 선택하곤 한다. </p>
<p>그러나 이번 Clean Architecture를 공부하면서도 배웠겠지만 상속이나 직접적으로 객체를 참조하는 것은 강한 묶임/의존이 된다.</p>
<p>강하게 묶이는 것은 어느 한 객체의 변화에 다른 객체에 큰 영향을 미침을 의미하며 이는 곧 위험이다.</p>
<p>이를 해결하기 위해 DIP(의존성 역전 법칙)으로 배웠으며, 이를 디자인 패턴으로 구현한게 Delegation Pattern 이라고 보여진다.</p>
<p>Swift에서는 iOS Framework에서도 대부분의 기능확장을 Delegate로 구현이 되어 있으며, 알던 모르던 이미 본인은 많은 상황에서 Delegation pattern으로 앱을 만들고 있었을 것이다.</p>
<p>또 위에서 다룬 Protocol을 지원해 쉽게 설계가 가능할 수 있도록 했다.</p>
<p>내가 자주 Delegate를 사용하는  예시로 사용 예시를 보자.</p>
<h3 id="특정-월을-선택하는-월을-이전-viewcontroller에게-전달하는-연월-피커이다">특정 월을 선택하는 월을 이전 ViewController에게 전달하는 연/월 피커이다.</h3>
<pre><code class="language-swift">//ViewController간 데이터 전달 기능을 전달할 때
//해당 기능은 특정 월을 선택하는 월을 이전 ViewController에게 전달하는 연/월 피커이다.
protocol SelectMonthViewControllerDelegate: class {
    func selectMonthController(_ didSelectMonth: Date)
}

//Action을 하는 UIViewcontroller
class SelectMonthViewController: UIViewController {
        //기능을 하는 객체가 약한 참조로 구현을 한다.
        //delegate는 서로를 호출하는 경우가 많아 상황에따라 weak을 사용해주면 된다.
        weak var delegate: SelectMonthViewControllerDelegate

        func tappedItem(_ date: Date) {
                //delegate의 Action을 실행해준다.
                self.delegate?.selectMonthController(date)
                self.dismiss(animated: true, completion: nil)
        }
}

//Action을 받는 ViewController
class MainViewController: UIViewController {
        private func presentCalendar() {
        let calendar = SelectMonthViewController()
                calendar.delegate = self
        self.present(calendar, animated: false, completion: nil)
    }
}

extension MainViewController: SelectMonthViewControllerDelegate {
        func selectMonthController(_ didSelectMonth: Date) {
                self.viewModel.selectedMonthDate.accept(didSelectMonth)
        }
}</code></pre>
<p>위와 같은 상황을 볼 수 있다.</p>
<p>위의 구조를 그림으로 보게되면 아래와 같이 된다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/14fb3b9a-0c0a-4011-8c51-4654dc652bab/_2020-11-23__6.13.26.png" alt=""></p>
<p>뭐, 이런 패턴이 없다면 직접 MainViewController 를 SelectMonthViewController()내의 변수로 만들어 실행을 해둬도 되겠지만 더 Safety하고 유지보수성을 좋게 하기 위한 한가지의 디자인 컨셉인 것 같다.</p>
<p>iOS에선 TableView나 많은 Apple의 API에서 위의 패턴으로 구현이 되어있고 왜 그렇게 구현했는지에 대해서도 알고 있으면 좋으니까 오늘 내용을 다루어 봤다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Architecture & Detail]]></title>
            <link>https://velog.io/@elile-e/Architecture-Detail</link>
            <guid>https://velog.io/@elile-e/Architecture-Detail</guid>
            <pubDate>Mon, 15 Feb 2021 14:22:48 GMT</pubDate>
            <description><![CDATA[<p>드디어 이 책의 메인 이름인 아키텍처라는 부분이 나온다.</p>
<p>사실 본문에서 내용하는 바는 각각 제품의 주기별로 아키텍처를 지원해 좋은점들을 나열한다.</p>
<ul>
<li>개발</li>
<li>배포</li>
<li>운영</li>
<li>유지보수</li>
</ul>
<p>기본적으로 한가지의 프로젝트가 가지게 되는 사이클이 아닐까 생각한다.</p>
<p>훌륭한 아키텍터는 위와 같은 주기 내에서 알맞은 시점에 알맞은 분리와 설계로 최소한의 비용과 기간으로 주기를  순환 할 수 있도록 하는 목적을 가진다.</p>
<h2 id="boundaries-drawing-lines">Boundaries: Drawing Lines</h2>
<p>해당 파트에서는 소프트웨어 아키텍처는 선을 긋는 기술이라고 이야기 한다.</p>
<p>사실 이 부분에서 2가지를 느낄 수 있었다.</p>
<ul>
<li>컴포넌트를 나누고 그 관계에서 의존성을 관리하고 그로인해 얻을 수 있는 안정성</li>
<li>의존해야하는 라이브러리를 추후에 결정하며, 잘 그어진 선 덕분에 쉽게 변경할 수도 있다는 점.</li>
</ul>
<p>먼저 FitNesse 예시를 들었다.</p>
<ol>
<li>데이터베이스와 앱 사이에 경계선을 그어 앱은 관련 메소드 이외에는 데이터베이스에 대해서 접근할 수 있는 구조를 만들었다.  데이터베이스에 대해 알 수 없으며, 이는 즉 의존성을 제거했다는 의미로 볼 수 있다. 의존성이 없어지면서 데이터베이스를 수정하더라도 앱에 영향을 미치는 경우는 드물게 된다. 즉 매우 안정적인 상태로 들어 갈 수 있게 되었다.</li>
<li>데이터베이스를 쉽게 변경할 수 있게 되었다. mysql을 사용하던 mongo db를 사용하던 그 결정을 나중으로 미룰 수 있게 되었다. 이로 인해 먼저 앱의 기능들을 구현한 후 그에 적합한 데이터베이스를 선택할 수도 있게 된다.</li>
</ol>
<p>사실 이 부분에서 이 책을 읽으면서 가장 크게 생각하게 된 점을 마주하게 됐다.</p>
<p>기존에 어떤 서비스나 프로젝트에 대해서 고민하기를 어떤 라이브러리에 의존할까? 로 시작했었다.</p>
<p>지금 보면 큰 오류로 생각이 되는 부분인데,  어디에 의존을 하거나 편하게 쓰려고 고민하기 보단 재사용성, 유지보수성들을 고려해 만들게 될 컴포넌트의 구조를 설계하고 구현하는 것이 소프트웨어 개발자 입장에서는 더 높은 우선순위를 지닌다는 것을 알 수 없었다.</p>
<h2 id="screaming-architecture">Screaming Architecture</h2>
<p>: 소프트웨어의 아키텍처는 유스케이스를 지원하는 구조이다.</p>
<p>UseCase란 실제로 사용하기 위한 기능이며, 아키텍처의 목적이기도 하다.</p>
<p>아키텍처는 프레임워크로부터 제공받아서는 안되며, 준수해야 할 사항이 아니다. </p>
<p>이를 나의 실무와 연관지어보면</p>
<p>나는 iOS 개발자이며, iOS 프레임워크 아래에서 개발을 하게 된다. iOS 프레임워크에서 개발을 한다고 해서 앱 컴포넌트의 아키텍처를 iOS에 의존해서 되겠는가?</p>
<p>프레임 워크 역시 앱을 개발하기 위한 한가지의 컴포넌트이며, 또 한가지의 도구일 뿐 그곳에 의존해서는 안된다. 라고 생각을 하게 되니 많은 생각을 할 수 있었다.</p>
<p>또 이 아키텍처의 중심은 UseCase를 위해 그곳으로 기준이 되어 있어야 함을 잊어서는 안되겠다. </p>
<h2 id="clean-architecture">Clean Architecture</h2>
<p>드디어 이 장에서 클린아키텍처가 무엇인지 설명해준다.</p>
<p>클린 아키텍처란 내부는 고수준/변형성이 적은 구조부터 점점 저수준/변형성이 높은곳으로.</p>
<p>의존성은 안쪽을 향하는 아키텍처의 구조이다.</p>
<p>위의 의존성 관계 즉, 클린 아키텍처를 지키는 것은 가장 비용 절감적일 것 이며, 좋은 아키텍처를 지니는 것이라고 이야기 한다.</p>
<p>이전에 배워왔던 DIP 등의 개념들을 이해한다면 아래와 같은 구조를 쉽게 이해할 수 있다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/bf3eec63-df50-4732-8fc7-88ad8d816c11/_2020-10-27__10.24.34.png" alt=""></p>
<p>안쪽으로 갈 수록 높은 수준/변하기 어려운 것으로 이루어 지고 밖으로 갈 수록 그의 반대이다.</p>
<p>물론 서비스에 따라 원의 개수는 줄어들 수 있다고 생각 한다.</p>
<p>하지만 나는 아래와 같은 기준으로 나뉘어야 하지 않을까 생각한다.</p>
<ol>
<li>불변성의 수준</li>
<li>의존하는 관계가 안쪽으로 흐르는 것</li>
<li>조금 더 아키텍처에서 서비스적으로 중요한 정책을 가지고 있는 것.</li>
</ol>
<p>위의 기준대로 또 앞서 말한 여러 원칙들을 통해 얼마나 잘 분리하는 것이 클린 아키택처이다. </p>
<h1 id="detail">Detail</h1>
<p>저자가 말하는 세부사항은 클린 아키텍처 구조에서 가장 밖의 부분에 위치해야하는 구조물이다.</p>
<p>가장 변동사항이 많으며, 그저 UI와 비슷하게 제품의 핵심적인 구조물 보단 입출력 장치와 같은 구조물이다.</p>
<h2 id="database">Database</h2>
<p>데이터 베이스는 단순히 데이터를 장기적으로 보관해두는 도구. </p>
<h2 id="web">Web</h2>
<p>웹은 단순히 기능들을 표시하는 출력하는 도구</p>
<h2 id="framework">Framework</h2>
<p>단순히 어플리케이션들을 빠르게 제작할 수 있는 도구</p>
<p>위의 모든 요소들은 단순히 도구에 지나지 않는다. 아키텍처의 목표를 실제로 이루는 부분은 아니라는 것이다.</p>
<p>웹으로 표현하던 것을 모바일 앱으로 바꾸싶을 때도 있고.</p>
<p>더 좋은 프레임워크가 나와 바꾸고 싶을 때도 있고.</p>
<p>다루는 데이터들의 성격이 더 방대해지거나 변경이 되어 더 이상 RDB가 필요하지 않을 수도 있다.</p>
<p>아키텍처의 핵심적인 기능들이 이에 의존하게 된다면 그 뒤의 변경에선 말하지 않아도 될 것이다.</p>
<h1 id="clean-architecture-후기">Clean Architecture 후기</h1>
<p>사실 이전부터 좋은 구조를 설계해야하고 그런 필요성에 대해서 생각만 했었지 직접적으로 어떻게 해결하려는 액션이나 스터디를 해본적이 없었다.</p>
<p>그러므로 이 책이 내 아키텍처에 대한 첫 고민이라 할 수 있다.</p>
<p>사실 읽으면서 아직 길지 않은 개발 경험 때문인지 실로 공감이 가지 않거나 명확히 이해하지 못하는 부분들도 여럿 있었다. 워낙 내용 자체가 추상적이기도...</p>
<p>그러나 배운 부분에 있어서는 명확하고 앞으로 좋은 코드에 있어서 바라보아야 할 방향성을 짚어준 것에 대해서는 확실하다.</p>
<ol>
<li>코드를 분리할 것.</li>
<li>변할 수 있는 것들과 변하지 않는 것으로 나눌 것.</li>
<li>변할 수 있는 것들이 변할 때, 변하지 않는 것에 영향을 주지 않을 것.</li>
<li>그 방법은 추상화를 통한 의존성에 대한 역전으로.</li>
</ol>
<p>위의 배움들로 조금 더 생각을 해보면 앞으로의 코드에 많은 변화들을 줄 수 있지 않을까.</p>
<p>아마 몇개의 프로젝트 뒤에 더 읽어본다면 더 많은 내용들이 보일 수 있을 것 같다.</p>
<p>아는 만큼 보이고 경험한 만큼 배울 수 있는 책인 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Component Principles]]></title>
            <link>https://velog.io/@elile-e/Component-Principles</link>
            <guid>https://velog.io/@elile-e/Component-Principles</guid>
            <pubDate>Mon, 15 Feb 2021 14:20:28 GMT</pubDate>
            <description><![CDATA[<h2 id="component">Component</h2>
<p>이전에 말한 SOLID원칙들은 모두 코드 뭉텅이, 클래스 내부의 구현 방법들에 대한 방법이었다.</p>
<p>저자가 말하기를 벽돌에 관련한 이야기 였다면 이번에는 벽돌들을 쌓아 방의 구조를 설계하는 수준의 컴포넌트에 관련한 내용들을 다룬다고 한다.</p>
<p>&quot;컴포넌트는 배포를 할 수 있는 가장 작은 단위&quot;</p>
<h2 id="component-cohesion">Component Cohesion</h2>
<p>컴포넌트의 응집도란 클래스를 어떤 컴포넌트를 생성하고 배치해서 나눌지에 대한 3가지 원칙을 정리한다.</p>
<h3 id="reuserelease-equivalence-principle-rep">Reuse/Release Equivalence Principle (REP)</h3>
<p>: 재사용 단위는 릴리즈의 단위와 같다.</p>
<p>하나의 기준으로 묶인 클래스는 한개의 버전을 가지고 있어야 하며, 동일한 릴리즈 문서에 있어야한다.</p>
<p>우리의 기준으로 보면 한개의 깃 레포지토리로 볼 수 있을 것 같다.</p>
<p>뭐 지금 우리에게 생각하면 뭐 그런 당연한 이야기를 해? 라고 할 수 있지만</p>
<p>지켜지지 않을 경우에 대해서는 문제가 생겨 원칙이라고 저자는 말한다.</p>
<h3 id="common-closure-principle">Common Closure Principle</h3>
<p>: 동일한 이유로 동일한 시점에 변경되는 클래스를 같은 컴포넌트로 묶어야한다.</p>
<p>해당 원칙의 목적은 유지보수 성이다.</p>
<p>변경의 여지가 있는 클래스는 한 군데에 변경의 여지가 없는 불변의  클래스는 또 다른 컴포넌트로 위험성을 나누고자하는 것이 목표이다.</p>
<p>어디서 들어본 개념이 아닌가?</p>
<p>코드에서 해당하는 SRP(단일책임원칙)이 한가지의 이유 한가지의 책임을 가지는 것으로 묶어야한다고 이야기했다.</p>
<p>또 OCP(개방폐쇄원칙) 변경이 가능한 것과 불가능한 것의 구분하여 묶어야한다고 이야기했다.</p>
<p>CCP는 컴포넌트 차원에서의 위 원칙을 정의하는 것 같다.</p>
<h3 id="common-reuse-principle-crp">Common Reuse Principle (CRP)</h3>
<p>: 사용자들이 필요하지 않은 것에 의존하지 않도록 해야한다.</p>
<p>사실 해당 원칙도 SOLID의 ISP(인터페이스분리원칙)과 대칭되는 개념이다.</p>
<p>A컴포넌트에서 B컴포넌트를 의존한다고 하자.</p>
<p>B컴포넌트에서 변경이 일어날 경우 A컴포넌트에서도 변경사항이 발생할 수 있으며 이는 즉 위험요소가 발생할 수 있다는 의미이다.</p>
<p>그러므로 지난 LSP에서도 해당 기능들을 분리해 필요한 기능들에게만 의존할 수 있도록 하자라는 의미를 가졌었다.</p>
<p>컴포넌트에서도 이와 비슷하다. CRP는 컴포넌트 간에 의존성이 발생할 때, 의존하는 컴포넌트의 모든 기능들이 필요한가? 에 대해서 고민해보고 필요가 없다면 분리해야한다는 의미이다.</p>
<h3 id="the-tension-diagram-for-component-cohesion">The Tension Diagram for Component Cohesion</h3>
<p>: 컴포넌트 응집도에 대한 균형 다이어그램.</p>
<p>REP와 CCP 원칙은 두 컴포넌트를 어떻게 합쳐야 할지에 대한 고민거리들</p>
<p>CRP는 컴포넌트를 어떻게 분리해야 할 지를 고민할 수 있게 해주는 원칙들이다.</p>
<p>이 원칙들을 잘 고민하여 균형있게 컴포넌트들의 구조들을 가져가는 것이 좋은 코드를 만들 것이라는 이야기를 한다.</p>
<p>또한 해당 구조들은 프로젝트의 상태에 따라 변화한다고 이야기한다.</p>
<p>프로젝트가 태동되는 시기에는 재사용성에 대해서 고민을 하게 되며, 프로젝트가 점점 발전하는 시기에는 유지보수성에 대에서 더 고민하여 움직이게 된다.</p>
<p>결국은 그 때에 따라 어떻게 균형있게 가져갈지를 고민해 더 중점을 두어 컴포넌트를 구상해야한다고 이야기한다.</p>
<h2 id="component-coupling">Component Coupling</h2>
<h3 id="acyclic-dependencies-principle-adp">Acyclic Dependencies Principle (ADP)</h3>
<p>: 의존성 비순환 원칙</p>
<p>컴포넌트 간의 관계에 있어서 항상 순환이 끊어져야만 한다.</p>
<p>기본적인 컨셉은 컴포넌트를 분리해 최소한의 릴리즈 가능한 단위로 구현.</p>
<p><img src="https://images.velog.io/images/elile-e/post/0192fee9-d3ef-480b-b55f-c28dd77d1616/_2020-10-26__10.38.10.png" alt=""></p>
<p>그러나 위의 그래프를 보면 Interactors, Authorizer, Entities 가 서로 순환해 구현이 되고 있는데, 이렇다면 컴포넌트를 나눈다 한들 저들 중 한가지를 수정하기 위해선 3번의 릴리즈가 필요한 구조가 되며,  컴포넌트화를 하느니 못한 상황이 발생한다.</p>
<p>이때, 비효율적인 순환을 해결하기 위해 DIP에 사용된 방식이 적용이 된다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/4d9a2529-a06c-4edd-bee9-f038778f4673/_2020-10-26__10.43.03.png" alt=""></p>
<p>이전과 같이 인터페이스 역할을 하는 Permissions라는 컴포넌트를 만들어 의존성을 역전시켜 순환의 고리를 해결한다고 한다.</p>
<h3 id="stable-dependencies-principle-sdp">Stable Dependencies Principle (SDP)</h3>
<p>: 안정된 의존성 원칙 </p>
<p>변동성이 높은 컴포넌트를 의존하지 않도록 관계를 가지는 것.</p>
<p>이곳에선 변동성이 낮은 것은 안정성이 높다고 표현하며, 쉽게 변할 수 있는 것은 안정성이 낮다고 표현한다.</p>
<p>그리고 안정성이 높은 것에 의존할 수 있도록 컴포넌트를 설계하라는 의미로 이전에 OCP의 컴포넌트 관계 버전이 아닐까 생각된다.</p>
<h3 id="stable-abstractions-principlesap">Stable Abstractions Principle(SAP)</h3>
<p>컴포넌트는 안정된 정도만큼만 추상화되어야 한다.</p>
<p>사실 Class 수준의 DIP의 관계에서는 완전히 추상적이거나 완전히 구체적이거나 둘 중 하나의 경우를 따를 수 있었다.</p>
<p>하지만 컴포넌트 수준에서는 명확히 이를 나누기란 쉽지 않은 것이다. </p>
<p>이에 대한 솔루션으로 추상화 정도를 측정을 해. </p>
<p>변동이 가능한 컴포넌트는 안정도와 추상도를 고려해 두 균형을 이루는 수준에서 구현해 유동적으로 대응 할 수 있어야 한다고 이야기 한다.</p>
<h2 id="결론">결론</h2>
<p>기존엔 컴포넌트 수준의 고민을 실제로 해본 적이 없어 슬슬 책의 내용이 나에겐 추상의 영역으로 넘어온 듯한 이야기들이었다.</p>
<p>실제 구현에서는 안드로이드 앱과 iOS 앱이 관계를 가질 일도. 서버와 앱이 관계를 가질 일은 API 정도 밖에 없을 것이다.</p>
<p>아마 추후에 우리 서비스를 고도화 시켜 한 앱 내부에 큰 규모에서 여러 컴포넌트를 다룰 일이 생길 때 다시 펼쳐볼지 모르겠다.</p>
<p>크게 느낀 컨셉에선 이전에 다루었던 디자인 원칙과 크게 다르지 않았다.</p>
<p>변하지 않는 것과 변하는 것들을 쪼개고 서로가 서로에게 영향을 미치는 영향이 적을 수 있도록 설계하는 것.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Design Principles]]></title>
            <link>https://velog.io/@elile-e/Design-Principles</link>
            <guid>https://velog.io/@elile-e/Design-Principles</guid>
            <pubDate>Mon, 15 Feb 2021 14:00:22 GMT</pubDate>
            <description><![CDATA[<p>이전 프로그래밍 패러다임에서는 코드들을 표현화하는 것을 다루었다면</p>
<p>이번 디자인 원칙에서는 그보다 한단계 더 상위 단위인 개념인 클래스 그리고 함수들의 중간 단계에 대한 구조들의 원칙들을 기술한다.</p>
<p>목표는 아래와 같다. (좋은건 다 있는 느낌이랄까...)</p>
<ol>
<li>변경에 유연함</li>
<li>재사용성</li>
<li>코드의 가독성</li>
</ol>
<h2 id="single-responsibility-principle">Single Responsibility Principle</h2>
<p>해당 원칙이 생겨나게 된 배경이나 필요성을 가지고 원칙을 설명하도록 한다.
<img src="https://images.velog.io/images/elile-e/post/752ad5a3-de28-473f-82e1-ec82404959a5/_2020-10-22__4.49.22.png" alt=""></p>
<p>먼저 위의 사진을 보면 Employee라는 Class를 사용하는 관계자들이 3명이 있다는 부분을 집중하면 된다.</p>
<p>각각 한가지씩의 기능을 필요로 하는데, 그게 모두 한 클래스에 집중이 되어있다는 것이다.</p>
<p>사실 수정이 없다면 더 이상 고민할 필요가 없겠지만, 우리의 소프트웨어는 soft 해야하지 않은가.</p>
<p>그럼 이제 저렇게 구현이 된 상태에서 새로운 기능을 추가한다고 가정해보자.</p>
<ol>
<li>CFO가 급여를 계산하는데 인센티브 제도를 도입해 Employee 클래스를 수정한다.</li>
<li>COO 역시도 report 함수를 수정할 일이 생겨 수정한다.</li>
</ol>
<p>동시에 한 클래스를 두명이서 수정하고 있지 않은가.</p>
<p>당연히 그 둘은 이것이 동시에 수정되고 있음도 알 수 없다. </p>
<p>나중에 VCS에서 병합 시점에 알 수 있겠지. 문제는 이 시점에서 발생하게 된다. </p>
<p>병합을 시도하는 과정에서 문제가 발생하면 그것은 또 누가 수정하고 해결을 할 것인가? </p>
<p>저자는 이 부분이 문제라고 이야기한다.</p>
<p>그러므로 class를 분리하여, 두 사람이 동시에 class를 수정하는 일이 없도록 CFO는 CFO가 필요한 파일만 수정할 수 있고. CTO는 CTO가 필요한 파일만 수정해 </p>
<p>서로 충돌하는 것을 방지하는 방식으로 해결을 한다고 한다.</p>
<p>SRP 원칙이 지켜진 구조는 아래와 같다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/65f8330e-88c5-46ef-8b2a-30aafe092457/_2020-10-22__5.07.53.png" alt=""></p>
<p>간단하게 설명하면 Employee Facade class에는 코드가 없으며 하위에 3개의 클래스를 생성해 그들에게 위임하게 된다.</p>
<p>각 참여자들은 해당 클래스를 수정하면 되니, 병합 중 충돌에 대해 걱정하지 않아도 되며, 수정되는 것을 꼭 알아야 할 필요도 없다고 생각한다. </p>
<p>정리해보면 &quot;SRP 원칙은 하나의 모듈을 한 단위의 참여자가 수정/접근하도록 한다&quot; 정도로 말할 수 있을 것 같다.</p>
<h2 id="open-closed-principle">Open Closed Principle</h2>
<p>아래의 코드를 예시로 문제점을 생각해 보자.</p>
<pre><code class="language-swift">struct Book { 
    let id: String 
    let title: String 
    let author: String 
    let rentalPrice: Int 
} 

struct Video { 
    let id: String 
    let title: String 
    let director: String 
    let rentalPrice: Int 
} 

//해당 클래스는 렌탈 가격을 계산해주는 기능을 함수이다.
class RentalPriceCalculator {
 var totalRentalPrice: Int { 
        var result = 0 
        result += self.books.reduce(0, { $0 + $1.rentalPrice })
        result += self.videos.reduce(0, { $0 + $1.rentalPrice }) 
        return result 
    } 

    func addBook(_ book: Book) { 
        self.books.append(book) 
    } 

    func addVideo(_ video: Video) { 
        self.videos.append(video) 
    } 

    private var books = [Book]() 
    private var videos = [Video]() 
}
</code></pre>
<p>만약 이곳에서 보드게임을 추가하고 싶은 경우를 생각해보면</p>
<p>RentalPriceCalculator 클래스를 다시한번 손을 봐야한다.</p>
<p>저자는 상위의 모듈을 수정하거나 변경하는 일이 위험한 일이라고 이야기한다.</p>
<p>하위 모듈의 변화로 상위 모듈까지 변경되는 것은 위험하다.</p>
<p>그러므로 하위모듈에 대해선 확장이 가능하지만(open) 상위모듈에 대해서는 변경을 하지 않아도 되도록 하는 것.</p>
<p>이것이 OCP의 개념이다.</p>
<p>그럼 OCP가 지켜진 아래의 코드를 보자.</p>
<pre><code class="language-swift">protocol RentalItem { 
    var id: String { get } 
    var rentalPrice: Int { get } 
}

class RentalPriceCalculator { 
    var totalRentalPrice: Int { 
        return self.items.reduce(0, { $0 + $1.rentalPrice }) 
    } 

    func addRentalItem(_ item: RentalItem) {
         self.items.append(item) 
    }

    private var items = [RentalItem]() 
}
</code></pre>
<p>단순히 프로토콜을 따르는 구조체를 만들어 렌탈 아이템이 추가되더라도 RentalPriceCalculator를 수정하는 일은 없게된다.</p>
<p>그러므로 OCP가 잘 지켜졌다고 볼 수 있다.</p>
<h2 id="liskov-subsitution-principle">Liskov Subsitution Principle</h2>
<p><img src="https://images.velog.io/images/elile-e/post/3a9313c6-d988-4e4b-abf1-4343603e3f4b/_2020-10-23__12.43.45.png" alt=""></p>
<p>위와 같은 문제를 해결하기 위해 LSP 원칙이 필요한 이유인데 이를 한번 설명해보겠다.</p>
<p>Square는  Rectangle의 하위타입으로 적합하지 않다.</p>
<p>Rectangle에서 넓이 높이는 독립적으로 변경되어야한다. 하지만 Square의 넓이 높이는 반드시 같아야만하므로 항상 함께 변경되어야한다.</p>
<p>그러므로 LSP에 따르면 위와 같은 관계는 옳지 않다</p>
<p>위의 구조를 유지하면서 문제를 해결하기 위해서는 if문으로 타입을 확인해 그에 따른 함수를 호출해야하는데, 평행사변형등의 또 타입이 늘어나면 어떻게 대응하겠는가? </p>
<p>위와 같은 문제들이 발생하지 않게 해결한다고 하면</p>
<p>Shape → Square</p>
<pre><code>   → Rectangle</code></pre><p>위와 같이 수직적 확장보단 수평적 방향으로 해결해야하지 않을까 싶다.</p>
<p>저자는 이것의 해결방법으로 항상 상위 하위가 치환이 가능한 상태가 지켜져야 한다고한다. </p>
<h2 id="interface-segregation-principle">Interface Segregation Principle</h2>
<p>인터페이스를 따르는 객체가 나에게 필요없는 객체를 따르게 됐을 때 생기는 문제의 예시를 보자.</p>
<pre><code class="language-swift">protocol MediaProtocol {
        var isMute: Bool { get set }

        func play()
        func load()
}

//여기서는 별 문제없이 모든 인터페이스 기능을 잘 사용하고 있다.
class OurVideoView: MediaProtocol {
    var isMute: Bool {
        get { return self.player.isMuted }
        set { self.player.isMuted = newValue }
    }

    func play() {
            //play action
    }

    func load() {
            //load something
    }
}

//아래의 예시에서는 슬슬 모든 기능을 사용하지 않고 형식에 맞추기 위해 인터페이스를 사용하는데....
class YoutubeVideoView: MediaProtocol {
    var isMute = false //미사용

    func load() {
        //load action
    }

    func play() {
        //미사용
    }
}

//나중에 추가기능으로 음소거일 경우 재생을 하지 않도록하는 기능을 추가
func showMedia(_ view: MediaProtocol) {
        guard !view.isMute else { return }
        view.load()
}
//드디어 문제가 터졌다 우리는 YoutubeViewView는 무조건 isMute를 false로 구현해놓지  않았는가.
//YoutubeVideoView는 절대 재생이 안되는 문제가 생긴다.
</code></pre>
<h2 id="dependency-inversion-principle">Dependency Inversion Principle</h2>
<p>의존성 역전의 법칙</p>
<p>사실 SOLID 개념 중에 가장 핵심적인 개념이라 볼 수가 있다.</p>
<p>의존성을 반대방향으로 역전이라는 말로 이해하니 처음에는 쉽게 이해할 수 없었다.</p>
<p>그 의미보다는 추상화된 인터페이스를 통해 직접적으로 의존하던 관계를 간접적으로 변화시킨다는 생각을 가진다면 더욱 쉽게 이해할 수 있을 것 같다.</p>
<p>그럼 DIP로 해결하고자 하는 문제를 살펴보자.</p>
<p><img src="https://images.velog.io/images/elile-e/post/f0368f05-00f6-432f-b466-a29f1be1fc30/_2020-10-23__3.36.17.png" alt=""></p>
<p>이는 우리가 쉽게 생각할 수 있는 관계이다.</p>
<p>직접적으로 Layer 별로 관계를 맺고 있고 강하게 묶여있다.</p>
<p>그러므로 최하위에 있는 Utility Layer를 변경하게 되면 Policy Layer까지 변경 영향을 미칠 수 있게되며,</p>
<p>여러 부분의 수정에 따른 위험 감수를 따르게 된다.</p>
<p>이제 DIP를 잘 따르는 구조를 한번 보자.</p>
<p><img src="https://images.velog.io/images/elile-e/post/8954bb3f-da24-4f1b-8381-bda89b1adccd/_2020-10-23__3.40.45.png" alt=""></p>
<p>하위 레이어와 상위레이어는 중간에 인터페이스란 추상화된 것에 의존성을 바라보게 된다.</p>
<p>하위 레이어인 Mechanism Layer는 Policy Service Interface만 잘 따르게 된다면 무수히 많은 형태로 변형이 생기더라도 영향이 갈 일이 드물다.</p>
<p>저자는 DIP를 무조건적으로 지키는건 사실 어려운 일이라고 말한다.</p>
<p>그렇지만 머릿속에서 위와 같은 배경과 솔루션을 가질 수 있다는 것을 알고 구조를 잡는 것과 그렇지 못한 것은 큰 차이가 있을 것이다.</p>
<p>실제 DIP를 지키기 위한 저자의 가이드를 보자.</p>
<ol>
<li>변할 수 있는 클래스를 참조하지 말아라.</li>
<li>변할 수 있는 클래스를 따르지 말아라.</li>
<li>해당 클래스의 함수를 오버라이딩 하지 말아라</li>
<li>변동성이 큰 것에 대해서 언급 자체를 말아라...</li>
</ol>
<p>전체적인 규칙을 보면 이야기하고자 하는 것은 변동성이 큰 클래스와 아닌 클래스를 분리하며, 그 클래스들과의 관계는 직접적인 상속, 선언보단 추상화를 통한 인터페이스를 활용해 접근하라는 의미인 것 같다.</p>
<p>참조한 레퍼들</p>
<p><a href="https://wlaxhrl.tistory.com/80">SOLID 원칙을 Swift 코드로 이해해보기</a></p>
<p><a href="https://cheese10yun.github.io/spring-solid-dip/">Spring 예제로 보는 SOLID DIP - Yun Blog | 기술 블로그</a></p>
<p><a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency inversion principle</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Programming Paradigm]]></title>
            <link>https://velog.io/@elile-e/Programming-Paradigm</link>
            <guid>https://velog.io/@elile-e/Programming-Paradigm</guid>
            <pubDate>Mon, 15 Feb 2021 13:56:28 GMT</pubDate>
            <description><![CDATA[<p>비교적으로 패러다임이란 것은 언어와 무관하며 더 중요하다.</p>
<p>패러다임은 어떤 구조를 언제 쓸 지를 고민할 수 있게 해준다.</p>
<h2 id="structured-programming">Structured Programming</h2>
<ul>
<li>첫번째로 적용된 패러다임이다.</li>
<li>마구잡이로 goto문을 쓰던 시절이 있었다고하는데 난잡한 코드가 되어 이를 해결하기 위해</li>
<li>If, while, for 등의 제어문을 권장하는 패러다임이다.</li>
<li>이를 통해서 코드에 대해 직접적으로 if/while,for 등으로 분기 및 함수수준에서의 모듈화를 가능하도록 했다.</li>
</ul>
<h2 id="object---oriented-programming">Object - Oriented Programming</h2>
<ul>
<li>함수호출 이후 오랫동안 힙이 된 것을 알고 거기서 착안</li>
<li>함수 생성자 &gt; 클래스 / 로컬 변수 &gt; 인스턴스 변수 &gt; 중첩 함수 &gt; 메소드</li>
<li>캡슐화, 상속, 추상화, 다형성가 특징이라 하지만 캡슐화와 상속은 이전의 컨셉에서도 가능했으며 단지 조금 쉽게 가능하게 해주었다는 것. 진짜 가장 큰 컨셉은 추상화와 다형성이라고 말함. (아직 개념에 대한 정리가 더 필요하다)</li>
</ul>
<h2 id="functional-programming">Functional Programming</h2>
<ul>
<li>프로그래밍 이전에 발견된 것 그러나 가장 최근에 반영되는 패러다임</li>
<li>특정 범위 내에 값에 대한 불변성을 보장하면서 할당문에 규칙에서 제한하도록 하는 것</li>
<li>이로 인해 값이 전역변수로 언제 값이 변하는 것을 알 수 없는 두려움에서부터 벗어난다.
<a href="https://velog.io/@elile-e/FRP-Funcional-Reactive-Programming">이전 블로그 게시글</a></li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<ul>
<li>패러다임은 전체적으로 개발자에게 어떤 새로운 기능을 쥐어주기보단</li>
<li>새로운 규제들을 추가해서 무엇을 하지 말아야 할지 알려주는 제안이다.</li>
<li>저자는 현 패러다임에서 우리에게 더 가져갈 것이 없다고 말하며, 더 이상의 패러다임은 없을 것이라고 이야기한다.</li>
<li>패러다임은 앞으로의 아키텍쳐에서 3가지 모두 차용되어야한다고 한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Intro]]></title>
            <link>https://velog.io/@elile-e/Intro</link>
            <guid>https://velog.io/@elile-e/Intro</guid>
            <pubDate>Mon, 15 Feb 2021 13:54:00 GMT</pubDate>
            <description><![CDATA[<p>Clean Architecture를 읽어가며 생각한 내용들을 정리한 내용.</p>
<p>인트로 부분에서 저자는 좋은 코드와 아키텍쳐가 무엇인지 설명을 하고 왜 필요한지에 대해서 설명을 하게된다.</p>
<h2 id="1-굴러가기만-하는-코드">1. &quot;굴러&quot;가기만 하는 코드</h2>
<p>나의 개발 역사를 조금 설명하자면 첫째도 구현, 둘째도 구현 ... 마지막도 구현이었다.</p>
<p>사업과 서비스를 만들어 가기 위해서 개발을 시작했고 구현만 됐으면 됐고 그 다음 또 다른 기능의 구현이었다. 당연히 좋은 코드에 대해서는 관심이 없었던 과거였다.</p>
<p>저자도 첫장에서 &quot;그들이 만든 코드는 아마도 예쁘지 않을 것, 그러나 작동한다&quot; 라고 이야기 한다.</p>
<h2 id="2-정도를-걷는-것은-힘든-것">2. 정도를 걷는 것은 힘든 것</h2>
<p>저자는 개발을 제대로 정도로 하는 것은 매우 힘들다고 한다.</p>
<p>이 부분에서 깊은 사고력과 통찰력이 필요하다고 하는데 &quot;굴러&quot;가기만 하는 코드를 작성하는 사람들은</p>
<p>그것이 문제인지 아닌지에 대한 자각도 없는데 어떻게 그런 사고력과 통찰력이 있을 수 있을까?</p>
<p>나는 당연히 그 힘듦도 필요성을 가지고 있을 수도, 알 수도 없었다.</p>
<h2 id="3-코드-잘-짜면-뭐가-좋은데">3. 코드 잘 짜면 뭐가 좋은데?</h2>
<p>저자는 몇가지 물음을 통해 그 필요성에 대해 스스로 답할 수 있게 해준다.</p>
<ol>
<li>막 짠 코드로 간단한 수정이 며칠씩 걸리는 경험 해 보았나? (yes)</li>
<li>누군가 짜둔 후진 코드로 인해 방해를 받아봤나? (yes)</li>
<li>설계가 엉망이어 제대로 제품을 만들지 못해 고객의 신뢰를 잃고 팀의 사기가 떨어져봤나? (yes)</li>
<li>프로그래밍 지옥을 경험해봤나? (yes)</li>
</ol>
<p>나는 각각 한가지의 질문에 대해서 쉽게 그 경험들을 떠올릴 수 있다.</p>
<p>나 역시 최근 1-2년 들어서야 위의 문제점과 심각성을 동감 할 수 있고 해결책을 모색하고 있던중이다.</p>
<h2 id="4-저자가-제시하는-좋은코드란">4. 저자가 제시하는 좋은코드란?</h2>
<ol>
<li>기능에 비해 거대한 인력이나 투자가 없어진다.</li>
<li>변경사항을 쉽고 빠르게 대응할 수 있다.</li>
<li>그 변경사항에 대해선 결함이 거의 없다.</li>
<li>극대한 효율성과 확장성을 갖게 된다.</li>
</ol>
<p>위의 문제점을 보고나니 저자가 말한대로 <strong>&quot;유토피아&quot;</strong> 적인 상황이 아닐 수 없다.</p>
<p>그리고 저자는 그런 프로젝트들을 경험했다고 자신한다.</p>
<h1 id="what-is-design-and-architecture">What is Design and Architecture?</h1>
<p>부채가 많이 쌓인 개발자들에게 가장 추상적이고 먼 단어가 아닐까 싶다.</p>
<p>그리고 디자인과 아키텍처에 대해 많이들 혼동 했을텐데 두 단어는 큰 차이가 없고 나누는 것이 무의미하다라고 한다.</p>
<p>그래도 굳이 나눈다고 한다면 </p>
<p>디자인은 시스템 설계를 미시적으로 보아 디테일한 부분을 정의한다는 것</p>
<p>아키텍처는 반대로 거시적으로 보아 큰 구조물을 해당하는 것을 정의한다는 것</p>
<p>소프트웨어를 설계하는 데에 있어서는 두 부분 모두 필수적이며 두가지가 긴밀하기 이어진다고 한다.</p>
<h2 id="목표는">목표는?</h2>
<p>그 아키텍처의 목표는 만들고 발전시켜나갈 시스템에 필요 인력을 최소화하는데에 있다.</p>
<h2 id="케이스-스터디">케이스 스터디</h2>
<p>저자는 여러 실제 회사들의 사례들을 보여주며 개발자의 수는 점점 늘어나는데 그에 반해 생산성은 급속도로 떨어지는 것을 증명한다.</p>
<h2 id="결론">결론</h2>
<p>결론은 당연하게도 소프트웨어의 품질을 높이는 것만이 이 문제를 해결 할 수 있는 방법이라고 이야기를 한다.</p>
<h1 id="a-tale-of-two-values">A Tale of Two Values</h1>
<p>개발자에게 있어서 두 가지의 가치가 있다고 한다.</p>
<ol>
<li><p>행동</p>
<p> 프로그래머는 어떤 제품을 만들어 가치를 창출해야만 한다. </p>
<p> 사업측의 요구사항에 맞추어 제품을 만들어낸다.</p>
<p> 많은 잘못된 개발자들이 이것을 개발자의 주된 업무라고 생각한다.</p>
</li>
<li><p>구조</p>
<p> Software에서 ware는 제품을 의미하며, Soft가 즉 두번째 가치에 해당.</p>
<p> 소프트웨어에서 변경은 쉬워야한다. 그렇지 못하면 hard ware가 아닌가.</p>
<p> 특정 요구사항이 있으면 그 요구사항의 범위에 의해서만 작업의 비용이 결정되어야 하며,</p>
<p> 요구사항으로 인해 소프트웨어의 구조가 변경되어서는 안된다.</p>
<p> 아키텍처가 어떠한 형태에 포함되거나 그곳에 종속되어서 요구사항을 점점 맞추기 힘들어지고 그 기존의 어떠한 형태도 점점 잃어 갈 수 있어 두번째 가치를 잃게 될 수 있다.</p>
</li>
<li><p>더 중요한 가치</p>
<p> 옛날의 나에게는 더 중요한게 무엇이냐 한다면 제품을 만들어 내는 것이다.</p>
<p> 쉽게 그렇게 생각했던 이유는 결국 개발도 서비스나 제품을 만들기 위한 것이며, 서비스가 존재해야 그 제품을 만들어가는 개발자들도 계속해서 필요하다고 생각했기 때문이다. </p>
<p> 하지만 이곳에서 저자는 사업의 요청사항에 의해 급급하게 기능구현만을 하게 된다면 다음 요청사항에 대해서 변경이 불가능한 경우가 생긴다고 했다. 그 경우는 <strong>변경으로 인해 얻는 이익보다 변경을 하기 위해 필요한 비용이 커질 때이다.</strong> </p>
<p> 저자는 여기서 프로그래머가 그 구조를 지켜내야한다고 이야기한다.</p>
</li>
<li><p>아키텍처를 위한 투쟁</p>
<p> 소프트웨어 아키택처를 지켜내는 일은 개발자의 책무이며, 이것을 위해 기능구현을 우선순위로 하는 것들과 싸워야 한다고 한다.</p>
<p> 사실 나도 이전까진 사업이 더 중요하지... 개발이 더 중요해? 이러한 생각을 가지면서 위의 생각을 완벽하게 공감할 수 없었다. 하지만 아래의 생각들을 가지게 되면서 저자의 생각에 공감하게 되었다.</p>
<p> 내가 이것을 이해하게 된 생각은 각 포지션 별로 중요하게 보아야 할 것들이 다르다는 것이다.</p>
<p> <strong>공통의 목표로 나아가지만 중요하게 보아야 할 것들은 다르다.</strong></p>
<p> 마케팅팀도 투쟁한다.</p>
<p> 어떻게든 최고로 많은 유저 유입을 위해서 최대한 많은 마케팅 비용을 집행하려고 노력한다.</p>
<p> 경영팀도 투쟁한다.</p>
<p> 어떻게든 운영 비용을 감소시켜 때론 직원들의 불편함을 만들면서도 회사가 이익이 날 수있도록 노력한다.</p>
<p> 개발팀도 투쟁해야한다.</p>
<p> 어떻게든 사업측의 요구를 빠르고 낮은 리소스를 활용해 받을 수 있도록 아키텍처를 보존하는 노력.</p>
<p> 더 드는 생각이지만 이런 구조가 이루어지기 위해선 각자 다른 포지션의 팀원들을 신뢰할 수 있는 문화가 뒷받침 되어야 한다고 생각까지 들었다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[RxCocoa]]></title>
            <link>https://velog.io/@elile-e/RxCocoa</link>
            <guid>https://velog.io/@elile-e/RxCocoa</guid>
            <pubDate>Mon, 15 Feb 2021 13:49:06 GMT</pubDate>
            <description><![CDATA[<p>RxCoocoa는 &quot;UIKit 및 Cocoa 개발을 지원하는 Rx 클래스, RxSwift의 확장&quot; 정도로 생각하면 좋겠다.</p>
<p>아래 간단한 두개의 예시로 Rx로 UI를 더 간결하게 처리 할 수 있는 기능들을 보여주고자 한다.</p>
<h2 id="uibutton">UIButton</h2>
<pre><code class="language-swift">//기존 우리가 UIButton에 touchUpInside이벤트를 처리하는 방법
@objc func onClickButton(_ sender: UIButton) {
        //버튼 엑션    
}

self.someButton.addTarget(
    self, 
    action:#selector(self.onClickButton(:_), 
    forControlEvents: .touchUpInside
)

//RxCocoa를 사용한 처리방법
self.someButton.rx.tap
        .bind { _ in
                //버튼 액션
        }.disposed(by: self.disposeBag)</code></pre>
<p>이전과 비교해 항상 직관적이지 못했던 addTarget이라는 과정을 setUp이나 viewDidLoad 등에서 해주었다.</p>
<p>보다 코드를 더 잘 분리할 수 있는 도움을 주지 않을까 생각하게 된다.</p>
<h2 id="uitableview">UITableView</h2>
<pre><code class="language-swift">//기존의 UITableView
extension ViewController: UITableViewDataSource {
//데이터소스 구현
}

extension ViewController: UITableViewDelegate {
//델리게이트 구현
}

func viewDidLoad() {
        self.tableView.delegate = self
        self.tableView.dataSource = self
}</code></pre>
<p>Rx를 사용하지 않는 UITableView에서는 항상 Delegation pattern으로 구현을 해주어야 했다.</p>
<p>RxCocoa에서 지원하는 bind 기능을 통해서 아래와 같이도 구현할 수 있게 된다.</p>
<p>DataSource의 기능을 대체할 수 있다.</p>
<pre><code class="language-swift">let cities = Observable.of([&quot;Lisbon&quot;, &quot;Copenhagen&quot;, &quot;London&quot;, &quot;Madrid&quot;, &quot;Vienna&quot;]) 

cities.bind(to: tableView.rx.items) { (tableView, index, element) in 
    let cell = UITableViewCell(style: .default, reuseIdentifier: &quot;cell&quot;) 
    cell.textLabel?.text = element 

    return cell
}.disposed(by: disposeBag) </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Scheduler]]></title>
            <link>https://velog.io/@elile-e/Scheduler</link>
            <guid>https://velog.io/@elile-e/Scheduler</guid>
            <pubDate>Mon, 15 Feb 2021 13:46:20 GMT</pubDate>
            <description><![CDATA[<p>기본적으로 RxSwift에서 Scheduler는 멀티쓰레딩. </p>
<p>즉, 병렬작업을 하는 기능 객체이며, 기존에 우리가 알던 큐를 매핑하는 기능이다.</p>
<p>많은 Rx를 처음 공부하는 분들이 observeOn과 subscribeOn 두가지가 있는데, 이 두가지의 차이점</p>
<p>그리고 언제써야하는지 등...</p>
<p>여기서 많은 어려움을 겪는 것 같고 나도 처음 마주했을땐 아리송 했다.</p>
<p>알 것 같다가도 모르겠는</p>
<p>아래의 포스트가 많은 도움이 되어 포스트한다.</p>
<p><a href="http://rx-marin.com/post/observeon-vs-subscribeon/">observeOn vs. subscribeOn</a></p>
<p>처음에 내가 접했던 오류는 subsctibeOn은 subscribe 클로저에서 실행 할 것을 정하는게 아니야?</p>
<p>라고 생각했지만 그게 아니였다.</p>
<p>아래를 명확히 기억하면 이해하기 쉬울 것 같다</p>
<p>observeOn은 어떤 큐에서 관찰된 값을 처리할지.</p>
<p>subscribeOn은 어떤 큐에서 값을 가져오는 과정을 처리할지.</p>
<p>위와 같이 생각하면 쉽게 생각할 수 있을 것 같다.</p>
<p>그럼 이제 코드로 한번 보자.</p>
<p><img src="https://images.velog.io/images/elile-e/post/4914f189-c0ca-4ed4-bda7-c278f3c4038a/_2020-11-02__12.34.01.png" alt=""></p>
<p>observeOn은 아래인 관찰된 값을 처리하는 과정에 영향을 미치고 스케쥴러에서 메인큐에서 처리를 할 수 있도록한다.</p>
<p>연산자는 여러번 동작이 될 수 있기 때문에 observeOn은 당장 아래에 있는 &#39;다운 스트림&#39;에 영향을 미친다.</p>
<p>또 동작하는 연산자마다 다른 큐에서 처리하고 싶을 수 있으므로 여러개의 observeOn을 가질 수 있다.</p>
<p>subscribeOn은 값을 가져오는 과정인 생성 단계에 영향을 미치고 백그라운드로 처리를 할 수 있도록  한다.</p>
<p>값을 가져오는 생성 단계는 한번만 있을 수 있으므로 최초 한번 호출되는 subscribeOn만 유효하게 된다.</p>
<p>많은 사람들이 subscribeOn은 위에만 영향을 미치고 observeOn은 아래만 영향을 미친다는 말을 해서 그 부분에서 명확히 이해되지 않았지만 생성과정, 처리과정을 나누어 생각하니 쉽게 이해할 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Operators]]></title>
            <link>https://velog.io/@elile-e/Operators</link>
            <guid>https://velog.io/@elile-e/Operators</guid>
            <pubDate>Mon, 15 Feb 2021 13:44:41 GMT</pubDate>
            <description><![CDATA[<p>RxSwift 는 Observables를 잘 활용하고 편리하게 다루기 위해</p>
<p>다양한 Operators들을 제공한다.</p>
<p>Operators가 너무 많기  때문에 타입별로 자주 사용하게 될 것 같은걸 몇개씩만 정리해보려고 한다.</p>
<p>모든 내용은 아래의 공식 Docs에 있으니 첨부한다.</p>
<p><a href="http://reactivex.io/documentation/operators.html">ReactiveX - Operators</a></p>
<h2 id="creating">Creating</h2>
<pre><code class="language-swift">//Create
//가장 기본적인 생성 메서드로 아래와 같은 예시로 Observable을 생성 가능하다.
Observable.create() { emitter in
        //아래와 같이 데이터를 발생
        emitter.onNext(&quot;Something&quot;)

        return Disposables.create()
}

//Just
//단일의 이벤트를 방생시켜,
//간결하게 한개만 데이터를 넣고 싶을 때 사용
Observable.just(&quot;just one&quot;)

//From
//한번에 여러개의 이벤트를 전달한다. ex) 배열 등
Observable.from([1, 2, 3])</code></pre>
<h2 id="transforming">Transforming</h2>
<p>발생되는 이벤트의 값을 변경시켜주는 Operators</p>
<pre><code class="language-swift">let numberOb = Observable&lt;Int&gt;.just(10)
//이벤트 값을 String으로 변경해줌
let stringMap = numberOb.map { String($0) }

stringMap.subscribe(onNext: { event in
    // event는 String으로 내려오게 됨
    print(event)
}).disposed(by: disposeBag)</code></pre>
<h2 id="filtering">Filtering</h2>
<p>발생하는 이벤트들을 선택적으로 발생시키는 Operators</p>
<pre><code class="language-swift">let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9 10]

Observable.from(numbers)
            .filter{ $0.isMultiple(of: 2) }
            .subscribe { print($0) }
//2의 배수만 필터가 되어 아래와 같이 출력된다.

//next(2)
//next(4)
//next(6)
//next(8)
//next(10)</code></pre>
<h2 id="combining">Combining</h2>
<p>한개 이상의 Observable을 한개의 Observable로 </p>
<pre><code class="language-swift">//추후 다룰 내용이지만 아직 값이 없는 Observable 형태
let subject1 = PublishSubject()
let subject2 = PublishSubject()

//of 연산자는 여러개의 값/Observable을 받을 수 있는 생성 연산자
Observable.of(subject1, subject2)
    //받아진 Observable을 merge로 결합    
   .merge()
   .subscribe {
       print($0)
   }

subject1.on(.Next(10))
subject1.on(.Next(11))
subject1.on(.Completed)
subject2.on(.Next(22))
subject2.on(.Completed)

//아래와 같이 차례대로 수행됨
Next(10)
Next(11)
Next(22)
Completed</code></pre>
<h2 id="error">Error</h2>
<p>do try catch와 비슷하며,</p>
<p>Observable가 error로 끝나지 않고 Observable&lt;&gt; 타입을 반환한다.</p>
<pre><code class="language-swift">let observable = Observable&lt;Int&gt;
    .create { observer -&gt; Disposable in
        observer.onNext(1)
        observer.onNext(2)
        observer.onError(NSError(domain: &quot;&quot;, code: 100, userInfo: nil))
        observer.onError(NSError(domain: &quot;&quot;, code: 200, userInfo: nil))
        return Disposables.create { }
}

observable
        //에러가 발생하면 NSError.code의 이벤트를 발생시킨다.
    .catchError { .just(($0 as NSError).code) }
    .subscribe { print($0) }
    .disposed(by: disposeBag)

/* Prints:
    next(1)
    next(2)
    next(100)
        next(200)
    completed
*/</code></pre>
<h2 id="mathematical">Mathematical</h2>
<p>Observable이 배출하는 모든 값을 연산하여 이벤트를 발생시키는 연산자.</p>
<pre><code class="language-swift">//reduce
//Swift의 Reduce와 동일해 별다른 설명은 생략하며, 예시로 확인한다.
Observable.of(1,2,3,4,5).reduce(0,accumulator: +)
    .subscribe(onNext: {
        print($0)
    })

//모든 값을 더 해 이벤트를 발생
//retrun 15
</code></pre>
<h2 id="정리">정리</h2>
<p>RxSwift에서는 다양한 연산자를 제공하며 최소한으로 몇가지만 정리를 해보았다.</p>
<p>물론 공식 docs를 확인하면 수 많은 것들이 있으며, Rx를 사용하면서 때에 필요한 연산자를 찾아 사용하면서 익힐 수 있도록 해야한다.</p>
<p>이번 정리에서는 이런 연산자들이 있으며, 다음부터는 있을 것 같은? 느낌이 들거나 있으면 편하겠다는 생각이 들 때 그때그때 공부하도록 하면 될 듯 하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Observable]]></title>
            <link>https://velog.io/@elile-e/Observable</link>
            <guid>https://velog.io/@elile-e/Observable</guid>
            <pubDate>Mon, 15 Feb 2021 13:41:35 GMT</pubDate>
            <description><![CDATA[<p>먼저 Observable에 앞서 마블 다이어그램을 설명하고자 한다.</p>
<p>Rx를 공부하다보면 아래와 같은 그림을 자주 볼 수 있다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/3255d05f-6410-4ffe-9c26-3a2af78ed21e/_2020-10-30__1.58.31.png" alt=""></p>
<ol>
<li>위에 줄은 새로 들어오는 값이고 왼쪽에서부터 오른쪽으로 흘러간다.</li>
<li>마지막 짝대기는 해당 스트림이 더 안내려온다는 의미.</li>
<li>중간에 박스는 들어오는 값들을 연산하는 연산자.</li>
<li>맨 아래줄은 연산을 통해 내려오는 값들을 이야기한다.</li>
</ol>
<h2 id="나중에-생기는-데이터">나중에 생기는 데이터</h2>
<p>실제로 Observable이나 쉽게 이해하기 위해 &quot;나중에생기는데이터&quot;로 예시를 들어본다.</p>
<pre><code class="language-swift">class 나중에생기는데이터&lt;T&gt; {
  private let task: (@escaping (T) -&gt; Void) -&gt; Void

  init(task: @escaping (@escaping (T) -&gt; Void) -&gt; Void) { 
    self.task = task
}

  func 나중에오면(_ f: @escaping (T) -&gt; Void) {
    task(f)
  }
}

func downloadSomething() -&gt; 나중에생기는데이터&lt;String?&gt; {
  //생성 시점에 비동기 코드를 넣어준다.
  return 나중에생기는데이터() { f in
    //비동기처리
    //나중에 왔다는 가정
    f()
  }
}

func load() {
  let data = downloadSomething()
  data.나중에오면 { json in
            //ui 처리등
  }
}</code></pre>
<p>위에 있는 내용이 Rx내용의 핵심이며</p>
<p>Rx내용의 전부라고 생각한다. </p>
<p>단순히 &#39;나중에생기는데이터&#39;를 Observable로 바꾸어 생각해주면 이해할 수 있게된다.</p>
<p>위의 내용을 실제 Observable로 구현해 보자.</p>
<pre><code class="language-swift">func downloadSomething() -&gt; Observable&lt;String?&gt; {
  return Observable.create() { emitter in
  //비동기처리
  비동기 { response in
      emitter.onNext(data)
      emitter.error(&quot;&quot;)
      emitter.complete()
      //Disposable을 리턴하게 되는데,
      //아래에서 한번 더 정리해보겠다.
      return Disposable.create()
      } 
    }
}

func load() {
  //위의 예시에선 바로 데이터를 내려주었지만 
  //실제 Observable은 event라는 녀석을 내려준다.
  //그곳에 내려오는 데이터 / 에러 / 더이상 내려오지 않는 컴플릿까지 상태를 내려올 수가 있다.
  let _ = downloadSomething().subscribe { event in
    switch event {
    case let .next(json):
    //내려오는 값
    case .completed:
    break
    case .error:
    break
    }
    }
}</code></pre>
<h2 id="disposable">Disposable</h2>
<p>단어를 번역하면 &quot;처분할 수 있는&quot;이란 단어인데, </p>
<p>이 녀석은 더 이상 구독을 하지 않을때, 구독을 중단하고 싶을 때 사용을 하게된다. </p>
<p>안한다면 메모리릭이 생긴다.</p>
<p>실제로 ViewController가 해제하거나 닫을 때 이런 처리를 하게될 때가 가장 많은 사용케이스가 될 것 같다.</p>
<p>아래로 dispose하는 예시를 보자.</p>
<pre><code class="language-swift">import RxSwift

class SomeViewController: UIViewController {
//이 DisposeBag은 Disposable들을 담을 수 있는 클래스이다.
//해당 클래스가 메모리에서 해제되면 가방안에 있는 모든 Disposable들도 같이 해제된다.        
    let disposeBag = DisposeBag()
    override func viewDidLoad() {
    super.viewDidLoad()

        Observable.of(&quot;A&quot;, &quot;B&quot;, &quot;C&quot;)
            .subscribe {
                    print($0)
                }
        .disposed(by: disposeBag)
        //위의코드로 Disposeable을 담아둔다.
        }
     }

}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[FRP - Funcional Reactive Programming]]></title>
            <link>https://velog.io/@elile-e/FRP-Funcional-Reactive-Programming</link>
            <guid>https://velog.io/@elile-e/FRP-Funcional-Reactive-Programming</guid>
            <pubDate>Mon, 15 Feb 2021 13:31:24 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.youtube.com/watch?v=cXi_CmZuBgg&amp;feature=youtu.be">곰튀김님의 FRP세션을 기반으로 공부하였습니다.</a></p>
<p>최근 몇년간 iOS 개발자들 사이에서는 가장 핫하게 차지하는 토픽이 RxSwift 였습니다.
많은 컨퍼런스에서 iOS 세션에서 발표되는 내용 역시도 Rx에 관한 것임을 쉽게 볼 수 있었죠.</p>
<p>외쳐 RxSwift의 시대 였던 것 같습니다.</p>
<p>그래서 그동안 엿보고만 있었지 공식 튜토리얼에 들어가더라도 쉽게 이해가 되지 않았던게 상황이었습니다.
RxSwift는 훌륭하지만 가장 큰 단점이 러닝커브가 높다는 것이죠.</p>
<p>그러니까 나중에 봐야지 고이고이 모셔두다가 이번에 회사에서 Rx를 도입하면서 공부한 내용들을 적으려고 합니다.</p>
<p>가장 먼저 집중했던 부분은 
&quot;그래서 Rx가 왜 필요한데?&quot; 
일단 공부하는 첫 시작에서 RxSwift가 왜 필요한지에 대한 이야기 먼저 해보려고 한다.</p>
<p>그러나 그전에 알아야 할 것이 있습니다.
RxSwift를 알기 위해선 Reactive Programming을 알아야 합니다.
Reactive Programming을 알기 위해선 Functional Programming을 알아야 합니다.
Functional Programming을 알기 위해선 Declarative(선언형)과 Imperative(명령형) Programming을 알아야 합니다.
ㅎㅎㅎㅎ.....</p>
<p>차근차근 알아가보도록 합시다.</p>
<h2 id="why-functional">Why Functional?</h2>
<p>순서상으론 선언형과 명령형을 알아야하겠지만 필요성에 대해서는 Functional이 먼저일 것 같습니다.</p>
<ol>
<li>무어의 법칙은 깨졌지만 풍부한 메모리와 CPU처리 성능을 가지게 되었습니다.</li>
<li>그를 기반으로 병렬처리 또는 동시성으로 실행되는 프로그램이 만들어지게 되었습니다.</li>
</ol>
<p>이런 배경에서 문제가 생겨났습니다. 
동시성으로 여러 인스턴스에서 하나의 데이터에 접근한다고 했을 때, 읽을 때 문제는 되지 않지만 새 값을 쓰게 될 때 기대하는 값이 나오지 못하는 문제가 있었습니다.</p>
<p>실행되는 순서에 따라 다른 인스턴스에서 기대하지 않던 값을 써버린 다던가하는 문제 말이죠.
그러면서 많은 버그를 초래하며, 위험성이 높은 프로그램이 발생을 했다고 합니다.</p>
<h2 id="whats-functional-programming">What&#39;s Functional Programming</h2>
<p>Functional Programming은 위에서 다룬 문제를 해결하기 위해서 태어났습니다.</p>
<p>목적이라고 한다면 위들의 문제들을 해결하면서 더 가독성 높고 간결한 코드를 만드는 것 입니다.
Functional Programming은 아래와 같은 기능으로 위의 목적을 실현하고자 합니다.</p>
<h3 id="immutable">Immutable</h3>
<p>값이 변하는게 무서우니까 그냥 값을 못바꾸게 만들자:)
그래서 사용되는게 var 구문이 아닌 let 구문이죠.</p>
<p>그럼 변하는 데이터는 어떻게 처리해?
메모리가 빵빵하니까 그냥 필요할 때 새로 만들어 쓰자~</p>
<p>그렇게 데이터 불변성을 보장하기 되었습니다.</p>
<h3 id="pure-function">Pure Function</h3>
<p>다음은 순수한 함수라고 하는데요.
왜 필요할까요?</p>
<p>그것은 Side Effects 때문인데요.
즉, 함수의 scope 밖으로 영향을 끼치지 않는 함수를 뜻합니다. 아래와 같은 규칙들을 가집니다.</p>
<ul>
<li>순수함수는 입력(parameters)으로 주어진 것 외의 연산은 실행하지 않는다.</li>
<li>순수함수는 side Effects가 없어야 한다.</li>
<li>입력이 동일하면 출력이 동일해야한다.</li>
<li>상태의 변화가 없어야한다.</li>
</ul>
<p>그럼 코드로 잠깐 볼게요.</p>
<pre><code class="language-swift">var value = 10

func addValue(_ addValue: Int) {
    value += addValue
}

addValue(10)</code></pre>
<p>위의 함수는 순수함수가 아닙니다.
scope 밖의 상태를 바꾸고 있으니까요.</p>
<p>저기서 함수 2번을 실행하면 결과물이 동일 할까요?
아닙니다, 두번을 하면 30이라는 결과가 출력되겠죠.</p>
<p>그럼 순수함수를 한번 봅시다.</p>
<pre><code class="language-swift">func addTwoValue(a: Int, b: Int) -&gt; Int {
    return a + b
}

addTwoValue(a: 1, b: 2)
//3 출력

addTwoValue(a: 1, b: 2)
//3 출력
</code></pre>
<p>네, 이게 순수함수라고 합니다.</p>
<h3 id="first-class-citizen">First Class Citizen</h3>
<p>함수는 1급 객체에 해당하게 합니다.
함수가 1급 객체란 아래와 같은 조건을 충족해야합니다. </p>
<ul>
<li>변수나 데이터 안에 담을 수 있다.</li>
<li>함수의 파라미터로 전달할 수 있다.</li>
<li>반환값으로 사용할 수 있다.</li>
<li>할당에 사용된 이름과 고유한 구별이 가능하다.</li>
<li>동적으로 프로퍼티 할당이 된다.</li>
</ul>
<p>Swift에서 함수는 1급 객체이다.</p>
<h3 id="function-composition">Function Composition</h3>
<p>함수를 결합해서 사용할 수 있다.</p>
<pre><code>func getTen() -&gt; Int {
    return 10
}

func addTwo(a: Int, b: Int) -&gt; Int {
    return a + b  
}

func output(value: Int) {
    print(&quot;\(value)&quot;)
}

output(value: addTwo(a: getTen(), b: getTen())))</code></pre><h3 id="high-order-function">High Order Function</h3>
<p>간단하게는 Swift의 Closure에 해당</p>
<ul>
<li>함수에 함수를 파라미터로 전달하는 함수</li>
<li>함수의 반환으로 사용하는 함수</li>
</ul>
<h3 id="declarative선언형">Declarative(선언형)</h3>
<p>기존에 우리가 알고 있던 코드에 작성은 위에서 아래로 if와 for 같은 조건문들을 걸어 프로그램을 명령에 따라 돌아가게 됩니다.</p>
<p>어떤 목적을 수행하기까지에 How에 입각해서 시간순서대로 명령으로 프로그래밍하는 것이 기존에 우리가 하는 방식이었죠.
데이터를 어떻게 바꿀까 하는 과정들을 써내려가는 코딩입니다.</p>
<p>하지만 함수형 프로그래밍에서는 이런 명령형의 방식이 아닌 선언형의 프로그래밍을 하게 됩니다.
what에 입각해서 무엇을 할지 기술에 초점을 맞추는 코딩방식 입니다.</p>
<p>기존보다 코드스럽기보단 조금 더 자연어와 가깝다는 생각이 들며, 그렇게 되어 가독성도 높아지며 더 간결해집니다.</p>
<p>이 선언형 프로그래밍은 함수형의 위 기능들로 가능하게 합니다.</p>
<p>간단하게 예시를 보자면 가장 크게는 아래와 같습니다.</p>
<pre><code class="language-swift">var numbers = [1, 3, 5, 6, 10, 7]

// Imperative
var newNumbers = [Int]()

for number in numbers {
    if number % 2 == .zero {
        newNumbers.append(number)
    }
}

// Declarative
newNumbers = numbers.filter { $0 % 2 == .zero }</code></pre>
<p>그냥 코드줄인거 아니야? 라고 말하겠지만
for문을 돌린다는 것은 데이터를 다루는 과정으로 읽혀서
&quot;numbers 돌면서 2로 나눈 나머지가 0인 아이들을 찾는다&quot;</p>
<p>filter라는 고차함수를 사용했기 때문에 
&quot;2로 나누애를 zero인 애들만 filter를 할거야.&quot;
라는 선언, 목표를 보여주게 된다.</p>
<p>이것이 선언형과 명령형 언어 패러다임의 차이입니다.
아마 기존 코딩에서 생각의 전환이 필요한 방법입니다.</p>
<h2 id="functional-concept-to-async">Functional Concept to Async</h2>
<h3 id="issue-before-reactivce">Issue before Reactivce</h3>
<p>우리는 기존에 비동기 처리를 하기 위해서 delegate pattern 또는 @escaping 함수를 closure로 전달해 해결하곤 했습니다.
아래와 같이요.</p>
<pre><code class="language-swift">class API {
  static func getSearchResult(_ item: String, completion: @escaping(_ result: [Model]) -&gt; Void) {
      Alamofire.request(url, method: .get, headers: header).responseArray { response in
        completion(response.result)
      }
  }
}


func loadSearchResult(_ word: String) {
  API.getSearchResult( word ) { response in

  }
}</code></pre>
<p>그렇지만 이 방식은 코드를 읽고 유지하는데에 큰 리소스를 쓰게 됩니다.
이리저리 돌아가며 그 코드를 읽어야하기 때문이죠.</p>
<p>곰튀김님은 시선이 분산된다고 설명을 해주신 부분이 있는데, 아마 그게 이 내용이지 않을까 싶습니다.</p>
<h3 id="what-is-reactive">What is Reactive</h3>
<p>그래서 훌륭한 우리의 개발자들은 이것을 해결하기 위해 아이디어를 냅니다.
async한 처리에서도 functional 하게 사용하자는 것 입니다.</p>
<p>그 방법은 아래와 같습니다.
stream이라는 비동기 데이터 흐름을 만들고 그것에 data를 흘려 보내는 것이죠.
흘러오는 데이터를 사용할 수 있도록 하는 것 입니다.</p>
<p>그리고 그 Reactive하게 Swift를 사용할 수 있게해주는 라이브러리가 RxSwift 입니다.</p>
<p>그럼 다음장부터 RxSwift를 알아보도록 합시다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift Lint]]></title>
            <link>https://velog.io/@elile-e/Swift-Lint</link>
            <guid>https://velog.io/@elile-e/Swift-Lint</guid>
            <pubDate>Fri, 12 Feb 2021 04:08:21 GMT</pubDate>
            <description><![CDATA[<h2 id="lint">Lint?</h2>
<p>스웨더의 보풀 같은 것을 보고 Lint라는 의미를 가진다.
해당 내용을 코드에서는 이런 내용이 뭘까. 아래 같은 것들이 있을 것이다.</p>
<ol>
<li>맞지 않는 들여쓰기</li>
<li>사용되지 않은 변수</li>
<li>한줄이 너무 길어진 구문
등등</li>
</ol>
<p>잘 정돈 되어진 코드를 보는 것과 그렇지 않은 것들은 얼마나 많은 차이가 있는지는 많은분들이 공감을 하리라고 생각한다. (요즘의 코딩에는 제품의 효율성보다 가독성이 더 중요시되는 부분도 존재한다)</p>
<p>내가 아무리 이것을 의식하여 쓴다해도 human-error는 존재할 수 밖에 없다.
컴파일시에 이런 것들을 찾아 알려줘 알려주는 기능을 담은 것이 Lint이다.</p>
<p>IDE에서 어느정도 제공을 하지만 더 읽기 좋은 코드를 쓰기 위한 개발자들은 여기서 만족하지 못한다.
그렇기에 외부의 라이브러리들을 자주 사용한다.</p>
<h2 id="code-convention">Code Convention</h2>
<p>직역하면 코드에 대한 규약.
위의 Lint외에도 한 조직에서 협업을 위해서는 서로 공유할 수 있는 Convention을 만들어, 누가 작업을 하더라도 쉽게 읽을 수 있다는 것은 꼭 필요한 내용한 내용일 것이다.</p>
<p>뭐 이런 것들이 Convention이 될 수 있겠죠.</p>
<ol>
<li>최대 함수 구문의 길이</li>
<li>함수/변수명에 생성 규칙</li>
<li>들여쓰기 길이</li>
<li>Snake case or Camel case
등등</li>
</ol>
<p>기본적으로 각각 언어에서 지원하는 convention이 있으며, 그것을 토대로 조직에 맞는 컨벤션을 공유해 사용하는 것이 중요하다.</p>
<p>아래는 Swift를 사용하는 이들에게 많은 도움이 될 것 같아 첨부한다.
<a href="https://google.github.io/swift/">Swift Style Guideline</a></p>
<h2 id="swift-lint">Swift Lint</h2>
<p>이제 이 글을 작성한 이유인 Swift Lint를 소개하겠다.
Realm에서 제공하는 Swift 사용자를 위한 Lint Library이다.</p>
<p><a href="https://github.com/realm/SwiftLint">라이브러리 사용법</a></p>
<p>CocoaPods로 쉽게 설치할 수 있다.</p>
<p>설치 후 간략한 사용법을 간단하게 써보겠습니다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/489759c7-f518-42da-b548-4e244e841a2f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2012.53.13.png" alt=""></p>
<p>Target &gt; Build Phase &gt; + &gt; new run script phase</p>
<p>아래 스크립트 코드 추가</p>
<pre><code>${PODS_ROOT}/SwiftLint/swiftlint</code></pre><h2 id="lint-rule">Lint Rule</h2>
<p>Lint에 어마막지하게 많은 Rule들이 존재하게 되는데, 이 부분에서 적당히 조직에 따라 Code Convention에 맞추어 옵션을 포함/제외하면 된다.
<a href="https://realm.github.io/SwiftLint/rule-directory.html">Swift Lint Rule</a></p>
<p>어떻게 포함 제외하면 된다고?</p>
<p><img src="https://images.velog.io/images/elile-e/post/e0fed84b-ece5-4116-9983-8c03c5ced472/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2012.58.41.png" alt=""></p>
<p>empty file로 .swiftlint.yml 파일을 추가한다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/cba328cf-6a0b-4f16-b904-a2b1676c9d7b/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.00.41%201.png" alt="">
가장 기본적으로 사용 되는것</p>
<p>disabled_rules: 사용 안할 규칙들을 정의
included: 포함 할 파일들을 정의
excluded: 포함하지 않을 파일들을 정의</p>
<p>자세한건 라이브러리 가이드라인에 잘 기입되어 있다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/cf51ce76-3272-4478-8a5a-da3060d70534/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.06.25.png" alt=""></p>
<p>그렇게 빌드를 돌려보면 나의 과오들이 Warning 과 Error로 나타날 것이다.
몇번 쓰다보면 노란딱지를 보기 싫어서 의식해서 코드를 짜게되는 나를 볼 수 있을 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[R.Swift]]></title>
            <link>https://velog.io/@elile-e/R.Swift</link>
            <guid>https://velog.io/@elile-e/R.Swift</guid>
            <pubDate>Mon, 08 Feb 2021 14:20:53 GMT</pubDate>
            <description><![CDATA[<p>iOS를 작업해보다보면 리소스 관리에 많은 고민을 하게 된다.</p>
<p>string으로 파일을 상당량 불러오게 된다.</p>
<pre><code class="language-swift">
let icon = UIImage(named: &quot;settings-icon&quot;)
let font = UIFont(name: &quot;San Francisco&quot;, size: 42)
let color = UIColor(named: &quot;indicator highlight&quot;)
let viewController = CustomViewController(nibName: &quot;CustomView&quot;, bundle: nil)
let string = String(format: NSLocalizedString(&quot;welcome.withName&quot;, comment: &quot;&quot;), locale: NSLocale.current, &quot;Arthur Dent&quot;)</code></pre>
<p>이 모든  String들을 어떻게 관리하며, 파일을 한번 바꾸려면 어떻게 한담.
골치도 이런 골치가 없다.
만약 한 파일로 캡슐화를 시켜 관리한다해도 맨날 그걸 열심히 만들고 있자니...</p>
<p>이런 문제를 해결하는 훌륭한 라이브러리가 있었다.</p>
<p>바로바로 R.swift. (Rx나 이런거랑 상관 없음ㅋㅋ)</p>
<p><a href="https://github.com/mac-cain13/R.swift">R.swift Git</a></p>
<h2 id="rswift를-사용하면">R.swift를 사용하면?</h2>
<pre><code class="language-swift">let icon = R.image.settingsIcon()
let font = R.font.sanFrancisco(size: 42)
let color = R.color.indicatorHighlight()
let viewController = CustomViewController(nib: R.nib.customView)
let string = R.string.localizable.welcomeWithName(&quot;Arthur Dent&quot;)</code></pre>
<p>이렇게 편리할 수가.</p>
<h2 id="usage">Usage</h2>
<ol>
<li><p>일단 pod &#39;R.swift&#39; 하고 pod install</p>
</li>
<li><p>아래와 같이 Build Phases를 더해준다.</p>
</li>
</ol>
<p><img src="https://images.velog.io/images/elile-e/post/d79349db-29f8-4dc4-989e-a1b5ab5a303a/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.15.27.png" alt=""></p>
<ol start="3">
<li>빌드를 한번 해준다.</li>
<li>그럼 위에 적은 file path에 파일이 생긴다.</li>
<li>해당 파일을 xcode 동일한 폴더에 import 시켜준다.</li>
</ol>
<p>그러면 리소스 파일을 더해줄 때마다 빌드를 한번씩 해주고 호출해서 사용을 하면 된다.
컴파일 타임시에 생성이 되니 리소스를 수정한다면 꼭 빌드 한번을 돌려주자.</p>
<p>좀 더 깔끔하게 처리를 할 수 있다.</p>
<p>하하하</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Design Pattern]]></title>
            <link>https://velog.io/@elile-e/Design-Pattern</link>
            <guid>https://velog.io/@elile-e/Design-Pattern</guid>
            <pubDate>Mon, 08 Feb 2021 14:01:51 GMT</pubDate>
            <description><![CDATA[<p>디자인 패턴은 개발에 있어서 일반적으로 발생하는 문제를 재사용 가능한 코드로 해결하는 솔루션들이다.
뭐 넓은 의미에서 있어서는 이런 의미를 지니겠고 어떤 수준에서 보느냐에 따라 많은 디자인 패턴이 존재한다.</p>
<p>iOS 아키텍처에 있어서는 일반적으로 View, Model, Business Logic들을 어떤 관계를 어디에 두면서 맺어줄지에 대해서 고민하는 것이다.</p>
<p>앞으로 다룰 대표적으로 많이 사용되고 지지를 받아오는 Pattern들이 있다.
이 밖에도 수 많은 디자인 패턴들이 있음을 잊지 말아야 하며, 정답도 없는 내용들이다.
어떤 제품에선 적합한 패턴들이 있을 수 있고 그렇지 않을 수도 있다.
그러므로 우리가 만들어가는 제품에 가장 적합한 패턴을 도입해야하며, 어쩌면 새로운 패턴을 만들어 낼 수도 있다.
또 이런저런 패턴을 섞어가면서 쓸 수도 있음을 인지해야한다.</p>
<h2 id="mvc-model---view---controller-or-massive-view-controller">MVC (Model - View - Controller or Massive View Controller)</h2>
<p>일단 iOS 의 기본적인 패턴은 MVC 패턴을 염두에 두고 설계가 되어있고 많은 부분들이 mvc로 구현이 되어있다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/62c0e19f-4aa5-4e85-aa5f-ac749770de0f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.57.46.png" alt=""></p>
<p>여러 코드들을 예시로 쉽게 볼 수 있지만 위의 요소로 볼 수 있다.
Model: 비즈니스 로직들을 담고 있으며, 데이터들을 주로 다룬다.
View: 화면 요소를 들고 있으며, UIView로 구성이 되어 있다. (Interface Builder를 사용하는 유저라면 Stroyboard가 되겠다)
Controller: Model과 View를 제어해 적당한 시점에 모델에서 데이터를 불러와 View에 반영해주는 방식이다.</p>
<p>각각 요소들이 소통하는 방식에 제한이 어느정도 있는데, 간단히만 정리를 한다.</p>
<p>View ↔ Controller</p>
<ol>
<li>Controller &gt; View를 직접 들고 있어 곧바로 전달을 하게 되어 직접 제어를 한다.</li>
<li>View &gt; Controller 는 IBOutlet or IBAction 등으로 소통을 하는 방식이 된다.</li>
</ol>
<p>Model ↔ Controller</p>
<ol>
<li>Model &gt; Controller 기본적으로 모델은 컨트롤러에게 직접적으로 접근할 수 없는게 룰이며, Notification이나 Delegate Pattern을 이용해 대화를 한다. </li>
<li>Controller &gt; Model는 직접 들고있어 곧장 호출하거나 접근 할 수 있어 특이한게 없다.</li>
</ol>
<p>매우 간단한 구조이며, 어느정도의 룰이 있긴 하나 위에서 읽어봐서 간단하게 느낄 수 있겠지만 Controller의 역할이 막중하다. 정말 Controller가 다 한다.</p>
<p>그렇기에 너무 많은 코드들이 Controller에 위치해 Massive ViewController라는 말이 생겨났다는....</p>
<p>아마 애플에서도 초기 설계시점에 앱의 생태계나 구현되는 UI들이 이리 복잡해질 줄은 몰랐겠지... </p>
<p>이 문제 역시도 애플에서 인지하고 Swift UI + Combine 결합이 생기면서 어느정도 해결을 하려고 했던 것 같다. </p>
<h2 id="mvp-model---view---presenter">MVP (Model - View - Presenter)</h2>
<p>아마 MVC의 비대함과 길어지는 코드들을 해결하기 위해서 고안된 파생 구조인 것 같다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/48e584fc-3cb0-4698-b0d1-c0dc3f7c8d66/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.58.32.png" alt=""></p>
<p><strong>View</strong>: View + Controller로 생각을 하면 된다.</p>
<p><strong>Presenter</strong>: 비즈니스 로직과 보여지는 값들을 관리 한다.</p>
<p><strong>Model</strong>: 기존의 모델과 동일</p>
<p>MVP의 목적은 굉장히 간단해 보인다.</p>
<p>기존에 우리가 MVC라는 녀석을 많이 사용하면서 문제로 지적되어 왔던 거대한 Controller의 무게를 Presenter를 만들어 나누자는 취지 같아 보인다.</p>
<p>간단한 예로는 아래정도의 코드로 정리할 수 있을 것 같다.</p>
<p><a href="https://medium.com/swlh/simple-mvp-design-pattern-in-swift-3655811e0415">Simple MVP Design Pattern in Swift</a></p>
<p>보면 위의 MVC에 비해 한결 간결해진 모습을 가질 수 있는 것 같다.
모든 책임을 Presenter로 넘겨버려 View의 역할이 굉장히 작아진다.
Massive View Controller를 탈출한다는 얘기. </p>
<p>단점이라면 Presenter와 View의 관계를 맺어주는 과정에 있어서 많은 코드가 필요하다 정도 인 것 같다.</p>
<h2 id="mvvm--model---view---viewmodel">MVVM ( Model - View - ViewModel)</h2>
<p>디자인 패턴을 고민하는 많은 iOS 개발자들에게 선택받는 디자인패턴이 아닐 까 싶다.
그러나 다른 MVx 패턴과는 조금 다르게 Rx를 함께 해야 제대로된 구현이 가능하다.
그래서 러닝커브가 다른 아키텍처를 도입할 때 보다 높다고 볼 수 있다.</p>
<p>그렇지만 그만큼 코드를 나누고 유지보수 가능한 데에 있어서 상당한 이점이 있는 것으로 보여진다.</p>
<p>이제 내용을 보자.</p>
<p><img src="https://images.velog.io/images/elile-e/post/7de6c95a-c7d0-497f-9612-be9885a3eb82/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.59.22.png" alt=""></p>
<p>크게 구성요소는 다른 MVx와 비슷하게 3가지 요소로 구성이 된다.</p>
<p><strong>Model</strong>: 기존 MVx과 같은 역할을 하게 된다.</p>
<p><strong>View</strong>: UIView와 UIViewController 가 이에 해당을 하는데 뷰 구성들을 모두 들고 있다. 또 ViewModel을 소유하며 바인딩 코드를 통해 View에 반영해준다.</p>
<p><strong>View Model:</strong> 데이터를 보여주기 위한 로직과 데이터를 가지고 있다. 특징이란 것이 데이터의 state를 가진다는 것이다. </p>
<p>뭐 위처럼 설명을 했지만 가장 큰 점은 값의 상태변화에 따른 바인딩이 가장 큰 컨셉으로 보여질 수 있다.</p>
<p>이를 통해 비슷한 화면의 ViewModel이라면 View에 따라 매번 ViewModel을 생성하는 게 아니라 다른 화면에서도 재사용을 할 수 있을 것이다.</p>
<p>또한 View 바인딩이라는 적당한 책임을 부여해주는 것 역시 한 몫을 한다고 본다.</p>
<p>위의 바인딩이라는 과정에서  RxSwift의 필요성이 굉장히 커지는데, 기본 iOS에서 사용하려면 Notification 또는 KVO 같은 내용을 사용해야 한다. (그럴바엔 MVVM 안쓰고 만다)</p>
<p>크게 특징을 나누어 본다면</p>
<ol>
<li>적당한 요소간 책임 분리</li>
<li>View Model의 재사용 가능성</li>
<li>더 적은 코드</li>
<li>로직과 뷰의 분할로 테스트 용이성 상승</li>
</ol>
<p>위의 정도로 보며, 많은 개발자들이 선택하는 이유가 되는 것 같다.</p>
<p>좀 단점이 있다면 Massive를 탈출하기 위함이었지만 View Model이 비대해질 수 있다는... </p>
<h2 id="viper">Viper</h2>
<p>우리가 기존에 봐 왔었던 MVx 패턴들을 대체하기 위해서 구현된 디자인 패턴으로 조금 더 많은 책임 분산으로 나뉘어져 있다.</p>
<p>크게 5개의 요소들로 나뉘어져 있으며, 구조는 아래와 같다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/a1de8166-cbf4-4e6a-bb90-dae7591d109e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.00.02.png" alt=""></p>
<p>그림이 이전의 MVx들과 비교해 굉장히 많이 쪼개져 있다.</p>
<p><strong>View:</strong> MVP 와 동일한 정말 View만을 담당한다.</p>
<p><strong>Interactor:</strong> Use case에 따라 데이터를 조작</p>
<p><strong>Presenter:</strong> Interactor에서 데이터를 가져오고, 뷰로부터의 사용자 입력 처리, 뷰에서 보여줄 내용을 정리 </p>
<p><strong>Entities:</strong> 단순 프로퍼티를 정의하는 모델</p>
<p><strong>Router:</strong> 화면을 넘어가는  Navigation 영역을 담당한다.</p>
<p>아무래도 MVx 패턴과 조금 찢어지다 보니 예시 코드들을 보아가면서 해야 이해가 가능할 듯 하다.</p>
<p><a href="https://medium.com/cr8resume/viper-architecture-for-ios-project-with-simple-demo-example-7a07321dbd29">VIPER-Architecture for iOS project with simple demo example.</a></p>
<p>위에 코드들을 보면 알겠지만 분리로서 MVVM에 View Model에 해당 하는 내용이 상당부분이 더 나뉘었으며, Router를 통해서 어디에 둘지 모르는 segue 관리까지 할 수 있다.</p>
<p>Viper에 대해서 느낀점이라면 더 세분화된 책임으로 책임에 따른 코드 나눔이 명확하다는 것이다. </p>
<p>또한 영역별로 기능별로 Test가 든다는 점.</p>
<p>단점은 역시 보다시피 한 화면 기능을 만드는데 5개나 되는 파일을 만들어야 한다는 점....</p>
<p>이것을 관리하고 유지시키는데 또 처음 구축할 때 역시도 기능에 따라 오버헤드가 발생하는 느낌을 받게 될 예정이다.</p>
<p>뭐 아래와 같이 어느정도 기능에 따라 템플릿화 시켜서 생성해주는 도움을 받아 수고를 더는 방법도 있긴하다.</p>
<p><a href="https://github.com/strongself/Generamba">strongself/Generamba</a></p>
<p>그래도 일반적인 단순한 리스트나 뷰가 위주인 서비스에 적합하기 보단 서비스 복잡도가 높아 이렇게 관리하지 않으면 안될 서비스에 적합해 보인다. (아마 필요성을 느끼는 개발자가 찾지 않을까 싶다 ...)</p>
<h2 id="reactorkit">ReactorKit</h2>
<p>사실 ReactorKit의 내용은 디자인 패턴이라기 보단 프레임워크이다.</p>
<p>프레임 워크로 Reactor라는 프로토콜을 따라 일련된 패턴들을 적용시키기에 적합하다.</p>
<p>RxSwift를 기반에 두어 Rx를 시작하는데에도 조금은 쉽게 쓸 수 있는 예시들을 제공한다.</p>
<p>기존 MVVM과 RxSwift의 조합은 상태 관리가 쉽지 않다. 초기화 값을 위해 꼭 BehaviorSubject를 엄청 사용하게되는데 이게 맞나 싶기도 하고, Binding 시점에 이게 View에 있어야 할 코드인가? View Model에 있어야하는 코드인가? 하는 문제 점도 있었는데 구현해야하는 함수를 프로토콜로 강제하면서 이런 문제를 해결해주는 듯 한다. </p>
<p>가장 큰 컨셉은 반응형 단방향 앱을 구현하는 것 입니다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/46fcf87a-d78f-482e-b1a3-6703e04222f9/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2011.01.01.png" alt=""></p>
<p>가장 좋은 문서는 저자의 글을 조회하는게 가장 좋을 것 같다.</p>
<p>국내 개발자가 개발을 해, 한국어 자료가 많고 국내 기업에서도 많이 도입되어 있다는 점도 장점으로 꼽을 수 있을 것 같다.</p>
<p><a href="https://medium.com/styleshare/reactorkit-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-c7b52fbb131a">ReactorKit 시작하기</a></p>
<p>기본적인 컨셉으로</p>
<p>View는 Action을 Reactor로 전달을 하고</p>
<p>Reactor 내의 mutate()에서 비즈니스 로직을 처리
Reactor 내의 reduce()에서 보여질 수 있는 데이터로 처리</p>
<p>후에 State를 업데이트 하는 일관성 있는 단방향 처리가 가능해 굉장히 심플하게 구현이 가능하다는게 큰 장점으로 보인다.</p>
<p>아마 이번 테스트 모앱은 Reactor Kit으로 작업을 해보지 싶어 모앱 모델링이나 설계부분에서 더 자세히 다뤄보려고 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift UI]]></title>
            <link>https://velog.io/@elile-e/Swift-UI</link>
            <guid>https://velog.io/@elile-e/Swift-UI</guid>
            <pubDate>Mon, 08 Feb 2021 13:52:32 GMT</pubDate>
            <description><![CDATA[<p>아마 2-3년? 아마 그보다 더 뒤의 시점에 현재 사용되는 Interface Builder를 대체하는 방향으로 애플이 설정한 것 같다.</p>
<p>당장 사용할 것은 아니지만 미래를 대비하는 점에서 공부를 조금은 해두는게 좋을 것 같아서, 간략하게 스터디 정도만 해보려고 한다.</p>
<p>사실 처음 간단한 예제 코드들을 보고 굉장히 당황했다.</p>
<p>기존 Constraint나 SnapKit으로 이용했던 Constraint 정의 부분도 상당부분 바뀌었다.</p>
<p>웹의 구현 방식을 많이 따라갔다고 하는데 웹을 몰라서...</p>
<h2 id="why-swift-ui">Why Swift UI</h2>
<p><a href="https://velog.io/@idevkang/SwiftUI-VS-UIKit">SwiftUI vs UIKit</a></p>
<p>Swift UI가 왜 만들어졌을까에 대한 질문에 대해선 위의 링크에서 어느정도 해소가 될 수 있을 것 같다.</p>
<p>iOS가 처음 만들어진 2008년 시절엔 2.5G 이동통신세대이며, 대부분의 데이터들이 정적이었을 것 같다.</p>
<p>크게 데이터가 바뀔 일이나 복잡한 화면에 대해서 관계를 생각하지 않아도 됐을 것 같다.</p>
<p>그러나 지금의 앱들에선 한 화면에서 복잡한 뷰로 엄청난 데이터를 보여주는 지금과는 달랐다.</p>
<p>지금의 앱 개발자들은 애플이 디자인한 현재의 아키텍처로 복잡한 앱을 보여주기엔 한계가 있었다.</p>
<p>수천줄의 ViewController를 보는 것은 당연하며 이를 관리하는 것은 굉장히 곤혹스러운 일일 것이다.</p>
<p>이를 해결하기 위해 우리의 iOS 개발자들은 MVP,  MVVM, Viper 등의 디자인 패턴이나 RxSwift, Reactive Swift 등의 비동기 처리방식 등을 고안해 내어 발전해나갔다.</p>
<p>그럼에도 불구하고 애초에 애플이 설계해둔 방향이 바닥에 깔려있다보니 위의 고민들로도 쉽게 해결될 수 없었을 것이다.</p>
<p>또 Interface Builder의 문제들도 있었겠지.</p>
<p>아마 그래서 Swift UI를 만들게 되지 않았을까 싶다.</p>
<p>더 모던한 앱을 만들기 위해 최적화 된 UI 인터페이스 구현 방식과 데이터 바인딩을 가진 Swift UI가 애플의 솔루션이다.</p>
<h2 id="uikit을-대체">UIKit을 대체?</h2>
<p>Swift UI를 조금 봤을 때 가장 많이 가지는 생각이지 않을까 싶다.</p>
<p>개발자 입장에서는 앞으로 애플이 제시한 대로라면 몇년 이후에는 import UIKit을 보지 않게 될 것 같다.</p>
<p>대부분의 UI Components 들이 Swift UI에 1:1 매칭 되는 형식으로 추가가 된다. (ex UITableView → List)</p>
<p>그러나  UIKit은 존재할 예정이다. Swift UI 내부에서는 UIKit을 활용해 구현을 한다고 한다. 즉 UIKit 위에 SwiftUI가 있는 셈이다.</p>
<h2 id="간단한--구현-보기">간단한  구현 보기</h2>
<p><img src="https://images.velog.io/images/elile-e/post/5ee01f29-2c20-4147-8d20-797fa8cfcad7/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.52.52.png" alt=""></p>
<p>기본적인 튜토리얼 부분은 아래 링크 정도면 대충 컨셉에 대해선 이해가 가능 할 것 같다.</p>
<p><a href="https://www.hackingwithswift.com/quick-start/swiftui/building-a-menu-using-list">https://www.hackingwithswift.com/quick-start/swiftui/building-a-menu-using-list</a></p>
<p><img src="https://images.velog.io/images/elile-e/post/667ece8c-176f-4378-aa1e-b1ad70d53900/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.53.46.png" alt=""></p>
<h3 id="1-canvas">1. Canvas</h3>
<p>Canvas라는 기능을 통해 코드로 통해 그려지는 UI를 즉시 볼 수 있는 것도 큰 장점이다.</p>
<p>모든 옵션은 drag&amp;drop 방식으로도 제공이 된다.</p>
<p>더 이상 UI 하나 수정하고 빌드하고 반복하는 답답함은 겪지 않아도 좋을 것 같다는 것... </p>
<h3 id="2-ui-option">2. UI Option</h3>
<p>모든 UI Option들은 체이닝으로 값을 지정해줄 수 있다. 코드 가독성 측면에서도 상당히 예쁘게 보인다.</p>
<h3 id="3-stack">3. Stack</h3>
<p>기존에 AutoLayout으로 Constraint로 지정이 되어 있던 부분들을 Stack으로 해결을 할 수 있을 것 같다.</p>
<p>스택들에 View를 넣고 inset을 설정하는 방식으로 하게 된다.</p>
<p>이 부분이  AutoLayout을 3년간 사용하면서 개발을 해왔던 사람에겐 굉장히 어색한데, 쓰다보면 또 익숙해지겠지... 하고 있다.</p>
<p>위에 some이라고 하는 이상한 키워드가 있는 녀석이 있는데, 요놈은 좀 별도로 정리가 필요할 것 같다.</p>
<p>그렇지만 일단 급하게는 아래 내용정도면 간단한 이해를 할 수 있을 것 같다.</p>
<p><a href="https://usinuniverse.bitbucket.io/blog/some.html">SwiftUI에서 some이 뭘까? - usinuniverse</a></p>
<h2 id="combine">Combine</h2>
<p>Combine은 Apple이 제공하는 Reactive Programming framework 이다.</p>
<p>RxSwift를 어느정도 봤다면 Combine의 기능들을 쉽게 이해할 수 있을 것 같다.</p>
<p>기능 자체도 RxSwift와 사용법이나 개념들이 많은 부분이 대응이 된다. </p>
<p>이 부분도 간단하게 정리할 수 있는 글은 아닌 것 같아 아래 첨부정도로만 참고해보면 좋을 것 같다.</p>
<p><a href="https://blog.gangnamunni.com/post/SwiftUI+CombineQuickLook/">SwiftUI + Combine 핥아보기</a></p>
<p>간단하게 Swift UI를 살펴보고 잠깐 공부를 했는데 조금 적응하다보면 기존에 UI 그리는 것 보다 훨 씬 빠르게 쉽게 만들 수 있을 것 같다라는 생각이 들었다.</p>
<p>SnapKit을 사용하면 UI를 코드로 그릴 수는 있지만 매번 확인 할 때마다 빌드를 해야한다는 점이 굉장히 좋아보였고 조금 더 View부분에 대한 정의를 명확하게 할 수 있게 된다. (기존 ViewController 의 기능을 많이 덜었다).</p>
<p>그리고 퍼포먼스 관련해서도 잠깐 체크를 해보았는데, RxSwift + RxCocoa 의 바인딩 보다 Swift UI + Combine의 기능들이 월등하다고 한다.</p>
<p><a href="https://medium.com/flawless-app-stories/will-combine-kill-rxswift-64780a150d89">Will Combine kill RxSwift?</a></p>
<p>위에서 언급한 바와 같이 당분간은 아니다. 어느정도 레퍼가 쌓이고 실제 프로덕트 수준으로 도입은 몇년이 걸릴테니. </p>
<p>그렇지만 Apple 생태계에 있어서 괜찮은 변화이며, 많은 발전들이 있는 패러다임의 변화인 것 같다.</p>
<p>(추가로 웹 개발자들의 iOS 개발 진입 장벽도 어느정도 해소하는 느낌?)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Thread Managing (GCD)]]></title>
            <link>https://velog.io/@elile-e/Thread-Managing-GCD</link>
            <guid>https://velog.io/@elile-e/Thread-Managing-GCD</guid>
            <pubDate>Mon, 08 Feb 2021 13:49:12 GMT</pubDate>
            <description><![CDATA[<p><a href="https://jinshine.github.io/2018/07/09/iOS/GCD(Grand%20Central%20Dispatch)/">[iOS] GCD(Grand Central Dispatch)</a></p>
<p><a href="https://zeddios.tistory.com/519">iOS ) 왜 main.sync를 하면 안될까</a></p>
<h2 id="background">Background</h2>
<p>Multi-Thread를 처음 접하게 됐던 때는 REST API를 처음으로 작업을  할 때이다.</p>
<p>가뜩이나 처음 API를 작업해보는데 생각보다 CallBack이 오래걸리는 API 작업이었다.</p>
<p>나는 당연히 ViewController내에 API 호출 함수를 만들고 그를 호출해 데이터를 바인딩 시켜주었다.</p>
<p>viewWillAppear에서 함수를 호출했는데 화면이 너무 느리게 뜨는게 아닌가. 그때 이게 멀티쓰레딩이 필요한 순간이 아닌가?라고 생각하며 직감했다.</p>
<ol>
<li>iOS에서 UI는 main이라는 것에서만 돈다는 것은 들었던 것 같고</li>
<li>ViewController는 당연히 main일테고</li>
<li>API가 콜백이 올때까지 main은 그것을 기다리며 멈춰있을테니까...</li>
</ol>
<p>그때 나는 처음 iOS multi thread를 처음 찾아 보았다.</p>
<h2 id="gcd">GCD</h2>
<p>iOS에서는 Grand Central Dispatch(GCD)라는 것을 통해 Threading작업을 할 수 있다고 하는데, 사실상 우리가 직접 iOS에서 Thread를 다루는 것이 아니라 Queue에 올려둬 iOS에게 관리와 실행을 넘겨주는 api인 것이다.</p>
<p>이전엔 직접 Thread와 OperationQueue등으로 직접 수행을 했다고하는데 코드도 복잡해지고 굉장히 무거웠다고 한다(들었을뿐)</p>
<p>아무튼 Apple 문서에서는 GCD를 통해서 작업을 하라고 권장하고 있다.</p>
<h1 id="2가지의-dispatchqueue">2가지의 DispatchQueue</h1>
<p>GCD 컨셉에서 가장 핵심적인 개념이다.</p>
<p>Queue: </p>
<p>Task를 FIFO순으로 가지고 있는 대기열이며, 이곳에 올려두면 iOS에서 알아서 Task를 가져다 진행을 한다. 실제로 Thread = Queue는 아니다. Queue에 올려두면 어떤 Thread에서 할지는 iOS가 결정하고 책임을 진다.</p>
<p>DispatchQueue:</p>
<p>iOS의 Queue에 작업을 전달하는 방법. Task를 Block 단위로 묶어 간편하게 클로저로 전달을 할 수 있다.</p>
<pre><code class="language-swift">//Dispatch Queue에서 전달 방법
DispatchQueue.main.async {
    //해당 Queue에서 진행할 작업.
}</code></pre>
<h2 id="serial-queue">Serial Queue</h2>
<p>Queue에 추가된 순서대로 한번에 한개씩의 Task를 관리함</p>
<p>iOS가 실행될 때 기본으로 생성이 되는 Main Queue가 Serial으로 구현이 되어 있다.
<img src="https://images.velog.io/images/elile-e/post/80eef51c-28c2-4642-ad25-8c92324ee6fe/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.47.20.png" alt=""></p>
<h2 id="concurrent-queue">Concurrent Queue</h2>
<p>Concurrent는 병렬로 작업을 처리하는 방식인데 이는 실제 물리적인 thread 병렬처리와 다르다.</p>
<p>사실 한개의 Thread에서 
1작업 잠깐
2작업 잠깐
이런식으로 처리를 하는 방식으로 구현이 되어있다.</p>
<p>Queue이기 때문에 실제로 어떤 Thread에서 작업을 하는지에 대한 것은 모른다. iOS 에서 관리를 하기 때문에 그때그때 다를 수도 있고.</p>
<p>Queue를 다른 곳에서 실행한다고 해도 같은 Thread에서 수행이 될 수 있다는 말이다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/add2be84-8c7e-4552-ae42-46c1b9615c29/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-02-08%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%2010.47.57.png" alt=""></p>
<h3 id="global-queue">Global Queue</h3>
<p>UI작업을 제외한 시간이 오래걸리거나 메인에서 자주 사용하지 않는 작업은 Global로 빼서 작업을 한다.</p>
<p>Global Queue는 Concurrent Queue이며, Qos(Quality of Service)로 우선순위를 지정해줄 수 있다.</p>
<p>우선순위의 내용은 아래와 같다.</p>
<p><img src="https://images.velog.io/images/elile-e/post/c40e2680-9ba6-44e5-b210-47fd34a7baac/_2020-11-23__2.51.26.png" alt=""></p>
<p>아래와 같이 사용 할 수 있다.</p>
<pre><code class="language-swift">DispatchQueue.global(qos: .userInitiated).async {
        // 작업할 내용
}</code></pre>
<h1 id="sync와-async">Sync와 Async</h1>
<p>사실은 sync와 Async의 차이를 기존의 병렬처리와 잘못 이해하고 있었으며, 이번 스터디를 통해 가장 크게 느낀 부분이다.</p>
<p>Sync: 어떠한 작업을 Queue에 올려 놓으면 해당 작업의 결과나 완료 이후에 다음 코드를 실행할지 말지를 결정하는 것.</p>
<p>Async: 어떠한 작업을 단지 Queue에 올려두기만 하는 것. 작업에 완료에 대한 보장이나 기다림 같은 것은 없다.</p>
<p>그러므로 Queue에 따라 총 4개의 케이스가 나올 수 있다.</p>
<ol>
<li>Main - async</li>
<li><strong>Main - sync (금기 사항이다) 이유는 상단 링크 참조</strong> </li>
<li>Global - async</li>
<li>Global - sync</li>
</ol>
<p>아마 가장 쉽게 마주하게 되는 것은</p>
<p>Global - async 조합을 가장 많이 쓰게 될 것 이며, 해당 콜백을 UI에서 반영하기 위해서 Main - async를 통해 UI에 반영하는 방식이 가장 일반적이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[API 호출]]></title>
            <link>https://velog.io/@elile-e/API-%ED%98%B8%EC%B6%9C</link>
            <guid>https://velog.io/@elile-e/API-%ED%98%B8%EC%B6%9C</guid>
            <pubDate>Mon, 08 Feb 2021 13:45:29 GMT</pubDate>
            <description><![CDATA[<p>iOS에서 REST api를 다루기 위한 방법에 대해서 스터디를 한다.
사실 iOS framework 자체에서도 URL Loading하는 라이브러리를 제공하긴 하지만 
제공하는 기능들을 사용하는 방법들이 생각만큼이나 간단하지 않고 예쁘지 않다.</p>
<p>그래서 많은 iOS 개발자들이 기본 iOS framework에서 제공하는 기능을 확장하고 더 편리한 도구들을 제공하는 Alamofire를 사용하는 것이 일반적이다.
<a href="https://github.com/Alamofire/Alamofire">Alamofire/Alamofire</a></p>
<p>Alamofire가 제공하는 방법은 굉장히 직관적이며 편리하다.
간단한 Request 예시를 보자</p>
<pre><code class="language-swift">import Alamofire

func request() {
    AF.request(
            //요청 url
            BASE + url,
            //post, delete, update, get 메소드
            method: .post,
            //제공하는 parameter
            parameters: [&quot;someKey&quot;: &quot;someValue&quot;],
            //parameter 인코딩 방식
            endcoder: JSONParameterEncoder.default
            //헤더
            headers: [:]
        .responseString { response in
            print(response)
        }
}</code></pre>
<p>위처럼 간결하게 Request를 정의해 요청을 보낼 수 있으며, 콜백도 쉽게 받을 수 있다.</p>
<p>콜백을 받는 방법도 아래와 같이 여러가지 방식이 있다.</p>
<pre><code class="language-swift">
// 기본적인 문자열로 받기
.responseString { reponse in } 

// JSON 객체로 받기
.responseJSON{ data in }

// Swift4에서 제공되기 시작한 기능으로
// response가 미리 객체로 파싱되어 내려와 더 편하게 사용할 수 있다.
// Decodable로 바로 받기
.responseDecodable{ (response: AFDataResponse&lt;D&gt;) in 
        do {
                //아래의 코드로 파싱된 데이터를 가져올 수 있다.
                try response.result.get()
        } catch let error {
        }
}</code></pre>
<h2 id="mapping">Mapping</h2>
<p>API를 통해 받아오는 response 값을 앱에서 사용할 수 있는 객체로 생성을 해주기 위해선 Mapping이 필요하다.</p>
<p>보통의 개발자들은 크게 2가지의 방법을 많이 쓰는 것으로 한번 정리를 해본다.</p>
<ol>
<li>ObjectMapper with AlamofireObjectMapper </li>
</ol>
<p>아래와 같이 사용할 수 있다.</p>
<pre><code class="language-swift">import ObjectMapper
import AlamofireObjectMapper
import Alamofire

struct Post: Mappable {
    var title: String
    var user: String
    var content: String

    required init?(map: Map) {
    }

    func mapping(map: Map) {
        title &lt;- map[&quot;title&quot;]
        user &lt;- map[&quot;user_name&quot;]
        content &lt;- map[&quot;content&quot;]
    }
}

let url = &quot;&quot;
let params = [&quot;page&quot;: page]
let header = [&quot;Content-Type&quot;: &quot;application/json&quot;]

AF.request(url,
            method: .get,
            parameters: params,
            encoder: URLEncodedFormParameterEncoder.default,
            headers: header).responseObject { (response: DataResponse&lt;[Post]&gt; in
        let response = response.result.value
}</code></pre>
<ol start="2">
<li>Codable</li>
</ol>
<p>Swift4에서부터 제공하는 기능으로 Swift에 내장되어 있는 Mapping 기능이라고 생각하면 된다.</p>
<p>역시 Alamofire와 함께 이용이 가능하고 사용법은 아래 링크를 참조하면 된다.</p>
<p>아무래도 별도의 라이브러리 없이 내장된 기능이다보니 최신버전의 Swift를 사용한다면 Codable을 이용하게 되는 것 같다.</p>
<p><a href="https://shark-sea.kr/entry/Swift-Codable-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0">Swift :: Codable 알아보기</a></p>
<p>실제 데이터를 가져오는 코드로 Alamofire 관련된 내용을 한번 봐 보자.</p>
<pre><code class="language-swift">struct Post: Codable {
    var id: Int
    var title: String
    var user: String
  var content: String
}

static func getPosts(page: Int, success: @escaping([Post] -&gt; Void)) {
    let url = &quot;&quot;
    let params = [&quot;page&quot;: page]
    let header = [&quot;Content-Type&quot;: &quot;application/json&quot;]

    AF.request(url,
        method: .get,
            parameters: params,
        encoder: URLEncodedFormParameterEncoder.default,
        headers: header)
            .responseDecodable { (response: AFDataResponse&lt;[Post]&gt; in
            guard let stateCode = response.response?.statusCode else {
            return }
            do {
            } catch let error {
            }
    }
}</code></pre>
<p>내용만 보면 크게 어려운 내용들은 없다.
그만큼 Alamofire가 꽤 직관적이고 사용하기 예쁜편이다.</p>
<p>그러나 API 구문들이 많아지면 호출 구문들이 상당히 많아지며, 복잡해지곤 한다. 의존성에 대한 문제도 있다. 
만약 정말 훌륭한 개발자들이라면 자체적으로 APIManager나 APIService 같은 것들을 만들어서 잘 정리하시겠지.</p>
<p>그런데 이를 도와주는 라이브러리가 있다.
네트워크 추상화, 더 쉬운 테스트, 많은 API들을 Enum으로 정리할 수 있는 Moya 라이브러리다. (RxSwift도 따로 지원해서 궁합이 좋다고 한다.)</p>
<p><a href="https://medium.com/flawless-app-stories/getting-started-with-moya-f559c406e990">Getting started with Moya</a></p>
<p><a href="https://github.com/Moya/Moya">Moya/Moya</a></p>
<pre><code class="language-swift">import Moya

//열거형으로 API들을 정의한다.
enum OderPlus {
    //Parameter로 받는 것들과 함께 정의한다.
    case order(Int)
}

//Moya는 TargetType을 따르면서 구현이 되는데 이부분이 큰 특징이다.
//enum으로 구현부를 정리를 해, 가독성 및 관리측면에서 많은 도움이 된다.
//아마 읽어보면 크게 더 설명 할 부분은 없어보인다.
extension OrderPlus: TargetType {
    var baseURL: URL {
            return URL(string: &quot;http://api.orderplus.co.kr&quot;)!
    }

    var path: String {
        switch self {
        case .order:
            return &quot;order&quot;
        }
    }

    var method: Method {
        switch self {
            case .order: 
            return .post
            }
        }

         var task: Task {
            switch self {
                case .order(let id): 
                return .requestParameters(
                    parameters: [&quot;productId&quot;: id],
                        encoding: JSONEncoding.default
            )
            }
        }

    var headers: [String : String]? {
        return nil
    }
}

// 사용부
let provider = MoyaProvider&lt;OrderPlus&gt;()
provider.request(.order) { [weak self] result in 
        switch result {
        case .success(let response):
        case .failure:
        }
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>