<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>공공돌</title>
    <link>https://sheep1sik.tistory.com/</link>
    <description>성장하는 공공돌 블로그   </description>
    <language>ko</language>
    <pubDate>Thu, 7 May 2026 12:26:55 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Sheep1sik</managingEditor>
    <image>
      <title>공공돌</title>
      <url>https://tistory1.daumcdn.net/tistory/5717627/attach/28543049de7e4ace99d8f4ace0d27bb4</url>
      <link>https://sheep1sik.tistory.com</link>
    </image>
    <item>
      <title>[ Flutter ] 프로젝트 구조 해부</title>
      <link>https://sheep1sik.tistory.com/192</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter 학습 로드맵 Phase 1 - 두 번째 글&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;flutter create로 생성된 프로젝트의 모든 폴더와 파일을 iOS 프로젝트와 비교하며 하나씩 뜯어본다&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;들어가며&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Xcode에서 iOS 프로젝트를 만들면 &lt;code&gt;.xcodeproj&lt;/code&gt;, &lt;code&gt;AppDelegate.swift&lt;/code&gt;, &lt;code&gt;Info.plist&lt;/code&gt; 등이 자동 생성된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter도 마찬가지로 &lt;code&gt;flutter create&lt;/code&gt;를 실행하면 정해진 구조의 프로젝트가 만들어진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 글에서는 &lt;code&gt;flutter create first_app&lt;/code&gt;으로 생성된 실제 프로젝트를 기준으로, 각 폴더와 파일의 역할을 iOS 프로젝트와 비교하며 설명한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;전체 프로젝트 구조&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;first_app/                        (핵심 구조만 발췌)
├── lib/                    &amp;larr; Dart 코드 (핵심 작업 공간)
│   └── main.dart
├── test/                   &amp;larr; 테스트 코드
│   └── widget_test.dart
├── ios/                    &amp;larr; iOS 네이티브 설정
├── android/                &amp;larr; Android 네이티브 설정
├── web/                    &amp;larr; 웹 빌드 설정
├── macos/                  &amp;larr; macOS 데스크톱 설정
├── linux/                  &amp;larr; Linux 데스크톱 설정
├── windows/                &amp;larr; Windows 데스크톱 설정
├── build/                  &amp;larr; 빌드 산출물 (gitignore 대상)
├── pubspec.yaml            &amp;larr; 프로젝트 설정 파일 (핵심)
├── pubspec.lock            &amp;larr; 의존성 잠금 파일
├── analysis_options.yaml   &amp;larr; 린트 규칙 설정
├── README.md
└── (기타: .gitignore, .metadata, .dart_tool/, .idea/ 등 자동 생성 파일)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 프로젝트와 비교하면 이렇다:&lt;/span&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS (Xcode)&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;역할&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;lib/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift 소스 파일들&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;앱 코드 작성&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;test/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Tests/&lt;/code&gt; 타겟&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;테스트 코드&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;pubspec.yaml&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Package.swift&lt;/code&gt;/&lt;code&gt;Podfile&lt;/code&gt; + 앱 메타데이터&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;의존성 + Flutter 프로젝트 설정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;pubspec.lock&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Package.resolved&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;의존성 버전 잠금&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;ios/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Xcode 프로젝트 자체&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;네이티브 플랫폼 설정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;build/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;DerivedData/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;빌드 산출물&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;analysis_options.yaml&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;SwiftLint 설정&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코드 스타일 규칙&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1. lib/ &amp;mdash; 핵심 작업 공간&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Flutter 개발의 99%는 이 폴더 안에서 이루어진다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 프로젝트에서 Swift 파일들을 만들어 작업하듯이, Flutter에서는 &lt;code&gt;lib/&lt;/code&gt; 폴더 안에 Dart 파일을 만들어 작업한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;main.dart &amp;mdash; 앱의 진입점&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS의 &lt;code&gt;@main AppDelegate&lt;/code&gt;와 같은 역할이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;main()&lt;/code&gt; 함수가 앱의 시작점이다 (iOS의 &lt;code&gt;@main&lt;/code&gt; 어트리뷰트와 동일한 역할)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;runApp()&lt;/code&gt;에 루트 위젯을 전달하면 앱이 시작된다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS에서 &lt;code&gt;UIApplication.shared&lt;/code&gt; &amp;rarr; &lt;code&gt;AppDelegate&lt;/code&gt; &amp;rarr; &lt;code&gt;SceneDelegate&lt;/code&gt; &amp;rarr; &lt;code&gt;rootViewController&lt;/code&gt; 순서로 앱이 시작되는 것과 비교하면, Flutter는 &lt;code&gt;main()&lt;/code&gt; &amp;rarr; &lt;code&gt;runApp()&lt;/code&gt; &amp;rarr; 루트 위젯으로 훨씬 단순하다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트가 커지면?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;lib/&lt;/code&gt; 안에 하위 폴더를 만들어 구조화한다. 일반적인 패턴:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;lib/
├── main.dart               &amp;larr; 진입점
├── app.dart                &amp;larr; MaterialApp 위젯
├── screens/                &amp;larr; 화면 단위 위젯
│   ├── home_screen.dart
│   └── settings_screen.dart
├── widgets/                &amp;larr; 재사용 가능한 위젯
│   ├── custom_button.dart
│   └── user_card.dart
├── models/                 &amp;larr; 데이터 모델
│   └── user.dart
├── services/               &amp;larr; API, DB 등 외부 연동
│   └── api_service.dart
└── utils/                  &amp;larr; 유틸리티 함수, 상수
    └── constants.dart&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 프로젝트의 폴더 구조와 비교:&lt;/span&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 프로젝트&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;screens/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Views/&lt;/code&gt; 또는 &lt;code&gt;ViewControllers/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;widgets/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;재사용 커스텀 UIView/SwiftUI View&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;models/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Models/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;services/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Services/&lt;/code&gt; 또는 &lt;code&gt;Networking/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;utils/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Utils/&lt;/code&gt; 또는 &lt;code&gt;Extensions/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;포인트: Flutter는 폴더 구조에 대한 강제 규칙이 없다. Xcode처럼 빌드 타겟에 파일을 수동으로 추가하는 개념도 없다. lib/ 안에 .dart 파일을 만들면 별도 등록 없이 import로 바로 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트가 더 커지면? &amp;mdash; Feature-First 구조&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;위의 레이어 기반 구조는 입문용으로 좋지만, 앱이 커지면 &lt;b&gt;기능(Feature) 단위&lt;/b&gt;로 나누는 것이 커뮤니티에서 더 권장되는 방식이다:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;lib/
├── main.dart
├── app.dart
├── core/                   &amp;larr; 공통 유틸, 테마, 라우팅
│   ├── theme/
│   └── routing/
├── shared/                 &amp;larr; 공유 위젯, 모델
│   ├── widgets/
│   └── models/
└── features/               &amp;larr; 기능별 모듈
    ├── auth/
    │   ├── screens/
    │   ├── widgets/
    │   └── services/
    └── home/
        ├── screens/
        ├── widgets/
        └── services/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS의 TCA나 MVVM에서 Feature 모듈을 나누는 것과 같은 개념이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. test/ &amp;mdash; 테스트 코드&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:first_app/main.dart';

void main() {
  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    await tester.pumpWidget(const MyApp());

    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);

    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();

    expect(find.text('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS의 &lt;code&gt;XCTest&lt;/code&gt;와 비교:&lt;/span&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구분&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS (XCTest)&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;테스트 프레임워크&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter_test&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;XCTest&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;UI 테스트 도구&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;WidgetTester&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;XCUITest&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;테스트 실행&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter test&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Cmd+U&lt;/code&gt; 또는 &lt;code&gt;xcodebuild test&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;위치&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;test/&lt;/code&gt; 폴더&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Tests/&lt;/code&gt; 타겟&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter 테스트는 세 가지 레벨이 있다:&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Unit Test&lt;/b&gt;: 단일 함수/클래스 테스트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Widget Test&lt;/b&gt;: 위젯 렌더링 및 상호작용 테스트 (위 예시)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Integration Test&lt;/b&gt;: 전체 앱 흐름 테스트&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;별도의 테스트 타겟을 만들 필요 없이, test/ 폴더에 파일을 넣으면 바로 테스트가 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3. pubspec.yaml &amp;mdash; 프로젝트의 심장&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter 프로젝트의 의존성 관리, Dart SDK 버전 제약, 에셋/폰트 설정, 프로젝트 메타데이터를 &lt;b&gt;하나의 파일&lt;/b&gt;이 담당한다. iOS의 &lt;code&gt;Package.swift&lt;/code&gt;(SPM) + &lt;code&gt;Podfile&lt;/code&gt;(CocoaPods)의 의존성 관리 역할과 유사하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;name: first_app
description: &quot;A new Flutter project.&quot;
publish_to: 'none'
version: 1.0.0+1

environment:
  sdk: ^3.11.5

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.8

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^6.0.0

flutter:
  uses-material-design: true&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;각 섹션 설명&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;name / description / version&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;name: first_app              # Dart 패키지 이름 (iOS의 Bundle Name과는 다른 개념)
description: &quot;A new Flutter project.&quot;
version: 1.0.0+1             # 버전+빌드번호 (iOS의 CFBundleShortVersionString+CFBundleVersion)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;environment&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;environment:
  sdk: ^3.11.5               # Dart SDK 버전 범위: &amp;ge;3.11.5, &amp;lt;4.0.0 (캐럿은 호환 범위를 의미)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;dependencies &amp;mdash; 런타임 의존성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;dependencies:
  flutter:
    sdk: flutter              # Flutter SDK 자체
  cupertino_icons: ^1.0.8     # iOS 스타일 아이콘 (pub.dev에서 가져옴)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS에서 SPM이나 CocoaPods로 라이브러리를 추가하는 것과 같다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;패키지는 &lt;a href=&quot;https://pub.dev&quot;&gt;pub.dev&lt;/a&gt;에서 검색하고, 여기에 추가한 뒤 &lt;code&gt;flutter pub get&lt;/code&gt;을 실행하면 설치된다.&lt;/span&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;작업&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;패키지 저장소&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;pub.dev&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;SPM Registry / CocoaPods Specs&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;패키지 추가&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;pubspec.yaml&lt;/code&gt;에 추가 + &lt;code&gt;flutter pub get&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Xcode에서 Add Package 또는 &lt;code&gt;Podfile&lt;/code&gt; 수정 + &lt;code&gt;pod install&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;버전 표기&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;^1.0.8&lt;/code&gt; (캐럿 = 호환 범위)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;.upToNextMajor(from: &quot;1.0.8&quot;)&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;잠금 파일&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;pubspec.lock&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Package.resolved&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;dev_dependencies &amp;mdash; 개발 전용 의존성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;dev_dependencies:
  flutter_test:
    sdk: flutter              # 테스트 프레임워크
  flutter_lints: ^6.0.0       # 린트 규칙 (SwiftLint와 유사)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로덕션 빌드에는 포함되지 않는 개발 도구들이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;flutter 섹션 &amp;mdash; Flutter 전용 설정&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;flutter:
  uses-material-design: true  # Material 아이콘 폰트 포함
  # assets:                   # 이미지, JSON 등 에셋 등록
  # fonts:                    # 커스텀 폰트 등록&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS에서 이미지를 &lt;code&gt;Assets.xcassets&lt;/code&gt;에 추가하듯이, Flutter에서는 여기에 에셋 경로를 등록한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4. ios/ &amp;mdash; iOS 네이티브 레이어&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;ios/
├── Runner/
│   ├── AppDelegate.swift          &amp;larr; iOS 앱 진입점
│   ├── SceneDelegate.swift        &amp;larr; Scene 관리
│   ├── Info.plist                 &amp;larr; iOS 앱 설정
│   ├── Assets.xcassets/           &amp;larr; 앱 아이콘 등
│   ├── Base.lproj/                &amp;larr; LaunchScreen 스토리보드
│   ├── GeneratedPluginRegistrant.h/.m &amp;larr; 플러그인 자동 등록 (수정 금지)
│   └── Runner-Bridging-Header.h   &amp;larr; Swift-ObjC 브릿지
├── Runner.xcodeproj/              &amp;larr; Xcode 프로젝트
├── Runner.xcworkspace/            &amp;larr; Xcode 워크스페이스
├── RunnerTests/                   &amp;larr; iOS 네이티브 테스트
└── Flutter/
    ├── Debug.xcconfig             &amp;larr; 디버그 빌드 설정
    ├── Release.xcconfig           &amp;larr; 릴리즈 빌드 설정
    └── AppFrameworkInfo.plist     &amp;larr; Flutter 프레임워크 정보&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 개발자에게 친숙한 구조다. 실제로 Xcode에서 열어서 작업할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AppDelegate.swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;import Flutter
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -&amp;gt; Bool {
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
    GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;일반적인 iOS &lt;code&gt;AppDelegate&lt;/code&gt;와 비슷하지만, &lt;code&gt;FlutterAppDelegate&lt;/code&gt;를 상속받고 &lt;code&gt;FlutterImplicitEngineDelegate&lt;/code&gt; 프로토콜을 채택한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;FlutterImplicitEngineDelegate&lt;/code&gt;는 Flutter 엔진이 암시적으로 초기화될 때 호출되는 콜백을 제공하며, &lt;code&gt;didInitializeImplicitFlutterEngine&lt;/code&gt;에서 플러그인 자동 등록을 처리한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;언제 ios/ 폴더를 직접 수정하나?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대부분의 Flutter 개발에서는 &lt;code&gt;ios/&lt;/code&gt; 폴더를 건드릴 일이 거의 없다. 하지만 다음 경우에는 직접 수정해야 한다:&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;앱 아이콘 변경&lt;/b&gt;: &lt;code&gt;Assets.xcassets/AppIcon.appiconset/&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;권한 설정&lt;/b&gt;: &lt;code&gt;Info.plist&lt;/code&gt;에 &lt;code&gt;NSCameraUsageDescription&lt;/code&gt; 등 추가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;푸시 알림 / Background Modes&lt;/b&gt;: Capability 추가 (Xcode에서 직접)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;딥링크 / Universal Links&lt;/b&gt;: Associated Domains 설정, URL Schemes 추가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;서드파티 SDK 설정&lt;/b&gt;: &lt;code&gt;AppDelegate.swift&lt;/code&gt;에 초기화 코드 추가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;빌드 설정 변경&lt;/b&gt;: 코드 서명, 배포 프로파일, minimum deployment target 등&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Platform Channel&lt;/b&gt;: Swift로 네이티브 코드를 직접 작성할 때&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;즉, Apple 플랫폼 고유 기능이나 네이티브 빌드 설정이 필요할 때 &lt;code&gt;ios/&lt;/code&gt; 폴더를 수정한다고 보면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5. android/ &amp;mdash; Android 네이티브 레이어&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;android/
├── app/
│   ├── build.gradle.kts     &amp;larr; 앱 모듈 빌드 설정 (minSdk, targetSdk 등)
│   └── src/                 &amp;larr; Android 소스 (AndroidManifest.xml 등)
├── build.gradle.kts         &amp;larr; 프로젝트 레벨 빌드 설정
├── gradle/                  &amp;larr; Gradle 래퍼
├── gradle.properties        &amp;larr; Gradle 속성
└── settings.gradle.kts      &amp;larr; 모듈 설정&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 개발자 관점에서 핵심만 알면 된다:&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;build.gradle.kts&lt;/code&gt; &amp;rarr; iOS의 Xcode 빌드 설정과 유사&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;AndroidManifest.xml&lt;/code&gt; &amp;rarr; iOS의 &lt;code&gt;Info.plist&lt;/code&gt;와 유사 (권한, 앱 메타데이터)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;minSdk&lt;/code&gt; &amp;rarr; iOS의 minimum deployment target&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6. analysis_options.yaml &amp;mdash; 코드 품질 관리&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;include: package:flutter_lints/flutter.yaml

linter:
  rules:
    # avoid_print: false
    # prefer_single_quotes: true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS의 &lt;b&gt;SwiftLint&lt;/b&gt; &lt;code&gt;.swiftlint.yml&lt;/code&gt;과 동일한 역할이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter_lints&lt;/code&gt; 패키지가 기본 린트 규칙을 제공한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;규칙을 활성화/비활성화할 수 있다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter analyze&lt;/code&gt; 명령으로 전체 프로젝트 린트 검사를 실행한다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;7. 나머지 플랫폼 폴더&lt;/span&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;폴더&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대상 플랫폼&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;빌드 시스템&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;web/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;웹 브라우저&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;웹 부트스트랩 + JS/Wasm&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;macos/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;macOS 데스크톱&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Xcode&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;linux/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Linux 데스크톱&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;CMake&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;windows/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Windows 데스크톱&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;CMake&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter의 강점은 &lt;b&gt;하나의 &lt;code&gt;lib/&lt;/code&gt; 코드로 모든 플랫폼에 빌드&lt;/b&gt;할 수 있다는 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;각 플랫폼 폴더는 해당 OS의 네이티브 설정만 담당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;필요 없는 플랫폼은 &lt;code&gt;flutter create&lt;/code&gt; 시 &lt;code&gt;--platforms&lt;/code&gt; 옵션으로 제외할 수 있다:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;# iOS와 Android만 생성
flutter create --platforms=ios,android my_app&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;8. 빌드와 실행 명령어&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 개발자에게 익숙한 작업과 대응하는 Flutter 명령어:&lt;/span&gt;&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;작업&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS (Xcode)&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter CLI&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;빌드 + 실행&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Cmd+R&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter run&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;테스트&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Cmd+U&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter test&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;정적 분석&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Build Warnings&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter analyze&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;패키지 설치&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Resolve Packages&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter pub get&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;클린 빌드&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Cmd+Shift+K&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter clean&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;릴리즈 빌드&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Archive&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter build ios --release&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;디바이스 목록&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Window &amp;gt; Devices&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;flutter devices&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Hot Reload vs Hot Restart&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter의 가장 큰 장점 중 하나다:&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Hot Reload&lt;/b&gt; (&lt;code&gt;r&lt;/code&gt;): 코드 변경사항을 즉시 반영. 앱 상태(state)가 유지된다. Xcode의 Previews보다 빠르고, 실제 시뮬레이터에서 동작한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Hot Restart&lt;/b&gt; (&lt;code&gt;R&lt;/code&gt;): 앱을 완전히 재시작. 상태가 초기화된다. Xcode의 &lt;code&gt;Cmd+R&lt;/code&gt;과 유사하지만 훨씬 빠르다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;9. iOS 프로젝트 vs Flutter 프로젝트 구조 최종 비교&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;[iOS 프로젝트]                         [Flutter 프로젝트]
MyApp.xcodeproj                        pubspec.yaml
├── Sources/                           ├── lib/
│   ├── AppDelegate.swift              │   ├── main.dart
│   ├── Views/                         │   ├── screens/
│   ├── Models/                        │   ├── models/
│   └── Services/                      │   └── services/
├── Tests/                             ├── test/
├── Resources/                         ├── assets/ (pubspec.yaml에 등록)
│   └── Assets.xcassets                │
├── Info.plist                         ├── ios/Runner/Info.plist
├── Podfile (또는 Package.swift)       ├── pubspec.yaml (dependencies)
├── .swiftlint.yml                     ├── analysis_options.yaml
└── DerivedData/                       └── build/&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter 프로젝트 구조의 핵심을 정리하면:&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;code&gt;lib/&lt;/code&gt; 폴더가 전부다&lt;/b&gt; &amp;mdash; 개발 시간의 99%를 여기서 보낸다. 나머지 플랫폼 폴더는 특별한 네이티브 설정이 필요할 때만 건드린다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&lt;code&gt;pubspec.yaml&lt;/code&gt;이 프로젝트의 심장이다&lt;/b&gt; &amp;mdash; 의존성, 에셋, 폰트, 메타데이터가 모두 이 파일 하나에 들어간다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;플랫폼별 폴더는 &quot;포장&quot;이다&lt;/b&gt; &amp;mdash; 동일한 Dart 코드를 각 OS에 맞게 포장하는 역할이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Dart 코드 관리는 Xcode보다 단순하다&lt;/b&gt; &amp;mdash; 네이티브 빌드 설정(타겟, 스키마, 워크스페이스)은 &lt;code&gt;ios/&lt;/code&gt;, &lt;code&gt;android/&lt;/code&gt; 등에 여전히 존재하지만, 일상적인 Flutter 개발에서는 그 위에서 작업하므로 직접 다룰 일이 적다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 개발자가 가장 적응이 필요한 부분은, Xcode GUI 대신 &lt;b&gt;&lt;code&gt;pubspec.yaml&lt;/code&gt; 텍스트 파일로 프로젝트를 관리&lt;/b&gt;한다는 점이다. 하지만 익숙해지면 오히려 더 직관적이고 빠르다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;참고 자료&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://docs.flutter.dev/resources/architectural-overview&quot;&gt;Flutter 공식 문서 - Project Structure&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://docs.flutter.dev/tools/pubspec&quot;&gt;Flutter 공식 문서 - pubspec.yaml&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://dart.dev/tools/pub/package-layout&quot;&gt;Dart 공식 문서 - Package Layout&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://docs.flutter.dev/ui/assets/assets-and-images&quot;&gt;Flutter 공식 문서 - Assets and Images&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Flutter</category>
      <category>Flutter</category>
      <category>flutter create</category>
      <category>Flutter iOS 비교</category>
      <category>Flutter 디렉토리 구조</category>
      <category>Flutter 입문</category>
      <category>flutter 프로젝트 구조</category>
      <category>IOS</category>
      <category>pubspec.yaml</category>
      <category>공공돌</category>
      <category>앱 개발</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/192</guid>
      <comments>https://sheep1sik.tistory.com/192#entry192comment</comments>
      <pubDate>Thu, 23 Apr 2026 22:53:03 +0900</pubDate>
    </item>
    <item>
      <title>[ Flutter ]Swift 개발자를 위한 Dart 핵심 문법 비교</title>
      <link>https://sheep1sik.tistory.com/191</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Flutter 학습 로드맵 Phase 1 - 첫 번째 글&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 개발자가 Dart를 처음 접할 때, Swift와 비교하며 빠르게 익히는 핵심 문법 정리&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;들어가며&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 개발자로서 Flutter에 입문하면 가장 먼저 마주하는 것이 &lt;b&gt;Dart 언어&lt;/b&gt;다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다행히 Dart와 Swift는 현대적 언어 설계를 공유하고 있어서, Swift 경험이 있다면 Dart를 빠르게 익힐 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 글에서는 Swift 문법과 1:1로 비교하며 Dart의 핵심을 정리한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1. 변수 선언&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;var name = &quot;원식&quot;          // 변경 가능
let age = 25               // 변경 불가 (런타임 상수)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;var name = '원식';          // 변경 가능 (타입 추론)
final age = 25;             // 변경 불가 (런타임 상수, Swift의 let과 동일)
const pi = 3.14;            // 컴파일타임 상수 (Swift에는 없는 개념)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구분&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;변경 가능&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;var&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;var&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;런타임 상수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;let&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;final&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;컴파일타임 상수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;없음 (&lt;code&gt;static let&lt;/code&gt;으로 유사 구현)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;const&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;포인트: Dart의 const는 컴파일 시점에 값이 결정되어야 한다. final은 런타임에 한 번만 할당되면 된다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예를 들어 final now = DateTime.now();는 가능하지만, const now = DateTime.now();는 불가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. 기본 타입&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;let count: Int = 10
let price: Double = 9.99
let name: String = &quot;Flutter&quot;
let isActive: Bool = true&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;int count = 10;
double price = 9.99;
String name = 'Flutter';
bool isActive = true;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift는 &lt;code&gt;Int&lt;/code&gt;, &lt;code&gt;Double&lt;/code&gt; 등 대문자로 시작 &amp;rarr; Dart도 &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;은 소문자지만 &lt;b&gt;클래스&lt;/b&gt;다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart에서 모든 변수는 &lt;b&gt;객체의 참조&lt;/b&gt;다. &lt;code&gt;int&lt;/code&gt;도 객체다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart의 &lt;code&gt;num&lt;/code&gt; 타입은 &lt;code&gt;int&lt;/code&gt;와 &lt;code&gt;double&lt;/code&gt;의 상위 타입이다 (Swift에는 없음)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문자열은 작은따옴표(&lt;code&gt;'&lt;/code&gt;)와 큰따옴표(&lt;code&gt;&quot;&lt;/code&gt;) 모두 사용 가능 (Swift는 큰따옴표만)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3. Null Safety&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift와 Dart 모두 Null Safety를 지원한다. 문법도 매우 유사하다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;var name: String? = nil          // Optional
let length = name?.count         // Optional Chaining
let safeName = name ?? &quot;기본값&quot;   // Nil Coalescing
let forcedName = name!           // Force Unwrap&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;String? name = null;             // Nullable
int? length = name?.length;      // Null-aware access
String safeName = name ?? '기본값'; // Null-aware operator
String forcedName = name!;       // Null assertion&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문법이 거의 동일하다 (&lt;code&gt;?&lt;/code&gt;, &lt;code&gt;??&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift의 &lt;code&gt;if let&lt;/code&gt;, &lt;code&gt;guard let&lt;/code&gt; 바인딩 &amp;rarr; Dart에는 직접적인 대응이 없다. Dart 3.0의 패턴 매칭으로 일부 케이스는 유사하게 처리 가능하지만, 완전한 대체는 아니다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart는 &lt;code&gt;late&lt;/code&gt; 키워드로 나중에 초기화할 non-nullable 변수를 선언할 수 있다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;late String description; // 나중에 반드시 초기화해야 함
// 초기화 전에 접근하면 런타임 에러 발생 (Swift의 IUO와 다른 개념)
// late는 &quot;아직 값이 없지만, 사용 전에 반드시 넣겠다&quot;는 의미&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4. 컬렉션 타입&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// Array
var fruits: [String] = [&quot;사과&quot;, &quot;바나나&quot;, &quot;딸기&quot;]

// Dictionary
var scores: [String: Int] = [&quot;수학&quot;: 90, &quot;영어&quot;: 85]

// Set
var uniqueNumbers: Set&amp;lt;Int&amp;gt; = [1, 2, 3]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// List (Swift의 Array)
List&amp;lt;String&amp;gt; fruits = ['사과', '바나나', '딸기'];
// 타입 추론 버전
var fruits2 = &amp;lt;String&amp;gt;['사과', '바나나', '딸기'];

// Map (Swift의 Dictionary)
Map&amp;lt;String, int&amp;gt; scores = {'수학': 90, '영어': 85};

// Set
Set&amp;lt;int&amp;gt; uniqueNumbers = {1, 2, 3};&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구분&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;배열&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;[String]&lt;/code&gt; 또는 &lt;code&gt;Array&amp;lt;String&amp;gt;&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;딕셔너리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;[String: Int]&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Map&amp;lt;String, int&amp;gt;&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;집합&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Set&amp;lt;Int&amp;gt;&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Set&amp;lt;int&amp;gt;&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;스프레드 연산자&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;없음&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;...&lt;/code&gt; 지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;// Dart의 스프레드 연산자 - 컬렉션 합치기가 간편하다
var list1 = [1, 2, 3];
var list2 = [0, ...list1, 4]; // [0, 1, 2, 3, 4]

// 조건부 컬렉션 요소 - UI 빌드 시 매우 유용
var nav = [
  'Home',
  'Settings',
  if (isAdmin) 'Admin',
];&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5. 함수&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;func greet(name: String, greeting: String = &quot;안녕&quot;) -&amp;gt; String {
    return &quot;\(greeting), \(name)!&quot;
}

// 호출
greet(name: &quot;원식&quot;)
greet(name: &quot;원식&quot;, greeting: &quot;하이&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;String greet(String name, {String greeting = '안녕'}) {
    return '$greeting, $name!';
}

// 호출
greet('원식');
greet('원식', greeting: '하이');&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift는 기본적으로 &lt;b&gt;argument label&lt;/b&gt; 사용 &amp;rarr; Dart는 &lt;b&gt;positional parameter&lt;/b&gt;가 기본&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart의 &lt;b&gt;named parameter&lt;/b&gt;는 &lt;code&gt;{}&lt;/code&gt;로 감싸서 선언, 호출 시 이름 필요&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart의 named parameter는 기본적으로 optional &amp;rarr; &lt;code&gt;required&lt;/code&gt; 키워드로 필수화&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// required named parameter
void createUser({required String name, required int age}) {
    print('$name, $age');
}

// positional optional parameter - []로 감싼다
void sayHello(String name, [String? title]) {
    print('Hello ${title ?? &quot;&quot;} $name');
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;화살표 함수&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;// Swift - 클로저
let add = { (a: Int, b: Int) -&amp;gt; Int in a + b }&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;// Dart - 화살표 함수 (한 줄 표현식)
int add(int a, int b) =&amp;gt; a + b;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6. 클래스&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;class Person {
    let name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    func introduce() -&amp;gt; String {
        return &quot;저는 \(name)이고, \(age)살입니다.&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;class Person {
    final String name;
    int age;

    Person(this.name, this.age); // 축약 생성자

    // Named constructor
    Person.anonymous() : name = '익명', age = 0;

    String introduce() {
        return '저는 $name이고, $age살입니다.';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart는 &lt;code&gt;this.name&lt;/code&gt; 축약 생성자를 지원 &amp;rarr; 보일러플레이트가 적다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart는 &lt;b&gt;Named Constructor&lt;/b&gt;를 지원 (&lt;code&gt;Person.anonymous()&lt;/code&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift의 &lt;code&gt;self&lt;/code&gt; &amp;rarr; Dart에서도 &lt;code&gt;this&lt;/code&gt; (보통 생략)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart에는 Swift의 &lt;code&gt;struct&lt;/code&gt;처럼 사용자가 정의하는 값 타입이 없다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;주의: Swift 개발자가 가장 주의할 점은 Dart에 사용자 정의 값 타입(struct)이 없다는 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;클래스는 모두 참조 타입이다. 단, Dart 3.0부터 도입된 Record는 값 의미론(value semantics)을 가진다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Record는 Swift의 Tuple과 유사하며, 간단한 값 묶음을 표현할 때 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
    // Dart Record - Swift의 Tuple과 유사 (값 타입)
    (String, int) person = ('원식', 25);
    print(person.$1); // '원식'
    print(person.$2); // 25

    // Named field record
    ({String name, int age}) namedPerson = (name: '원식', age: 25);
    print(namedPerson.name); // '원식'
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;7. 상속과 프로토콜&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;protocol Describable {
    func describe() -&amp;gt; String
}

class Animal {
    let name: String
    init(name: String) { self.name = name }
}

class Dog: Animal, Describable {
    func describe() -&amp;gt; String {
        return &quot;\(name)는 강아지입니다.&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;// abstract class = Swift의 protocol과 유사
abstract class Describable {
    String describe();
}

class Animal {
    final String name;
    Animal(this.name);
}

class Dog extends Animal implements Describable {
    Dog(super.name);

    @override
    String describe() {
        return '$name는 강아지입니다.';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구분&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로토콜/인터페이스&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;protocol&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;abstract class&lt;/code&gt; 또는 &lt;code&gt;abstract interface class&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;상속&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;:&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;extends&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로토콜 채택&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;:&lt;/code&gt; (상속과 동일 문법)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;implements&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다중 상속&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;불가&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;불가 (하지만 &lt;code&gt;mixin&lt;/code&gt; 지원)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Mixin - Dart의 강력한 기능&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;mixin Swimming {
    void swim() =&amp;gt; print('수영 중!');
}

mixin Flying {
    void fly() =&amp;gt; print('비행 중!');
}

class Duck extends Animal with Swimming, Flying {
    Duck(super.name);
}

void main() {
    var duck = Duck('오리');
    duck.swim(); // 수영 중!
    duck.fly();  // 비행 중!
}&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift에서는 protocol extension으로 기본 구현을 제공하지만, Dart의 mixin은 상태(변수)까지 포함할 수 있어 더 강력하다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;8. 비동기 프로그래밍&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 부분은 Swift 개발자에게 가장 친숙할 것이다. Swift Concurrency와 매우 유사하다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;func fetchUser() async throws -&amp;gt; User {
    let data = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data.0)
}

// 호출
Task {
    let user = try await fetchUser()
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;Future&amp;lt;User&amp;gt; fetchUser() async {
    final response = await http.get(Uri.parse(url));
    return User.fromJson(jsonDecode(response.body));
}

// 호출
void main() async {
    final user = await fetchUser();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구분&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;반환 타입&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;async&lt;/code&gt; 키워드 사용&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Future&amp;lt;T&amp;gt;&lt;/code&gt; 반환&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에러 처리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;throws&lt;/code&gt; + &lt;code&gt;try&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;try-catch&lt;/code&gt; (throws 선언 불필요)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비동기 호출&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;await&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;await&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;스트림&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;AsyncSequence&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Stream&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;// Dart Stream - Swift의 AsyncSequence와 유사
Stream&amp;lt;int&amp;gt; countStream(int max) async* {
    for (int i = 0; i &amp;lt; max; i++) {
        await Future.delayed(Duration(seconds: 1));
        yield i;
    }
}

// 사용 (async 함수 내에서)
Future&amp;lt;void&amp;gt; main() async {
    await for (var count in countStream(5)) {
        print(count); // 0, 1, 2, 3, 4 (1초 간격)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;9. 에러 처리&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;enum NetworkError: Error {
    case notFound
    case serverError(code: Int)
}

func fetchData() throws {
    throw NetworkError.serverError(code: 500)
}

do {
    try fetchData()
} catch NetworkError.notFound {
    print(&quot;Not Found&quot;)
} catch NetworkError.serverError(let code) {
    print(&quot;Server Error: \(code)&quot;)
} catch {
    print(&quot;Unknown: \(error)&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;class NetworkException implements Exception {
    final String message;
    final int? code;
    NetworkException(this.message, {this.code});
}

void fetchData() {
    throw NetworkException('Server Error', code: 500);
}

void main() {
    try {
        fetchData();
    } on NetworkException catch (e) {
        print('Network: ${e.message}, code: ${e.code}');
    } on FormatException {
        print('Format Error');
    } catch (e) {
        print('Unknown: $e');
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift는 &lt;code&gt;throws&lt;/code&gt; 선언 필수 &amp;rarr; Dart는 &lt;b&gt;아무 함수나 throw 가능&lt;/b&gt; (선언 불필요)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift의 &lt;code&gt;do-catch&lt;/code&gt; &amp;rarr; Dart의 &lt;code&gt;try-catch&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart는 &lt;code&gt;on 타입 catch (e)&lt;/code&gt; 문법으로 특정 예외 타입을 잡는다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart에서는 어떤 객체든 throw 가능 (문자열도 가능하지만 비권장)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;10. 패턴 매칭 (Dart 3.0+)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart 3.0에서 추가된 패턴 매칭은 Swift의 &lt;code&gt;switch&lt;/code&gt;-&lt;code&gt;case&lt;/code&gt;와 유사하다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;enum Status {
    case success(data: String)
    case error(code: Int)
}

let result: Status = .success(data: &quot;OK&quot;)

switch result {
case .success(let data):
    print(&quot;성공: \(data)&quot;)
case .error(let code) where code &amp;gt;= 500:
    print(&quot;서버 에러: \(code)&quot;)
case .error(let code):
    print(&quot;에러: \(code)&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;sealed class Status {}
class Success extends Status {
    final String data;
    Success(this.data);
}
class Error extends Status {
    final int code;
    Error(this.code);
}

void main() {
    var result = Success('OK');

    switch (result) {
        case Success(data: var d):
            print('성공: $d');
        case Error(code: var c) when c &amp;gt;= 500:
            print('서버 에러: $c');
        case Error(code: var c):
            print('에러: $c');
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심 차이점&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift의 &lt;code&gt;enum&lt;/code&gt; associated value &amp;rarr; Dart의 &lt;code&gt;sealed class&lt;/code&gt; + 하위 클래스&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift의 &lt;code&gt;where&lt;/code&gt; &amp;rarr; Dart의 &lt;code&gt;when&lt;/code&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart 3.0의 &lt;code&gt;sealed class&lt;/code&gt;는 exhaustive switching을 보장 (Swift enum처럼)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한눈에 보는 비교표&lt;/span&gt;&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개념&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Dart&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;변경 가능 변수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;var&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;var&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;런타임 상수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;let&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;final&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;컴파일타임 상수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;const&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문자열 보간&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;&quot;\(변수)&quot;&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;'$변수'&lt;/code&gt; 또는 &lt;code&gt;'${표현식}'&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;옵셔널&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Type?&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Type?&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;배열&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;[Type]&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;List&amp;lt;Type&amp;gt;&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;딕셔너리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;[K: V]&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Map&amp;lt;K, V&amp;gt;&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로토콜&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;protocol&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;abstract interface class&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;상속&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;class A: B&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;class A extends B&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구현&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;class A: Protocol&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;class A implements Interface&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비동기 반환&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;() async -&amp;gt; T&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Future&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;스트림&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;AsyncSequence&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Stream&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;값 타입&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;struct&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사용자 정의 불가 (Record로 제한적 대체)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;타입 별칭&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;typealias&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;typedef&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;접근 제어&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;private&lt;/code&gt;, &lt;code&gt;internal&lt;/code&gt;, &lt;code&gt;public&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;_&lt;/code&gt;접두사 = private (라이브러리 단위)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;세미콜론&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;불필요&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;필수&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마무리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift 개발자가 Dart를 배울 때 가장 크게 느끼는 차이점은 세 가지다:&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;세미콜론이 필수다&lt;/b&gt; - 처음에는 자주 빼먹지만 IDE가 잡아준다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;사용자 정의 값 타입이 없다&lt;/b&gt; - 클래스는 모두 참조 타입이다. 불변 객체를 만들려면 &lt;code&gt;final&lt;/code&gt; 필드를 사용하고, 컴파일타임 상수가 필요하면 &lt;code&gt;const&lt;/code&gt; 생성자를 추가한다. Record는 값 타입이지만 사용자 정의 메서드를 가질 수 없다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;접근 제어가 언더스코어 기반이다&lt;/b&gt; - &lt;code&gt;_&lt;/code&gt;로 시작하면 라이브러리 private, 그 외에는 모두 public&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하지만 Null Safety, 비동기, 패턴 매칭 등 핵심 개념은 Swift와 매우 유사하다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Swift에서 쌓은 개념적 이해를 그대로 가져오되, 문법만 Dart 방식으로 바꿔서 쓴다는 감각으로 접근하면 빠르게 적응할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;참고 자료&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://dart.dev/guides/language/language-tour&quot;&gt;Dart 공식 문서 - Language Tour&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://dart.dev/null-safety&quot;&gt;Dart 공식 문서 - Null Safety&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://dart.dev/language/patterns&quot;&gt;Dart 공식 문서 - Patterns&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://docs.flutter.dev/&quot;&gt;Flutter 공식 문서&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Flutter</category>
      <category>DART</category>
      <category>Dart 문법</category>
      <category>Flutter</category>
      <category>IOS</category>
      <category>SWIFT</category>
      <category>공공돌</category>
      <category>네이티브</category>
      <category>앱 개발</category>
      <category>하이브리드</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/191</guid>
      <comments>https://sheep1sik.tistory.com/191#entry191comment</comments>
      <pubDate>Wed, 22 Apr 2026 17:02:13 +0900</pubDate>
    </item>
    <item>
      <title>[ Claude ] 나만의 오케스트레이터 설계, 왜 직접 만들었고, 6개 팀은 어떻게 탄생했는가</title>
      <link>https://sheep1sik.tistory.com/190</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&quot;이미 하네스를 자동으로 만들어주는 플러그인이 있는데, 왜 직접 만들어?&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;답은 간단하다. &lt;b&gt;원리를 이해하고 싶었고, 나에게 맞는 것을 만들고 싶었다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Harness 플러그인은 훌륭한 도구다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;하네스 구성해줘&quot;라고 말하면 도메인을 분석하고, 아키텍처 패턴을 선택하고, 에이전트와 스킬을 자동으로 생성해준다. 하지만 나는 그 과정을 &lt;b&gt;블랙박스로 넘기고 싶지 않았다&lt;/b&gt;.&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프레임워크를 쓰기 전에 프레임워크가 해결하는 문제를 직접 겪어봐야 한다는 말이 있다. UIKit을 이해하지 못한 채 SwiftUI를 쓰면, 문제가 생겼을 때 어디를 봐야 하는지 모른다. 하네스도 마찬가지다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;CLAUDE.md에 규칙을 적으면 AI가 왜 그 규칙을 따르는지, 에이전트를 분리하면 어떤 이점이 생기고 어떤 트레이드오프가 있는지, 스킬의 워크플로우를 어떻게 설계해야 AI가 일관되게 따르는지 이런 것들을 &lt;b&gt;직접 부딪히면서 이해하고 싶었다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그리고 무엇보다, 나는 iOS 개발자로서 &lt;b&gt;나만의 개발 습관과 작업 방식&lt;/b&gt;이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트를 동시에 운영하면서 쌓아온 나름의 원칙들이 있고, 트러블슈팅을 노션에 기록하는 습관이 있고, Apple 공식 문서를 우선 참고하는 버릇이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;범용 도구가 이 모든 걸 알아서 반영해줄 거라고 기대하기보다, &lt;b&gt;처음부터 내 방식으로 설계하는 게 더 확실&lt;/b&gt;했다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;설계의 출발점: 무엇이 문제였는가&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;매번 반복되는 컨텍스트 설명&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code를 본격적으로 개발에 활용하기 시작하면서 가장 먼저 느낀 불편함은, &lt;b&gt;매 대화마다 같은 맥락을 반복 설명해야 한다&lt;/b&gt;는 것이었다. 1탄에서도 언급했지만, 이건 실제로 겪어보면 생각 이상으로 피로하다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;이 프로젝트는 UIKit 기반이야&quot;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;아키텍처는 MVVM-C 패턴이야&quot;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;기존 코드 스타일을 따라줘&quot;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;Codable 대신 Encodable/Decodable 분리해서 써&quot;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이걸 매번 말해주지 않으면? Claude는 SwiftUI 코드를 제안하거나, 기존 구조와 전혀 다른 패턴을 권하거나, 심지어 기존 코드를 &quot;더 좋게&quot; 만든다며 통째로 재작성하기도 했다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트 간 컨텍스트 혼선&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 프로젝트를 동시에 운영하다 보니 더 심각한 문제가 있었다. A 프로젝트에서 작업하다가 B 프로젝트로 넘어갔을 때, &lt;b&gt;이전 프로젝트의 맥락이 섞여 들어오는&lt;/b&gt; 경우가 있었다. 각 프로젝트마다 아키텍처도 다르고, 코드 스타일도 다르고, 사용하는 라이브러리도 다른데, AI가 이걸 제대로 구분하지 못하면 미묘한 불일치가 생긴다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;일회성 작업의 반복&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;트러블슈팅을 할 때마다 같은 패턴이 반복됐다. 에러를 분석하고, 원인을 찾고, 해결하고 &amp;mdash; 여기까지는 좋다. 문제는 이 과정이 &lt;b&gt;다음에 비슷한 에러가 나면 처음부터 다시 시작&lt;/b&gt;된다는 것이었다. 기록이 체계적으로 남지 않으니, 3개월 전에 같은 에러를 어떻게 해결했는지 찾을 수가 없었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 세 가지 문제를 한꺼번에 해결하기 위해, 나는 &lt;b&gt;오케스트레이터&lt;/b&gt;를 설계하기로 했다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오케스트레이터란 무엇인가&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오케스트레이터의 역할을 한 문장으로 정의하면 이렇다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;모든 작업을 직접 한 번에 처리하는 것이 아니라, 요청의 성격을 분석해 필요한 전문 팀에만 작업을 위임하고, 그 결과를 통합하는 것.&quot;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오케스트라의 지휘자를 생각하면 된다. 지휘자는 바이올린을 직접 연주하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;어떤 파트가 언제 들어와야 하는지 판단하고, 전체적인 조화를 만든다. 내 오케스트레이터도 마찬가지다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;요청이 들어오면 &lt;b&gt;성격을 파악&lt;/b&gt;한다 &amp;mdash; 이건 구현인가? 기획인가? 버그인가?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;필요한 &lt;b&gt;전문 팀만 선택적으로 호출&lt;/b&gt;한다 &amp;mdash; 모든 팀을 매번 다 부르지 않는다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;각 팀의 결과를 &lt;b&gt;통합해서 사용자에게 전달&lt;/b&gt;한다&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심은 &quot;선택적 호출&quot;이다. 변수명 하나 바꾸는데 아키텍처 분석 팀까지 동원하면, 그건 체계가 아니라 관료주의다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최상위 원칙 설계: 오케스트레이터의 헌법&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀을 설계하기 전에, 전체를 관통하는 원칙부터 세워야 했다. 이 원칙들은 CLAUDE.md의 최상단에 위치하며, 모든 팀의 작업을 제어하는 &lt;b&gt;헌법&lt;/b&gt; 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실전에서 부딪히면서 정리한 10가지 원칙은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center; width: 40px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;#&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;원칙&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 원칙이 없으면 생기는 문제&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모든 요청에 모든 팀을 동시에 호출하지 않는다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;컨텍스트 낭비. 단순 수정에 6개 팀이 동원된다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;요청의 성격을 먼저 분류하고, 필요한 팀만 선택 호출한다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모든 작업에 풀 프로세스가 적용되어 느려진다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 디자인, 코드, 아키텍처, 네이밍, 작업 흐름을 최대한 보존한다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AI가 &quot;더 좋은 방법&quot;이라며 기존 코드를 전면 재작성한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;새로운 제안은 현재 프로젝트 컨텍스트 안에서 검토한다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;일반적 베스트 프랙티스가 프로젝트 일관성을 깨뜨린다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트별 프롬프트가 있다면 반드시 이를 우선 참고한다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트 간 규칙이 혼선된다 (A 프로젝트 규칙이 B에 적용)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;작업 결과는 재사용 가능한 개발 자산이 되도록 정리한다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;매번 같은 문제를 처음부터 다시 해결한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;7&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Apple Developer Documentation을 우선 참고 기준으로 삼는다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;블로그 글의 outdated 코드나 비권장 패턴이 적용된다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;8&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;참고 자료는 링크와 함께 왜 참고했는지 요약한다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;근거 없는 제안이 들어오고, 나중에 판단 과정을 추적할 수 없다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;9&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Apple 공식 방향성과 충돌하는 해결책은 지양한다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;deprecated API나 비권장 패턴이 슬며시 코드에 들어온다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;10&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;일반적 베스트 프랙티스를 강요하지 말고, 현재 프로젝트의 맥락을 우선 존중한다&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;TCA 프로젝트에 &quot;MVVM이 정석&quot;이라며 구조를 권한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 10가지 중 가장 자주 효과를 발휘하는 건 &lt;b&gt;3번과 10번&lt;/b&gt;이다. AI는 기본적으로 &quot;더 좋은 코드&quot;를 만들려 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그 의도는 좋지만, &lt;b&gt;&quot;더 좋은&quot;의 기준이 일반론인지 현재 프로젝트의 맥락인지&lt;/b&gt;에 따라 결과가 완전히 달라진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 원칙들이 없으면, Claude는 UIKit 프로젝트에서 SwiftUI를 권하고, SnapKit으로 통일된 프로젝트에서 Auto Layout을 제안한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 자산 보호: 하네스에서 가장 중요한 방어선&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;최상위 원칙 중에서도 별도 섹션으로 분리할 만큼 중요하게 다룬 것이 &lt;b&gt;기존 자산 보호&lt;/b&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AI 에이전트에게 지시하지 않으면, 기존 코드를 &quot;개선&quot;하려 한다. 변수명을 바꾸고, 함수를 분리하고, 더 &quot;깔끔한&quot; 구조로 리팩토링한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제는 이게 &lt;b&gt;요청하지 않은 변경&lt;/b&gt;이라는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;버그 하나 고치려고 했는데 파일 3개가 바뀌어 있으면, 리뷰 범위가 넓어지고 의도치 않은 사이드 이펙트가 생길 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그래서 다음과 같은 방어선을 명시적으로 정의했다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 코드를 함부로 대체하거나 전면 재작성하지 않는다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 UI/디자인 시스템을 함부로 변경하지 않는다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 아키텍처와 일관성을 우선 고려한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;변경은 &lt;b&gt;최소 침습적(minimally invasive)&lt;/b&gt; 방식으로 제안한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구조 변경이 필요한 경우, 먼저 이유, 영향 범위, 대안, 리스크를 설명한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;더 좋아 보이는 방법이 있더라도, 프로젝트의 일관성을 해치면 신중히 제안한다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그리고 해결책을 제시할 때는 &lt;b&gt;3단계로 나누어&lt;/b&gt; 개발자가 상황에 맞는 수준을 선택할 수 있게 했다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단계&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;설명&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;적용 시점&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;가장 작은 수정안&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 구조를 전혀 건드리지 않고 최소한의 변경&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;급한 핫픽스, 배포 직전&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;권장 개선안&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 구조 안에서 더 안전한 패턴으로 개선&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;일반적인 스프린트 작업&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;장기적 리팩토링안&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구조적 변경이 수반되지만 근본적으로 해결&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기술 부채 정리 기간&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;옳은 것과 적절한 것은 다르다. SwiftUI가 미래의 방향이라 해도, UIKit으로 80% 완성된 프로젝트에서 화면 하나를 SwiftUI로 만들면 그건 개선이 아니라 혼란이다. 이 구분을 AI에게 가르치는 것이 기존 자산 보호의 핵심이다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6개 팀 설계: 어떤 역할이 필요한가&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오케스트레이터의 핵심은 팀이다. iOS 개발 과정에서 반복적으로 필요한 역할들을 분석해서 &lt;b&gt;6개 전문 팀&lt;/b&gt;으로 나눴다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 구성의 원칙: 왜 모든 팀이 4명인가&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모든 팀은 &lt;b&gt;4명의 역할&lt;/b&gt;로 구성된다. 이건 임의로 정한 숫자가 아니라, 소프트웨어 개발의 기본 사이클을 반영한 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;역할&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기능&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 역할이 없으면&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;리드 (방향 설정)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제를 해석하고 작업 방향을 결정&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;목표 없이 작업이 흩어진다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;실행/분석 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실제 작업 수행 또는 분석&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;결정만 있고 실행이 없다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;검토 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;품질 점검, 영향 범위 확인, 사이드 이펙트 탐지&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실행 결과의 부작용을 놓친다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;문서 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기록, 정리, 재사용 가능한 자산화&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;같은 문제를 다음에 또 처음부터 해결한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단일 관점으로 결론을 내면 특정 측면이 빠진다. 구현만 생각하면 리뷰가 빠지고, 분석만 하면 문서화가 빠진다. 4명 구조는 이런 &lt;b&gt;관점의 누락을 구조적으로 방지&lt;/b&gt;하기 위한 장치다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다만 매번 4명의 관점을 장황하게 펼칠 필요는 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;작은 작업에서는 내부 협업 결과만 간단히 통합&lt;/b&gt;해서 제시하고, 큰 작업에서만 각 역할의 관점을 분명히 드러낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 내부에서 의견 차이가 있다면 무리하게 하나로 합치지 않고, 주요 선택지와 판단 근거를 함께 정리해서 개발자가 최종 결정을 내릴 수 있게 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 1: 개발 팀 &amp;mdash; 가장 자주 호출되는 팀&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코드를 직접 만지는 모든 작업이 이 팀을 거친다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #e8f4e8;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;역할&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;책임&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;개발 리드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제를 해석하고 구현 방향을 결정한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;구현 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실제 코드 수정, 기능 구현, 구조 반영을 수행한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;리뷰 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 코드와의 충돌, 영향 범위, 사이드 이펙트, 품질을 점검한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;문서 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;변경 내용, 적용 포인트, 주의점, 후속 작업을 정리한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;왜 리뷰 담당이 개발 팀 안에 있는가?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;별도의 리뷰 프로세스를 거치기 전에, &lt;b&gt;구현 단계에서부터 기존 코드와의 충돌을 1차로 점검&lt;/b&gt;하기 위해서다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;외과 수술에서 집도의와 별개로 수술실 내 확인 간호사가 있는 것과 같은 원리다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 2: 기획 팀 &amp;mdash; 범위 정의가 먼저&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;요구사항이 모호하거나 기능의 범위를 먼저 잡아야 할 때 호출된다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #e8e8f4;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;역할&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;책임&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;기획 리드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;요구사항과 기능 목적을 정리한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;플로우 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;유저 플로우와 화면 흐름을 정리한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;검증 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;범위 과다, 모호성, 빠진 요구사항을 점검한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;문서 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기획안, 결정 사항, 우선순위를 문서화한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;프로필 화면에 뱃지 시스템 추가해줘&quot;라는 요청이 들어왔다고 하자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;바로 코드를 쓰면 안 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;뱃지는 어떤 조건에서 획득하는지? 화면 어디에 보여주는지? 서버 API가 필요한지? &lt;b&gt;기획 팀이 이 정리를 먼저 하고, 정리된 결과를 개발 팀에 넘긴다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 3: 인사이트 팀 &amp;mdash; 학습과 기록의 선순환&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;새로운 기술이나 패턴을 학습할 때, 또는 &quot;이 API는 어떻게 쓰는 게 맞아?&quot;라는 질문에 답할 때 호출된다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f4e8e8;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;역할&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;책임&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;공식 문서 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Apple Developer Documentation, WWDC, 공식 샘플 코드 중심으로 조사한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;실무 적용 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 프로젝트에 실제로 어떻게 적용할지 분석한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;비교 분석 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다른 기술, 패턴, 접근 방식과의 차이점과 트레이드오프를 비교한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;문서 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;인사이트를 노션에 바로 붙여넣을 수 있게 정리하고 참고 링크를 포함한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 팀의 핵심은 &lt;b&gt;&quot;조사 &amp;rarr; 적용 &amp;rarr; 기록&quot;의 사이클&lt;/b&gt;이다. 단순히 &quot;이건 이래요&quot;가 아니라, &quot;이건 이렇고, 우리 프로젝트에는 이런 상황에서 적용하면 되고, 주의할 점은 이거&quot;까지 한 번에 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그리고 이 결과가 노션에 기록되어 팀 지식이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 개발에서 이 팀이 특히 중요한 이유는 &lt;b&gt;Apple 공식 문서 우선 참고&lt;/b&gt; 원칙 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AI가 블로그 글이나 Stack Overflow 답변을 기반으로 설명하면, deprecated API를 권하거나 outdated된 패턴을 제안할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;공식 문서 담당이 이걸 1차로 필터링한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 4: 트러블슈팅 작성 팀 &amp;mdash; 같은 문제를 두 번 풀지 않기 위해&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에러나 버그를 해결한 후, 그 과정을 체계적으로 기록하는 팀이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f4f4e8;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;역할&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;책임&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;문제 분석 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에러 현상, 재현 조건, 문제 상황을 정리한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;원인 추적 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;근본 원인(root cause)을 분석한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;해결 검토 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해결안, 대안, 재발 방지 포인트를 정리한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;문서 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;트러블슈팅 노션 템플릿에 맞게 구조화한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기록 양식을 통일해 놓은 것이 핵심이다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;제목&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제 상황&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;원인 분석&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;해결 방법&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;왜 이 해결이 적절한지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대안과 비교&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;재발 방지 포인트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;참고 자료 링크&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;관련 키워드 태그&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 양식을 따르면 3개월 후에 비슷한 에러가 발생했을 때, &lt;b&gt;노션에서 키워드 검색만으로 과거 해결 과정을 즉시 찾을 수 있다&lt;/b&gt;. 앞서 말한 &quot;일회성 작업의 반복&quot; 문제를 이 팀이 해결한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 5: 아키텍처 분석 팀 &amp;mdash; 가장 무거운 팀&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;새로운 기술 도입, 구조 변경, 아키텍처 결정이 필요할 때 호출된다. 신중하게 호출해야 하는 팀이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #e8f4f4;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;역할&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;책임&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;아키텍처 리드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;후보 구조와 판단 기준을 정의한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;프로젝트 적합성 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 프로젝트 특성과 제약조건을 분석한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;비교 검토 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다른 아키텍처와의 차이점, 장단점, 복잡도, 리스크를 비교한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;문서 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;ADR(Architecture Decision Record) 형태로 정리한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 팀의 특징은 결론만 내리지 않는다는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;반드시 &lt;b&gt;후보들의 장단점, 프로젝트 제약조건, 선택 이유, 제외 이유, 리스크&lt;/b&gt;를 함께 정리한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예를 들어 &quot;MVVM-C를 채택합니다&quot;로 끝나지 않는다. &quot;MVVM-C를 채택합니다. TCA도 고려했지만 학습 곡선과 현재 프로젝트 규모를 감안하면 MVVM-C가 더 적절합니다. 다만 상태 관리가 복잡해지면 부분적으로 TCA 도입을 재검토할 필요가 있습니다&quot;까지 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 6: 프로젝트 검수 팀 &amp;mdash; 배포 전 마지막 관문&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;배포 전 안정성 점검이나 성능 최적화 검토 시 호출된다. 코드를 직접 수정하지 않고, &lt;b&gt;진단과 권장사항만 제시&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f4e8f4;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;역할&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;책임&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;품질 검수 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기능 완성도와 에러 가능성을 점검한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;성능 검수 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;메모리, 렌더링, 동시성, 최적화 포인트를 점검한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;일관성 검수 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 코드 스타일, 디자인, 구조 훼손 여부를 검토한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;문서 담당&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;검수 결과, 수정 권장사항, 체크리스트를 정리한다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;검수 결과는 &lt;b&gt;&quot;바로 수정 가능한 포인트&quot;와 &quot;장기 개선 포인트&quot;를 구분&lt;/b&gt;해서 정리한다. 배포 전에 반드시 고쳐야 할 것과, 다음 스프린트에서 개선해도 되는 것을 명확히 나누는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6개 팀 전체 구조&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6개 팀을 한눈에 보면 이렇다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;1c&quot; style=&quot;background-color: #f8f8f8; padding: 20px; border-radius: 8px; overflow-x: auto; font-size: 13px; line-height: 1.6;&quot;&gt;&lt;code&gt;                     ┌──────────────────────┐
                     │    오케스트레이터      │
                     │   (요청 분류 &amp;amp; 통합)   │
                     └──────────┬───────────┘
                                │
         ┌──────────────────────┼──────────────────────┐
         │                      │                      │
    ┌────┴────┐           ┌────┴────┐           ┌────┴────┐
    │ 개발 팀  │           │ 기획 팀  │           │인사이트팀│
    │         │           │         │           │         │
    │ 리드    │           │ 리드    │           │ 공식문서 │
    │ 구현    │           │ 플로우  │           │ 실무적용 │
    │ 리뷰    │           │ 검증    │           │ 비교분석 │
    │ 문서    │           │ 문서    │           │ 문서    │
    └─────────┘           └─────────┘           └─────────┘

    ┌─────────┐           ┌─────────┐           ┌─────────┐
    │트러블슈팅│           │아키텍처 │           │프로젝트 │
    │ 작성 팀  │           │ 분석 팀  │           │ 검수 팀  │
    │         │           │         │           │         │
    │ 문제분석 │           │ 리드    │           │ 품질    │
    │ 원인추적 │           │ 적합성  │           │ 성능    │
    │ 해결검토 │           │ 비교검토 │           │ 일관성  │
    │ 문서    │           │ 문서    │           │ 문서    │
    └─────────┘           └─────────┘           └─────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 호출 규칙: 과잉 대응을 방지하는 핵심 로직&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6개 팀을 만들어놓고 매번 다 부르면 의미가 없다. &lt;b&gt;요청의 성격에 따라 필요한 팀만 골라 쓰는 규칙&lt;/b&gt;이 오케스트레이터의 핵심 로직이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;요청 유형&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;호출 팀&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이유&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;간단한 구현 요청&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;개발 팀&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코드만 수정하면 되므로 다른 팀 불필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;요구사항이 모호한 기능 요청&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;기획 팀 &amp;rarr; 개발 팀&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;범위 정의 후 구현. 순서가 중요하다&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에러/버그 해결&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;개발 팀 + 트러블슈팅 팀&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;수정과 기록을 동시에 진행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;새로운 기술/패턴 학습&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;인사이트 팀&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;조사와 정리만 필요하므로 개발 팀 불필요&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기술 도입/구조 변경 검토&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;아키텍처 팀 + 인사이트 팀&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구조 분석과 기술 조사를 병행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;배포 전 안정성 점검&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;프로젝트 검수 팀&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코드 수정 없이 진단만 수행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;큰 구조 변경이 포함된 요청&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;기획 팀 + 아키텍처 팀 + 개발 팀&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;범위 정의 &amp;rarr; 구조 설계 &amp;rarr; 구현의 풀 사이클&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;추가 규칙이 하나 더 있다: &lt;b&gt;기록 가치가 있는 문제나 학습 내용이 나오면, 해당 작업 후 문서화 팀을 추가 호출&lt;/b&gt;한다. 트러블슈팅이 될 수도 있고, 인사이트가 될 수도 있다. 이 판단은 오케스트레이터가 자동으로 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비효율 경고 시스템: 과잉 프로세스 방지 장치&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;체계적인 시스템을 만들면 생기는 부작용이 있다. &lt;b&gt;과잉 프로세스&lt;/b&gt;다. 변수명 하나 바꾸는데 6개 팀이 동원되고 ADR이 작성되면, 그건 체계가 아니라 관료주의다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AI에게 &quot;과잉 대응하지 마&quot;라고 명시적으로 알려주지 않으면, 기본적으로 가장 무거운 프로세스를 적용하려 한다. 이 문제를 해결하기 위해 &lt;b&gt;비효율 경고 레벨&lt;/b&gt;을 설계했다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center; width: 80px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;레벨&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;상태&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오케스트레이터의 행동&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center; color: green;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Level 1&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 방식이 적절함&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그대로 진행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center; color: #cc9900;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Level 2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;약간 비효율적이지만 진행 가능&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;진행하되 참고 수준으로 언급&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center; color: orange;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Level 3&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 호출이나 작업 범위를 줄이는 것이 좋음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;더 가벼운 워크플로우를 제안&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center; color: red;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Level 4&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 방식은 과도함&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;더 단순한 워크플로우로 전환 권장&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비효율을 감지하면 단순히 &quot;비효율적입니다&quot;로 끝나지 않는다. 반드시 다음을 함께 보고하도록 설계했다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;어떤 부분이 비효율적인지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;왜 비효율적인지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 단계에서 더 적절한 대안은 무엇인지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;생략하거나 통합할 수 있는 팀 또는 작업은 무엇인지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;속도와 품질을 균형 있게 유지하는 추천 작업 방식&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;설계 의도: 이 시스템의 핵심은 &quot;AI가 스스로 자기 프로세스를 점검하게 만드는 것&quot;이다. 사람이 매번 &quot;이건 너무 과하다&quot;라고 지적하는 대신, 오케스트레이터 자체에 자기 점검 메커니즘을 내장시켰다. 실제로 사용하다 보면 오케스트레이터가 &quot;이 작업은 Level 3입니다. 인사이트 팀 없이 개발 팀만으로 충분합니다&quot;라고 스스로 판단하는 경우가 생긴다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;작업 흐름: 7단계 파이프라인&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오케스트레이터가 요청을 받으면 항상 다음 순서로 처리한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;gradle&quot; style=&quot;background-color: #f8f8f8; padding: 20px; border-radius: 8px; overflow-x: auto; font-size: 14px; line-height: 1.8;&quot;&gt;&lt;code&gt;Step 1  요청의 성격을 파악한다
           &amp;darr;
Step 2  이 요청이 어떤 팀의 작업인지 분류한다
           &amp;darr;
Step 3  필요한 팀만 호출한다
           &amp;darr;
Step 4  기존 프로젝트 프롬프트와 충돌하는지 확인한다
           &amp;darr;
Step 5  기존 코드/디자인/구조를 해치지 않는 방향으로 해결책을 만든다
           &amp;darr;
Step 6  필요하면 참고 자료와 근거를 함께 정리한다
           &amp;darr;
Step 7  기록 가치가 있는 경우 노션용 형식으로 정리한다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Step 4&lt;/b&gt;가 특히 중요하다. 4개의 프로젝트를 동시에 운영하다 보면, A 프로젝트의 규칙이 B 프로젝트에 섞여 들어갈 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트별 CLAUDE.md가 존재하면 글로벌 규칙보다 이것이 우선한다는 것을 명시적으로 확인하는 단계다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Step 7&lt;/b&gt;도 눈에 띄는 단계다. 매 작업이 끝날 때 &quot;이 작업에서 기록할 만한 것이 있는가?&quot;를 자동으로 판단한다. 있다면 트러블슈팅 양식이나 인사이트 양식으로 정리하고, 노션 MCP를 통해 자동 기록한다. 이 단계 덕분에 &lt;b&gt;작업이 곧 기록&lt;/b&gt;이 된다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;멀티 프로젝트 운영: 글로벌과 프로젝트의 분리&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4개 프로젝트를 동시에 운영하면서 가장 신경 쓴 부분이 &lt;b&gt;컨텍스트 분리&lt;/b&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;계층&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;위치&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;담당 내용&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;글로벌 CLAUDE.md&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6개 팀 구성, 최상위 원칙, 팀 호출 규칙, 비효율 경고, 기록 규칙, 출력 프로토콜&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;프로젝트 CLAUDE.md&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;./CLAUDE.md&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트 팀(10명), 스킬(11개), 파이프라인 규칙, 기술 스택, 디자인 토큰&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;글로벌 CLAUDE.md에는 &quot;어떤 팀이 있고, 어떤 원칙을 따르는가&quot;라는 &lt;b&gt;운영 체계&lt;/b&gt;가 들어간다. 프로젝트 CLAUDE.md에는 &quot;이 프로젝트는 어떤 기술 스택이고, 에이전트는 어떻게 동작하는가&quot;라는 &lt;b&gt;실행 규칙&lt;/b&gt;이 들어간다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 분리 덕분에 같은 오케스트레이터 원칙을 공유하면서도, 프로젝트마다 완전히 다른 환경에서 작업할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code의 CLAUDE.md는 override가 아니라 병합(concatenation)된다. 글로벌과 프로젝트 CLAUDE.md가 동시에 로드되면서, 나중에 읽힌 프로젝트 규칙이 더 높은 우선순위를 가진다. 이 메커니즘 덕분에 글로벌 원칙을 기본으로 깔되, 프로젝트별로 다른 세부 규칙을 적용하는 것이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;출력 프로토콜: 매번 같은 포맷으로&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;오케스트레이터의 모든 출력은 다음 7가지를 포함하도록 규격화했다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;이번 요청의 성격&lt;/b&gt; &amp;mdash; &quot;이건 버그 수정 요청입니다&quot;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;호출할 팀&lt;/b&gt; &amp;mdash; 어떤 팀이 투입되었는지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;왜 그 팀이 필요한지&lt;/b&gt; &amp;mdash; 팀 선택의 근거&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;실제 해결 내용&lt;/b&gt; &amp;mdash; 작업 결과물&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;기존 코드/디자인을 어떻게 보호했는지&lt;/b&gt; &amp;mdash; 기존 자산 보호 관점 리포트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;참고 자료&lt;/b&gt; (필요 시) &amp;mdash; 링크와 참고 이유&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;노션용 정리 내용&lt;/b&gt; (필요 시) &amp;mdash; 트러블슈팅/인사이트 기록 양식&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5번이 핵심이다. 매 작업마다 &lt;b&gt;&quot;기존 것을 어떻게 보호했는지&quot;를 명시적으로 보고&lt;/b&gt;하게 함으로써, AI가 의도치 않게 기존 코드를 훼손하는 것을 구조적으로 방지한다. 보고서에 이 항목이 빠져 있으면, 뭔가 빼먹은 거다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;노션 자동 기록: 지식 자산화의 마지막 퍼즐&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;설계의 출발점에서 언급한 &quot;일회성 작업의 반복&quot; 문제, 그 해답이 노션 자동 기록이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;MCP(Model Context Protocol)를 통해 노션과 연동하고, 오케스트레이터가 기록이 필요하다고 판단하면 &lt;b&gt;노션 DB에 직접 페이지를 생성&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기록 프로세스&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;excel&quot; style=&quot;background-color: #f8f8f8; padding: 20px; border-radius: 8px; overflow-x: auto; font-size: 14px; line-height: 1.8;&quot;&gt;&lt;code&gt;작업 완료
    &amp;darr;
기록 대상인지 판단 (오케스트레이터 자동)
    &amp;darr;
&quot;노션에 기록할까요?&quot; 확인
    &amp;darr;
Notion MCP로 DB에 페이지 생성 + 본문 작성
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;트러블슈팅과 인사이트는 별도의 노션 DB로 분리 운영한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;각각의 속성(날짜, 상태, 유형, 프로젝트명)이 자동으로 채워지고, 본문은 앞서 정의한 표준 양식을 따른다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사용자가 &quot;기록해줘&quot;라고 명시적으로 요청하면 확인 없이 바로 기록한다. 매번 물어보는 것도 불필요한 오버헤드이기 때문에, 이런 세밀한 조건 분기도 설계에 포함시켰다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대규모 변경 주의 원칙&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마지막으로, 오케스트레이터에 하나 더 장치를 넣었다. 다음에 해당하는 작업은 &lt;b&gt;대규모 변경&lt;/b&gt;으로 간주한다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;파일 구조 전면 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;아키텍처 교체&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;디자인 시스템 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;외부 라이브러리 추가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;데이터 모델 대규모 수정&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;대규모 변경이 감지되면 오케스트레이터는 바로 코드부터 쓰지 않는다. 먼저 영향 범위, 리스크, 대안, 기대 효과를 정리하고, &lt;b&gt;항상 가장 작은 수정으로 해결 가능한지 먼저 검토&lt;/b&gt;한다. 작은 수정으로 해결되지 않을 때만 구조 개선안을 제안한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이건 AI의 기본 성향을 제어하기 위한 장치다. Claude는 기본적으로 &quot;깔끔한 해결&quot;을 선호한다. 제어하지 않으면 작은 문제에도 큰 리팩토링을 시작하려 한다. &lt;b&gt;&quot;가장 작은 수정부터&quot;&lt;/b&gt;라는 원칙이 이걸 막아준다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마치며&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Harness 플러그인을 쓰지 않고 직접 만든 이유는 &quot;원리를 이해하고, 나에게 맞는 것을 만들기 위해서&quot;라고 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실제로 직접 설계하면서 얻은 것을 정리하면 이렇다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;원리에 대한 이해&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;CLAUDE.md에 적은 규칙이 왜 지켜지고, 왜 가끔 안 지켜지는지 &amp;mdash; 문맥 길이와 규칙 준수율의 관계를 체감했다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트를 분리하는 것의 실질적 이점과 오버헤드 &amp;mdash; 무조건 나누는 게 좋은 건 아니라는 것&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AI에게 &quot;하지 마&quot;를 가르치는 것이 &quot;해라&quot;를 가르치는 것보다 어렵다는 것&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;나에게 맞는 시스템&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4개 프로젝트의 컨텍스트 분리가 자연스럽게 작동한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;트러블슈팅과 인사이트가 자동으로 노션에 쌓인다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Apple 공식 문서 우선 참고라는 내 습관이 시스템에 녹아들었다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비효율 경고 시스템 덕분에 과잉 프로세스에 시달리지 않는다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;물론 이 오케스트레이터도 완벽하지 않다. 약 260줄의 CLAUDE.md는 권장 200줄을 넘기고, 6개 팀의 4인 구조가 항상 최적인지는 더 실험이 필요하다. 하지만 &lt;b&gt;직접 만들었기 때문에 어디를 고쳐야 하는지 안다&lt;/b&gt;. 블랙박스를 쓰면 문제가 생겼을 때 어디를 봐야 하는지 모른다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Claude</category>
      <category>Claude</category>
      <category>claude code</category>
      <category>Harness</category>
      <category>IOS</category>
      <category>공공돌</category>
      <category>오케스트레이터 설계</category>
      <category>하네스</category>
      <category>하네스 엔지니어링</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/190</guid>
      <comments>https://sheep1sik.tistory.com/190#entry190comment</comments>
      <pubDate>Fri, 10 Apr 2026 15:44:45 +0900</pubDate>
    </item>
    <item>
      <title>[ Claude ] 하네스 엔지니어링이란 무엇인가?</title>
      <link>https://sheep1sik.tistory.com/189</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code를 쓰다 보면 한 가지 불편함을 느끼게 된다. 분명 똑똑한 도구인데, &lt;b&gt;매 대화마다 같은 맥락을 반복 설명해야 한다&lt;/b&gt;는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;나는 iOS 개발자고, 이 프로젝트는 UIKit 기반이고, 아키텍처는 이렇고, 코드 스타일은 저렇고...&quot;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;매번 이걸 말해줘야 Claude가 프로젝트에 맞는 답을 준다. 안 그러면? 일반적인 베스트 프랙티스를 그대로 던져주거나, 내 프로젝트 컨텍스트와 동떨어진 제안을 한다. 코드를 통째로 재작성하거나, 기존 설계를 무시한 &quot;더 좋은&quot; 구조를 권하기도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이건 Claude의 문제가 아니다. &lt;b&gt;구조의 부재&lt;/b&gt;가 문제다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;AI 에이전트에게 &quot;어떻게 일해야 하는지&quot;를 체계적으로 정의해주지 않으면, 매번 다른 방식으로 작동할 수밖에 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 문제를 해결하기 위해 AI 에이전트의 행동 체계를 설계하고 구축하는 접근법 &lt;b&gt;하네스 엔지니어링(Harness Engineering)&lt;/b&gt;에 대해 이야기하려 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스(Harness)란 무엇인가&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;사전적 의미에서 출발하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Harness의 사전적 의미는 &quot;마구(馬具)&quot; &amp;mdash; 말의 힘을 제어하고 원하는 방향으로 전달하는 장비다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;소프트웨어 세계에서도 같은 의미로 쓰인다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Test Harness&lt;/b&gt; &amp;mdash; 테스트를 체계적으로 실행하고 결과를 수집하기 위한 프레임워크&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;Wiring Harness&lt;/b&gt; &amp;mdash; 복잡한 전선들을 체계적으로 묶고 연결하는 구조물&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;공통점이 보이는가? 하네스의 본질은 &lt;b&gt;&quot;강력하지만 제멋대로인 힘을, 체계적으로 제어하고 원하는 방향으로 이끄는 구조&quot;&lt;/b&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code에서의 하네스도 정확히 같은 맥락이다. &lt;b&gt;AI 에이전트의 능력을 제어하고, 방향을 잡아주고, 체계적으로 작동하게 만드는 구조적 틀&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그렇다면 하네스 엔지니어링이란?&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스가 &quot;틀&quot;이라면, 하네스 엔지니어링은 &lt;b&gt;그 틀을 설계하고, 구축하고, 검증하고, 지속적으로 진화시키는 과정&lt;/b&gt; 전체를 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단순히 CLAUDE.md에 규칙 몇 줄 적는 것이 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다음과 같은 질문에 대한 답을 구조화하는 것이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;설계:&lt;/b&gt; 어떤 에이전트가 필요한가? 어떤 아키텍처 패턴으로 협업시킬 것인가?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;구축:&lt;/b&gt; 에이전트의 역할, 원칙, 통신 프로토콜을 어떻게 정의할 것인가?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;검증:&lt;/b&gt; 의도한 대로 작동하는가? 기존 자산을 보호하고 있는가?&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;진화:&lt;/b&gt; 실전 피드백을 어떻게 반영하고, 하네스를 어떻게 개선할 것인가?&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;소프트웨어 엔지니어링이 &quot;코드를 짜는 것&quot;이 아니라 &quot;소프트웨어를 체계적으로 만드는 것&quot;인 것처럼,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스 엔지니어링은 &lt;b&gt;&quot;AI 에이전트의 행동 체계를 엔지니어링하는 것&quot;&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스의 구성 요소&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구체적으로 하네스는 다음을 포함하는 &lt;b&gt;사전 설정(Pre-Configuration) 체계&lt;/b&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구성 요소&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;역할&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;위치&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예시&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;CLAUDE.md&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;운영 원칙과 작업 규칙&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트 루트 또는 &lt;code&gt;~/.claude/&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;기존 코드를 함부로 재작성하지 않는다&quot;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;에이전트 정의&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;전문 역할을 가진 AI 에이전트 설계&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;.claude/agents/*.md&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개발 리드, 리뷰 담당, 문서 담당&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;스킬&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트가 따르는 구체적 작업 절차&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;.claude/skills/*/SKILL.md&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;트러블슈팅 기록 양식, 코드 리뷰 절차&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;플러그인&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;확장 기능과 워크플로우 자동화&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;settings.json&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;superpowers, code-review&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;MCP 서버&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;외부 도구와의 양방향 연동&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;settings.json&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;노션 자동 기록, Figma 디자인 연동&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한 마디로, &lt;b&gt;&quot;Claude야, 너는 이런 환경에서 이런 원칙으로 이렇게 일해&quot;&lt;/b&gt;를 코드처럼 정의해놓는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스 엔지니어링을 위한 Claude Code 기초&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스를 설계하려면, 그 토대가 되는 Claude Code의 핵심 메커니즘을 먼저 이해해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;CLAUDE.md &amp;mdash; 프로젝트의 기억 장치&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;CLAUDE.md는 Claude Code에게 &lt;b&gt;&quot;이 프로젝트에서는 이렇게 일해&quot;&lt;/b&gt;라고 알려주는 마크다운 파일이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스의 최상위 계층이자, 모든 운영 원칙이 시작되는 곳이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;작동 방식&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;매 세션(대화) 시작 시 자동으로 로드된다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;현재 작업 디렉토리에서 상위 디렉토리까지 순회하며 모든 CLAUDE.md를 찾아 병합한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;system prompt가 아니라 &lt;b&gt;user message 형태로&lt;/b&gt; 주입된다 (이 점이 중요한데, system prompt보다 유연하게 확장 가능하다는 뜻이다)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;/compact&lt;/code&gt; 명령으로 대화를 압축해도 CLAUDE.md는 디스크에서 다시 읽어 재주입된다 &amp;mdash; 즉, 대화가 아무리 길어져도 CLAUDE.md의 규칙은 사라지지 않는다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;계층 구조 (아래로 갈수록 우선순위 높음)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;범위&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;위치&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;공유 범위&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;용도&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;글로벌&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;~/.claude/CLAUDE.md&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;본인 전체&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모든 프로젝트 공통 원칙&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;./CLAUDE.md&lt;/code&gt; 또는 &lt;code&gt;./.claude/CLAUDE.md&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀 (git 추적)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트별 규칙&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;로컬&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;./CLAUDE.local.md&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;본인만&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개인 작업 환경 설정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;여러 CLAUDE.md가 발견되면 &lt;b&gt;override가 아니라 모두 병합(concatenation)&lt;/b&gt;된다. 다만 나중에 읽힌 것이 우선하므로, 프로젝트 CLAUDE.md가 글로벌보다 높은 우선순위를 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;하네스 엔지니어링 관점에서의 함의&lt;br /&gt;공식 문서에서는 CLAUDE.md를 200줄 이하로 유지할 것을 권장한다. &lt;br /&gt;내용이 길어지면 컨텍스트 윈도우 소비가 커지고, 규칙 준수율(adherence)이 떨어진다. &lt;br /&gt;이것이 하네스 엔지니어링이 단순히 &quot;규칙을 많이 적는 것&quot;이 아닌 이유다 .&lt;br /&gt;제한된 공간 안에서 최대 효과를 내는 구조를 설계해야 한다.&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트와 스킬 &amp;mdash; &quot;누가&quot;와 &quot;어떻게&quot;의 분리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code는 두 가지 핵심 확장 메커니즘을 공식적으로 지원한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 둘의 분리가 하네스 엔지니어링의 핵심 설계 철학이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;에이전트 (Agents) &amp;mdash; &quot;누가&quot; 하는가&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;.claude/agents/*.md&lt;/code&gt;에 마크다운으로 정의한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;각 에이전트는 고유한 역할, 원칙, 프로토콜을 가진다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;/agents&lt;/code&gt; 명령으로 생성/관리 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;빌트인 타입: &lt;code&gt;general-purpose&lt;/code&gt;(범용), &lt;code&gt;Explore&lt;/code&gt;(코드 탐색 전용, 읽기 전용), &lt;code&gt;Plan&lt;/code&gt;(설계 전용)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;스킬 (Skills) &amp;mdash; &quot;어떻게&quot; 하는가&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;.claude/skills/*/SKILL.md&lt;/code&gt;에 YAML frontmatter + 마크다운으로 정의한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트가 작업 시 참조하는 절차적 가이드&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;트리거 조건에 따라 자동 활성화되거나, 사용자가 명시적으로 호출&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 분리가 왜 중요한가?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단순히 CLAUDE.md에 &quot;코드 리뷰할 때는 보안, 성능, 스타일을 체크해&quot;라고 적는 것과, 보안 전문 에이전트/성능 전문 에이전트/스타일 전문 에이전트를 각각 정의하고 코드 리뷰 스킬을 부여하는 것은 &lt;b&gt;결과물의 깊이가 다르다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;소프트웨어 공학에서 말하는 &lt;b&gt;관심사의 분리(Separation of Concerns)&lt;/b&gt;와 같은 원리다. 하나의 거대한 모놀리스보다, 전문화된 모듈들의 조합이 더 나은 결과를 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트 팀 &amp;mdash; 에이전트 간 실시간 협업&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2개 이상의 에이전트가 &lt;b&gt;실시간으로 소통하며 협업&lt;/b&gt;하는 기능이다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Agent Teams는 2026년 4월 현재 여전히 Experimental 기능이다. CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 환경변수를 설정해야 활성화되며, Claude Code v2.1.32 이상이 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;에이전트 팀 vs 서브 에이전트&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;항목&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트 팀&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;서브 에이전트&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;생성 도구&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;TeamCreate&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;Agent&lt;/code&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트 간 통신&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;SendMessage&lt;/code&gt;로 직접 통신 가능&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;통신 불가, 결과만 반환&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;작업 조율&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;공유 작업 목록으로 자체 조율&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;메인 에이전트가 모든 조율 담당&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;상호 검증&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팀원 간 도전/피드백 가능&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;불가&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;토큰 비용&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;상대적으로 높음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;효율적&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;적합 상황&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2+ 에이전트 협업 필요 시&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단발성 독립 작업&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트 팀의 핵심 이점은 &lt;b&gt;&quot;발견 공유, 상충 토론, 누락 보완&quot;&lt;/b&gt;이 가능하다는 점이다. 예를 들어 보안 에이전트가 발견한 취약점을 성능 에이전트가 참고해서 수정 방향을 조율할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;알려진 제한 사항&lt;/b&gt;&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;세션당 하나의 팀만 운영 가능 (단, Phase별로 팀을 해체하고 재구성할 수 있음)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;중첩 팀 불가 (팀원이 자체 팀 생성 불가)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;리더 고정 (리더십 이전 불가)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;/resume&lt;/code&gt;, &lt;code&gt;/rewind&lt;/code&gt;로 세션 복원 시 teammate 복원 불가&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;플러그인 시스템&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code는 공식 플러그인 마켓플레이스를 운영한다. &lt;code&gt;/plugin&lt;/code&gt; 명령으로 검색, 설치, 관리가 가능하며, 서드파티 마켓플레이스도 추가할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;플러그인은 에이전트, 스킬, 설정을 패키징한 배포 단위다. 예를 들어 &lt;code&gt;superpowers&lt;/code&gt; 플러그인은 brainstorming, TDD, debugging 등의 스킬을 한 번에 제공하고, &lt;code&gt;code-review&lt;/code&gt; 플러그인은 PR 리뷰 전용 워크플로우를 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스 엔지니어링 관점에서 플러그인은 &lt;b&gt;&quot;이미 잘 만들어진 하네스 조각&quot;&lt;/b&gt;이다. 처음부터 모든 것을 직접 만들 필요 없이, 검증된 플러그인을 기반으로 내 프로젝트에 맞게 확장하는 접근이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;왜 하네스 엔지니어링이 필요한가&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code를 &quot;있는 그대로&quot; 쓰면 어떤 문제가 생기는지, 그리고 하네스 엔지니어링이 각 문제를 어떻게 해결하는지를 정리한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제 1: 컨텍스트의 휘발성&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code는 대화 세션이 끝나면 컨텍스트를 잃는다. CLAUDE.md가 이 문제를 일부 해결하지만, &quot;이 프로젝트는 Swift로 작성되었습니다&quot; 수준의 정보로는 부족하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;하네스 엔지니어링의 해법:&lt;/b&gt; 작업 방식 자체를 구조화한다. 어떤 요청이 들어오면 어떤 팀이 담당하고, 어떤 순서로 처리하고, 어떤 원칙을 지켜야 하는지가 미리 정의되어 있다. 세션이 바뀌어도 이 구조는 CLAUDE.md와 에이전트/스킬 파일에 남아있으므로, 매번 처음부터 설명할 필요가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제 2: 일관성 없는 출력 품질&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;같은 질문을 해도 Claude의 답변 품질이 들쭉날쭉할 때가 있다. 어떤 때는 기존 코드를 존중한 최소한의 수정안을 주고, 어떤 때는 전체 파일을 새로 작성해버린다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;하네스 엔지니어링의 해법:&lt;/b&gt; 출력의 분산을 구조적으로 줄인다. 실제로 Harness 플러그인 제작자(revfactory)가 수행한 A/B 테스트 연구 결과가 이를 뒷받침한다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실험 설계: 15개 소프트웨어 엔지니어링 과제(Basic 5, Advanced 5, Expert 5)에 대해, Baseline(프롬프트만)과 Harness(.claude/ 사전 구성 포함)를 비교&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;지표&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Baseline&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Harness 적용&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;변화&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;평균 품질 점수&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;49.5&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;79.3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;+60%&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;승률&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;mdash;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;mdash;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;15전 15승 (100%)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;표준편차&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5.3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3.6&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;-32%&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;특히 과제 난이도가 높을수록 개선 효과가 증대했다 (Basic +23.8, Advanced +29.6, Expert +36.2).&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666; font-size: 0.9em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #666; font-size: 0.9em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;출처: &lt;a href=&quot;https://github.com/revfactory/claude-code-harness&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revfactory/claude-code-harness&lt;/a&gt; &amp;mdash; 이 수치는 플러그인 제작자의 &lt;b&gt;자체 실험&lt;/b&gt; 결과이며 외부 독립 검증을 거친 것은 아니다. 다만 실험 설계와 원시 데이터가 GitHub에 공개되어 있어 재현 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #666; font-size: 0.9em;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;수치의 신뢰도를 떠나, 시사하는 바는 명확하다. &lt;b&gt;구조화된 사전 설정이 AI 에이전트의 출력 품질과 일관성을 유의미하게 끌어올린다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제 3: 기존 자산의 보호&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;개인적으로 이것이 하네스 엔지니어링을 시작한 가장 큰 이유다. iOS 프로젝트에서 Claude Code를 쓰다 보면, 기존에 잘 작동하던 코드를 &quot;더 좋은&quot; 구조로 바꾸려는 시도가 빈번하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;구체적으로 겪었던 상황들&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;코드 스타일 침범:&lt;/b&gt; 프로젝트 전체가 특정 네이밍 컨벤션을 쓰고 있는데, 갑자기 다른 스타일로 코드를 작성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;아키텍처 무시:&lt;/b&gt; 기존에 MVVM으로 구성된 모듈에 MVC 패턴의 코드를 끼워넣음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;과잉 리팩토링:&lt;/b&gt; &quot;이 부분 버그 수정해줘&quot;라고 했는데 주변 코드까지 전면 재작성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;비공식 패턴 도입:&lt;/b&gt; Apple 공식 문서가 아닌 출처의 패턴을 검증 없이 적용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;하네스 엔지니어링의 해법:&lt;/b&gt; 기존 자산 보호 원칙을 구조적으로 정의한다. &quot;더 좋아 보이는 방법이 있더라도, 현재 프로젝트의 일관성과 유지보수성을 해치면 신중히 제안한다&quot; &amp;mdash; 이런 규칙이 에이전트의 행동을 제약한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제 4: 지식의 소실&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code와 나눈 대화에서 유의미한 발견들이 종종 나온다. 특정 API의 숨겨진 동작, 까다로운 버그의 근본 원인, 아키텍처 결정의 근거 등. 하지만 이런 지식은 대화 세션이 끝나면 사라진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;하네스 엔지니어링의 해법:&lt;/b&gt; 기록 규칙과 외부 연동을 설계한다. 트러블슈팅 과정이나 새로운 인사이트를 정해진 양식으로 정리하고, MCP 서버를 통해 노션 같은 외부 도구에 자동 기록되는 파이프라인을 구축한다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제 5: 과잉 처리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단순 구현 요청에 아키텍처 분석까지, 작은 버그 수정에 전체 모듈 리팩토링 제안까지. 작업의 크기에 맞지 않는 과도한 프로세스가 기본값이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;하네스 엔지니어링의 해법:&lt;/b&gt; 작업의 크기와 성격에 따라 호출할 팀과 프로세스 수준을 미리 분류해둔다. 간단한 구현 요청은 개발 팀만, 큰 구조 변경은 기획 + 아키텍처 + 개발 팀을 호출하는 식으로 &lt;b&gt;작업에 비례하는 프로세스&lt;/b&gt;를 설계한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스의 구성 계층&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스는 하나의 파일이 아니다. 여러 계층이 조합되어 하나의 체계를 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;┌─────────────────────────────────────────────────────┐
│               CLAUDE.md (최상위 규칙)                  │
│   운영 원칙 / 팀 구성 / 작업 흐름 / 호출 규칙 / 기록 규칙   │
├─────────────────────────────────────────────────────┤
│          에이전트 정의 (.claude/agents/*.md)            │
│      각 에이전트의 역할, 원칙, 통신 프로토콜 정의           │
│      &amp;rarr; &quot;누가&quot; 작업하는가                                │
├─────────────────────────────────────────────────────┤
│           스킬 (.claude/skills/*/SKILL.md)             │
│        에이전트가 따르는 구체적 작업 절차 정의              │
│        &amp;rarr; &quot;어떻게&quot; 작업하는가                             │
├─────────────────────────────────────────────────────┤
│          플러그인 (settings.json &amp;rarr; plugins)             │
│      사전 패키징된 에이전트/스킬 세트 (마켓플레이스)         │
├─────────────────────────────────────────────────────┤
│         MCP 서버 (settings.json &amp;rarr; mcpServers)          │
│        외부 도구 양방향 연동 (노션, Figma 등)              │
├─────────────────────────────────────────────────────┤
│                  settings.json                        │
│          모델, 플러그인 활성화, LSP, 언어 설정             │
└─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;각 계층은 독립적으로도 의미가 있지만, 조합했을 때 비로소 &lt;b&gt;&quot;체계&quot;&lt;/b&gt;가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;CLAUDE.md에 &quot;트러블슈팅은 이 양식으로 정리해&quot;라고 규칙을 적는다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;트러블슈팅 전문 에이전트를 &lt;code&gt;.claude/agents/troubleshooter.md&lt;/code&gt;에 정의한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;트러블슈팅 스킬을 &lt;code&gt;.claude/skills/troubleshoot/SKILL.md&lt;/code&gt;에 작성한다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;노션 MCP 서버를 연결한다&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이렇게 하면 버그를 해결할 때 &amp;rarr; 트러블슈팅 에이전트가 활성화되고 &amp;rarr; 정해진 스킬에 따라 원인을 분석하고 &amp;rarr; 결과를 노션 DB에 자동 기록하는 파이프라인이 완성된다. 이것이 하네스 엔지니어링이 추구하는 &lt;b&gt;end-to-end 자동화&lt;/b&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Harness 플러그인 &amp;mdash; 하네스 엔지니어링 도구&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;위에서 설명한 하네스 체계를 직접 처음부터 설계할 수도 있지만, &lt;b&gt;Harness 플러그인&lt;/b&gt;을 활용하면 이 과정을 체계적으로 가이드받을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Harness 플러그인이란&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;a href=&quot;https://github.com/revfactory/harness&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revfactory/harness&lt;/a&gt;는 Claude Code 플러그인으로 설치할 수 있는 &lt;b&gt;메타 스킬(Meta-Skill)&lt;/b&gt;이다. &quot;메타&quot;라고 부르는 이유는, 이 스킬 자체가 다른 에이전트와 스킬을 &lt;b&gt;생성&lt;/b&gt;하는 스킬이기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;하네스 구성해줘&quot;라고 말하면, 사용자의 도메인에 맞는 에이전트 팀과 스킬을 자동으로 설계하고, &lt;code&gt;.claude/agents/&lt;/code&gt;와 &lt;code&gt;.claude/skills/&lt;/code&gt; 디렉토리에 파일을 생성하고, CLAUDE.md에 하네스 컨텍스트를 등록하는 것까지 처리한다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; background-color: #f5f5f5; width: 120px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;현재 버전&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1.1.0 (2026-04-05 릴리스)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; background-color: #f5f5f5;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;라이선스&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Apache 2.0&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; background-color: #f5f5f5;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;제작자&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;robin (revfactory)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; background-color: #f5f5f5;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;초기 릴리스&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1.0.0 (2026-03-27)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6가지 아키텍처 패턴&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스 엔지니어링에서 가장 중요한 설계 결정 중 하나가 &lt;b&gt;&quot;에이전트들을 어떤 구조로 협업시킬 것인가&quot;&lt;/b&gt;다. Harness 플러그인은 6가지 아키텍처 패턴을 지원한다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1. 파이프라인 (Pipeline)&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;[분석] &amp;rarr; [설계] &amp;rarr; [구현] &amp;rarr; [검증]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;각 단계가 이전 단계의 산출물에 강하게 의존하는 &lt;b&gt;순차 작업&lt;/b&gt;에 적합하다. 기획 &amp;rarr; 개발 &amp;rarr; 리뷰처럼 단계적 의존이 있을 때 사용한다. 에이전트 팀의 이점이 제한적이지만, 단계 내에 병렬 구간이 있으면 유용하다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2. 팬아웃/팬인 (Fan-out/Fan-in)&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;         ┌&amp;rarr; [전문가 A] ─┐
[입력] ──┼&amp;rarr; [전문가 B] ──┼&amp;rarr; [통합]
         └&amp;rarr; [전문가 C] ─┘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하나의 입력을 여러 전문가에게 분배하고, 병렬 처리 후 결과를 통합한다. &lt;b&gt;에이전트 팀의 가장 자연스러운 패턴&lt;/b&gt;이다. 코드 리뷰에서 보안/성능/스타일을 동시에 분석하거나, 리서치에서 공식 문서/커뮤니티/학술 자료를 동시에 조사할 때 적합하다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3. 전문가 풀 (Expert Pool)&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;[라우터] ──&amp;rarr; 상황에 따라 ──&amp;rarr; [전문가 A] 또는 [전문가 B] 또는 [전문가 C]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;모든 전문가가 항상 활성화되는 것이 아니라, 상황에 따라 필요한 전문가만 선택 호출한다. &lt;b&gt;서브 에이전트 모드가 더 적합&lt;/b&gt;한 패턴이다 (불필요한 에이전트가 상시 대기할 필요 없으므로).&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4. 생성-검증 (Producer-Reviewer)&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;[생성] &amp;rarr; [검증] &amp;rarr; 문제 시 &amp;rarr; [생성] 재실행 (최대 2~3회)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;산출물의 품질 보장이 중요하고 객관적 검증 기준이 존재할 때 사용한다. 에이전트 팀 모드에서 &lt;code&gt;SendMessage&lt;/code&gt;로 실시간 피드백을 주고받을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5. 감독자 (Supervisor)&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;inform7&quot;&gt;&lt;code&gt;[감독자] ──&amp;rarr; 상태 확인 후 동적 분배 ──&amp;rarr; [작업자 A] / [작업자 B] / [작업자 C]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팬아웃과 비슷하지만, 사전 고정 분배가 아니라 &lt;b&gt;진행 상황에 따라 동적으로 작업을 조정&lt;/b&gt;한다. 에이전트 팀의 공유 작업 목록(&lt;code&gt;TaskCreate&lt;/code&gt;/&lt;code&gt;TaskUpdate&lt;/code&gt;)과 자연스럽게 맞는다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6. 계층적 위임 (Hierarchical Delegation)&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;[총괄] &amp;rarr; [팀장 A] &amp;rarr; [실무자 1, 2]
       &amp;rarr; [팀장 B] &amp;rarr; [실무자 3, 4]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;큰 작업을 재귀적으로 나눠서 위임한다. 다만 에이전트 팀은 중첩이 불가하므로, 1단계는 에이전트 팀으로 구성하고 2단계 이하는 서브 에이전트로 구현해야 한다. 깊이 3단계 이상은 지연과 컨텍스트 손실이 커지므로 &lt;b&gt;2단계 이내가 권장&lt;/b&gt;된다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;복합 패턴&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실전에서는 단일 패턴보다 복합 패턴이 더 흔하다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;조합&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예시&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;팬아웃 + 생성-검증&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4개 언어 병렬 번역 &amp;rarr; 각각 네이티브 리뷰어 검수&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;파이프라인 + 팬아웃&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;분석(순차) &amp;rarr; 구현(병렬) &amp;rarr; 통합 테스트(순차)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;감독자 + 전문가 풀&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;고객 문의 분류 후 적합한 전문가 할당&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;워크플로우 (Phase 0~7)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Harness 1.1.0 기준, 하네스 엔지니어링은 다음 단계로 진행된다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center; width: 80px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Phase&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left; width: 140px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이름&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;설명&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;0&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;현황 감사&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 &lt;code&gt;.claude/agents/&lt;/code&gt;, &lt;code&gt;.claude/skills/&lt;/code&gt;, &lt;code&gt;CLAUDE.md&lt;/code&gt;를 확인하고, 신규 구축 / 기존 확장 / 운영 유지보수 중 하나로 분기&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;1&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;도메인 분석&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트의 기술 스택, 데이터 모델, 주요 모듈 파악. 사용자 숙련도를 감지해 이후 커뮤니케이션 톤을 조절&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;팀 아키텍처 설계&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트 팀 vs 서브 에이전트 결정, 6가지 아키텍처 패턴 중 선택, 에이전트 분리 기준(전문성/병렬성/컨텍스트/재사용성) 적용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;3&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;에이전트 정의 생성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;.claude/agents/*.md&lt;/code&gt; 파일 생성 (핵심 역할, 작업 원칙, 입출력 프로토콜, 에러 핸들링). 세션 중단 대비 CLAUDE.md 임시 동기화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;4&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;스킬 생성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;code&gt;.claude/skills/*/SKILL.md&lt;/code&gt; 파일 생성. CLAUDE.md 임시 동기화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;5&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;통합 및 오케스트레이션&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;CLAUDE.md에 하네스 컨텍스트 최종 등록 (에이전트 팀 구조, 스킬 목록, 실행 규칙, 디렉토리 구조)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;6&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;검증 및 테스트&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;트리거 검증, 드라이런 테스트&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;7&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;하네스 진화&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실행 후 피드백 수집 &amp;rarr; 피드백 유형별 수정 대상 매핑 &amp;rarr; 변경 이력 기록 &amp;rarr; 자동 진화 트리거&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Phase 0과 Phase 7은 1.1.0에서 추가된 기능이다. 하네스를 &quot;한 번 만들면 끝&quot;이 아니라, &lt;b&gt;지속적으로 감사하고 진화시키는 시스템&lt;/b&gt;으로 설계한 것이 이 플러그인의 차별점이다. 이것이 바로 하네스 &quot;엔지니어링&quot;이라고 부르는 이유 &amp;mdash; &lt;b&gt;설계 &amp;rarr; 구축 &amp;rarr; 검증 &amp;rarr; 진화&lt;/b&gt;의 전체 라이프사이클을 다루기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;설치 방법&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;방법 1: 마켓플레이스 (권장)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude Code 터미널에서 실행:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;# 1. 서드파티 마켓플레이스 등록
/plugin marketplace add revfactory/harness

# 2. 플러그인 설치
/plugin install harness@harness&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;방법 2: 글로벌 스킬 직접 설치&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;GitHub에서 클론한 뒤 skills 디렉토리를 복사:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;cp -r skills/harness ~/.claude/skills/harness&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;필수 환경 변수 (에이전트 팀 기능 사용 시):&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;설치 후 &quot;하네스 구성해줘&quot; 또는 &quot;하네스 설계해줘&quot;라고 말하면 Phase 0부터 자동으로 시작된다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실제 활용 사례 &amp;mdash; Harness 100&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Harness 플러그인의 범용성을 보여주는 프로젝트로 &lt;a href=&quot;https://github.com/revfactory/harness-100&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revfactory/harness-100&lt;/a&gt;이 있다. 10개 도메인에 걸쳐 &lt;b&gt;100개의 프로덕션 레디 하네스&lt;/b&gt;를 이 플러그인으로 생성한 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;도메인&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예시&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;콘텐츠 제작&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;웹툰 제작, 유튜브 기획, 기술 문서 작성&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;소프트웨어 개발&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코드 리뷰, 마이그레이션, 풀스택 웹 개발&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;데이터/AI&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;데이터 파이프라인, ML 모델 검증&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비즈니스 전략&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;마케팅 캠페인, 시장 분석&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그 외&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;교육, 법률, 헬스케어, 커뮤니케이션, 운영 등&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;한국어/영어 200개 패키지, 에이전트 정의 978개, 스킬 630개, 총 1,808개 마크다운 파일로 구성되어 있다. 하네스 엔지니어링이 소프트웨어 개발에만 국한되지 않고 다양한 도메인에 적용 가능하다는 것을 보여주는 사례다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스 엔지니어링 vs 단순 CLAUDE.md 작성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;그냥 CLAUDE.md에 규칙 몇 줄 적으면 되는 거 아니야?&quot;라고 생각할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;맞다, CLAUDE.md만으로도 기본적인 규칙 설정은 가능하다. 하지만 하네스 엔지니어링과는 차원이 다르다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 20px 0;&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;background-color: #f5f5f5;&quot;&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;관점&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단순 CLAUDE.md&lt;/span&gt;&lt;/th&gt;
&lt;th style=&quot;border: 1px solid #ddd; padding: 10px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스 엔지니어링&lt;/span&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;역할 분리&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;Claude 하나가 모든 걸 처리&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;전문 에이전트가 역할별로 분담&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;품질 검증&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;자기가 만들고 자기가 판단&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;생성자와 검증자가 구조적으로 분리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;일관성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;규칙은 있지만 준수 강제력 약함&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트별 원칙과 프로토콜로 구조적 보장&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;확장성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;규칙이 늘면 파일이 비대해짐&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;에이전트/스킬 파일로 분산 관리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;재사용&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;프로젝트마다 다시 작성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;패턴화된 구조를 재활용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;외부 연동&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;수동 복사/붙여넣기&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;MCP로 노션, Figma 등 자동 연동&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;진화&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;수동으로 규칙 추가/수정&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;border: 1px solid #ddd; padding: 10px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;피드백 기반 자동 진화 메커니즘&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비유하자면, 단순 CLAUDE.md는 &lt;b&gt;&quot;팀원 한 명에게 긴 메모를 건네는 것&quot;&lt;/b&gt;이고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스 엔지니어링은 &lt;b&gt;&quot;조직을 설계하고, 역할을 나누고, 업무 매뉴얼을 만들고, 성과 피드백 시스템까지 구축하는 것&quot;&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;내가 하네스 엔지니어링을 시작한 이유&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;iOS 개발자로서 Claude Code를 쓰면서 반복적으로 겪은 문제들이 있었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;1. 기존 코드 파괴&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;잘 작동하는 코드를 &quot;모던한&quot; 방식으로 전면 재작성하려는 경향. 단순히 버그 하나 수정해달라고 했는데 주변 코드까지 리팩토링해버리는 경우가 빈번했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;2. 컨텍스트 망각&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;매 세션마다 프로젝트 구조, 아키텍처, 코드 스타일을 다시 설명해야 했다. CLAUDE.md에 기본 정보를 적어둬도, &quot;어떻게 일해야 하는지&quot;까지는 담기 어려웠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;3. 일관성 부재&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;같은 유형의 작업인데 매번 다른 방식으로 처리했다. 트러블슈팅을 할 때 어떤 세션에서는 체계적으로 원인을 분석하고, 어떤 세션에서는 대충 &quot;이거 바꿔보세요&quot; 수준의 답을 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;4. 기록 누락&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;중요한 트러블슈팅이나 인사이트가 대화 속에 묻혀 사라졌다. 나중에 비슷한 문제를 만났을 때 &quot;전에 이거 해결했었는데...&quot; 하며 기억을 더듬어야 했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;5. 과잉 처리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;단순 구현 요청에 아키텍처 분석까지, 작은 버그 수정에 전체 모듈 리팩토링 제안까지. 작업의 크기에 맞지 않는 과도한 프로세스가 기본값이었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하네스 엔지니어링은 이 모든 문제에 대한 &lt;b&gt;구조적 해답&lt;/b&gt;을 줄 수 있을거라 생각했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;규칙을 한 번 설계해두면, 매 세션마다 Claude가 그 규칙 안에서 작동한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기존 자산을 보호하고, 작업을 분류하고, 필요한 수준의 팀만 호출하고, 기록할 것은 기록한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;다음 편에서는 내가 실제로 CLAUDE.md에 어떤 오케스트레이터 시스템을 설계했는지 &amp;mdash; 6개 팀의 구성, 4인 역할 구조, 운영 원칙, 팀 호출 규칙, 비효율 경고 시스템까지 상세히 다뤄보려 한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p style=&quot;color: #888; font-size: 0.85em;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;이 글에서 언급된 도구와 리소스&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;bull; &lt;a href=&quot;https://code.claude.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Claude Code&lt;/a&gt; &amp;mdash; Anthropic의 공식 AI 코딩 에이전트&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;bull; &lt;a href=&quot;https://github.com/revfactory/harness&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revfactory/harness&lt;/a&gt; &amp;mdash; Claude Code 하네스 구성 플러그인 (Apache 2.0)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;bull; &lt;a href=&quot;https://github.com/revfactory/claude-code-harness&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revfactory/claude-code-harness&lt;/a&gt; &amp;mdash; Harness A/B 테스트 연구 데이터&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;bull; &lt;a href=&quot;https://github.com/revfactory/harness-100&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;revfactory/harness-100&lt;/a&gt; &amp;mdash; 10개 도메인 100개 하네스 컬렉션&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;bull; &lt;a href=&quot;https://code.claude.com/docs/en/memory&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Claude Code 공식 문서 - Memory&lt;/a&gt; &amp;mdash; CLAUDE.md 작동 방식&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&amp;bull; &lt;a href=&quot;https://code.claude.com/docs/en/agent-teams&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Claude Code 공식 문서 - Agent Teams&lt;/a&gt; &amp;mdash; 에이전트 팀 기능&lt;/span&gt;&lt;/p&gt;</description>
      <category>Claude</category>
      <category>Agent</category>
      <category>ai</category>
      <category>Claude</category>
      <category>claude code</category>
      <category>Harness</category>
      <category>IOS</category>
      <category>revfactory/harness</category>
      <category>공공돌</category>
      <category>클로드</category>
      <category>클로드 코드</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/189</guid>
      <comments>https://sheep1sik.tistory.com/189#entry189comment</comments>
      <pubDate>Wed, 8 Apr 2026 18:56:36 +0900</pubDate>
    </item>
    <item>
      <title>[ Algorithm ] Baekjoon_1002 : C++</title>
      <link>https://sheep1sik.tistory.com/188</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;C++로 백준 1002번 터렛 문제를 풀면서 기하학 개념 없이도 접근할 수 있는 방법을 정리해봤다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제 이해&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 문제를 처음 봤을 때 지문이 어려워서 이해가 잘 안 됐다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심만 정리하면 이렇다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;두 사람(조규현, 백승환)이 각각 자기 위치에서 적까지의 거리를 알고 있다. 조규현은 좌표 (x1, y1)에 있고 적까지 거리가 r1, 백승환은 좌표 (x2, y2)에 있고 적까지 거리가 r2이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이걸 기하학적으로 생각하면 각 사람을 중심으로 반지름만큼의 &lt;b&gt;원&lt;/b&gt;을 그릴 수 있다. 적은 그 원 둘레 어딘가에 있는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;결국 이 문제의 본질은 &lt;b&gt;두 원의 교점이 몇 개인지&lt;/b&gt; 구하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;쉬운 비유&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;기하학을 모르더라도 이렇게 생각하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;운동장에 두 사람이 서 있다. 각자 줄을 하나씩 들고 있는데, 줄 끝에 적이 있다. 첫 번째 사람 줄 길이가 r1이고, 두 번째 사람 줄 길이가 r2이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심은 &lt;b&gt;두 사람이 얼마나 떨어져 있느냐&lt;/b&gt;다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;두 사람이 &lt;b&gt;너무 멀리&lt;/b&gt; 서 있으면 &amp;rarr; 줄을 아무리 뻗어도 안 닿는다 &amp;rarr; 적이 있을 수 있는 곳이 없다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;적당한 거리&lt;/b&gt;로 서 있으면 &amp;rarr; 줄이 겹치는 지점이 두 군데 생긴다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;딱 맞는 거리&lt;/b&gt;면 &amp;rarr; 겹치는 지점이 한 군데&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;같은 자리&lt;/b&gt;에 서 있고 줄 길이도 같으면 &amp;rarr; 어디든 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;경우의 수 정리&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;두 원이 만나는 경우는 총 5가지로 나뉜다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;아래 그림을 보면 한눈에 이해할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;summary_all_cases.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nS0wB/dJMcagSBfMk/5lCWiElfabIImqeKWTYCT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nS0wB/dJMcagSBfMk/5lCWiElfabIImqeKWTYCT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nS0wB/dJMcagSBfMk/5lCWiElfabIImqeKWTYCT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnS0wB%2FdJMcagSBfMk%2F5lCWiElfabIImqeKWTYCT1%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;723&quot; height=&quot;301&quot; data-filename=&quot;summary_all_cases.png&quot; data-origin-width=&quot;1200&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하나씩 살펴보자.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;case1_too_far.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lAfO6/dJMcabDKP2E/eVAYQuw0QrFXhd5OSki4k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lAfO6/dJMcabDKP2E/eVAYQuw0QrFXhd5OSki4k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lAfO6/dJMcabDKP2E/eVAYQuw0QrFXhd5OSki4k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlAfO6%2FdJMcabDKP2E%2FeVAYQuw0QrFXhd5OSki4k1%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;606&quot; height=&quot;346&quot; data-filename=&quot;case1_too_far.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;두 원이 너무 멀리 떨어져 있어서 아예 만나지 않는다. 두 사람 사이 거리(d)가 두 줄 길이의 합(r1 + r2)보다 클 때 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;case2_touch_outside.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOWht8/dJMcadhfTGI/IvK1V7fk4uElLKKrCoxU3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOWht8/dJMcadhfTGI/IvK1V7fk4uElLKKrCoxU3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOWht8/dJMcadhfTGI/IvK1V7fk4uElLKKrCoxU3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOWht8%2FdJMcadhfTGI%2FIvK1V7fk4uElLKKrCoxU3K%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;628&quot; height=&quot;359&quot; data-filename=&quot;case2_touch_outside.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;두 원이 바깥쪽에서 딱 한 점에서만 닿는다. d = r1 + r2일 때 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;case3_two_points.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bja493/dJMcabqeGs5/szKdQGTn67vxrfdytkPu7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bja493/dJMcabqeGs5/szKdQGTn67vxrfdytkPu7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bja493/dJMcabqeGs5/szKdQGTn67vxrfdytkPu7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbja493%2FdJMcabqeGs5%2FszKdQGTn67vxrfdytkPu7k%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;579&quot; height=&quot;331&quot; data-filename=&quot;case3_two_points.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;두 원이 겹치면서 두 군데에서 만난다. |r1 - r2| &amp;lt; d &amp;lt; r1 + r2일 때 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;case4_inside.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzE2IY/dJMcaakxkBo/KBn7k0KUvo7UZ3lKXE1pE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzE2IY/dJMcaakxkBo/KBn7k0KUvo7UZ3lKXE1pE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzE2IY/dJMcaakxkBo/KBn7k0KUvo7UZ3lKXE1pE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzE2IY%2FdJMcaakxkBo%2FKBn7k0KUvo7UZ3lKXE1pE0%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;586&quot; height=&quot;335&quot; data-filename=&quot;case4_inside.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;작은 원이 큰 원 안에 완전히 들어가서 만나지 않는다. d &amp;lt; |r1 - r2|일 때 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;case5_same.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JFwkP/dJMcaco7NDj/RirqjazfCHdTBNoVdzu9FK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JFwkP/dJMcaco7NDj/RirqjazfCHdTBNoVdzu9FK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JFwkP/dJMcaco7NDj/RirqjazfCHdTBNoVdzu9FK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJFwkP%2FdJMcaco7NDj%2FRirqjazfCHdTBNoVdzu9FK%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;606&quot; height=&quot;346&quot; data-filename=&quot;case5_same.png&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;두 사람이 같은 위치에 있고 줄 길이도 같으면 원이 완전히 겹친다. 만나는 점이 무한대이므로 -1을 출력한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;d는 어떻게 구할까?&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;d는 두 사람 사이의 거리다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;두 사람의 좌표가 주어지니까 거리를 구할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예를 들어 (1, 1)과 (4, 5)라면&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;가로 차이 = 4 - 1 = 3
세로 차이 = 5 - 1 = 4

거리의 제곱 = 3 * 3 + 4 * 4 = 9 + 16 = 25
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;여기서 루트를 씌우면 거리가 5가 되는데, 코드에서는 &lt;b&gt;루트를 씌우지 않고 제곱 상태로 비교&lt;/b&gt;한다. 왜냐하면 루트를 씌우면 소수점 오차가 생길 수 있기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;참고로 순서를 바꿔서 (x1 - x2) 대신 (x2 - x1)로 해도 결과는 같다. 어차피 제곱하면 마이너스가 사라지기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;비교 기준 준비&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;d를 구했으면 비교할 값 두 개를 미리 만들어둔다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;sum = (r1 + r2) * (r1 + r2)    &amp;rarr; 두 줄 길이 합의 제곱
diff = (r1 - r2) * (r1 - r2)   &amp;rarr; 두 줄 길이 차의 제곱
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;sum&lt;/b&gt;은 두 사람이 줄을 최대한 뻗었을 때 닿을 수 있는 가장 먼 거리다. 두 사람 사이 거리가 이것보다 크면 아무리 해도 안 만난다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;diff&lt;/b&gt;는 두 줄 길이의 차이다. 두 사람 사이 거리가 이것보다 작으면 작은 원이 큰 원 안에 쏙 들어가서 안 만난다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;우선순위&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;조건을 확인하는 순서가 중요하다. 위에서부터 하나씩 걸러내면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;완전히 같은 원인지 확인&lt;/b&gt; &amp;rarr; d = 0이고 r1 = r2면 &amp;rarr; -1&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;같은 위치인데 줄 길이가 다른지 확인&lt;/b&gt; &amp;rarr; d = 0이고 r1 &amp;ne; r2면 &amp;rarr; 0&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;너무 멀거나 안에 쏙 들어가는지 확인&lt;/b&gt; &amp;rarr; d &amp;gt; sum 또는 d &amp;lt; diff면 &amp;rarr; 0&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;딱 닿는지 확인&lt;/b&gt; &amp;rarr; d = sum 또는 d = diff면 &amp;rarr; 1&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;나머지&lt;/b&gt; &amp;rarr; 2&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코드&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);

    int t;
    cin &amp;gt;&amp;gt; t;

    for (int i = 0; i &amp;lt; t; i++) {
        double x1, y1, r1, x2, y2, r2;
        cin &amp;gt;&amp;gt; x1 &amp;gt;&amp;gt; y1 &amp;gt;&amp;gt; r1 &amp;gt;&amp;gt; x2 &amp;gt;&amp;gt; y2 &amp;gt;&amp;gt; r2;

        // 두 사람 사이 거리의 제곱
        double d = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);

        // 비교할 값들도 제곱 상태로 준비
        double sum = (r1 + r2) * (r1 + r2);
        double diff = (r1 - r2) * (r1 - r2);

        // 우선순위대로 조건 확인
        if (d == 0 &amp;amp;&amp;amp; r1 == r2) {
            cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
        }
        else if (d == 0 &amp;amp;&amp;amp; r1 != r2) {
            cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
        }
        else if (d &amp;gt; sum || d &amp;lt; diff) {
            cout &amp;lt;&amp;lt; 0 &amp;lt;&amp;lt; &quot;\n&quot;;
        }
        else if (d == sum || d == diff) {
            cout &amp;lt;&amp;lt; 1 &amp;lt;&amp;lt; &quot;\n&quot;;
        }
        else {
            cout &amp;lt;&amp;lt; 2 &amp;lt;&amp;lt; &quot;\n&quot;;
        }
    }

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;정리&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;백준 1002번 터렛은 기하학 문제처럼 보이지만, 결국 &lt;b&gt;두 원의 위치 관계&lt;/b&gt;를 판별하는 문제다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;핵심은 세 가지 값을 비교하는 것이다.&lt;/span&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;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;d&lt;/b&gt;: 두 사람 사이 거리의 제곱&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;sum&lt;/b&gt;: 두 반지름 합의 제곱&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;diff&lt;/b&gt;: 두 반지름 차의 제곱&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 세 값만 비교하면 어떤 경우인지 알 수 있다. 작은 조건 분기를 정확히 나누는 것이 이 문제의 핵심이라고 생각한다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm/Baekjoon</category>
      <category>algorithm</category>
      <category>BOJ</category>
      <category>BOJ_1002</category>
      <category>C++</category>
      <category>공공돌</category>
      <category>기하학</category>
      <category>백준</category>
      <category>백준 터렛</category>
      <category>알고리즘</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/188</guid>
      <comments>https://sheep1sik.tistory.com/188#entry188comment</comments>
      <pubDate>Mon, 6 Apr 2026 17:57:46 +0900</pubDate>
    </item>
    <item>
      <title>[C++] 코딩테스트에서 endl 대신 &amp;quot;\n&amp;quot;을 써야 하는 이유</title>
      <link>https://sheep1sik.tistory.com/187</link>
      <description>&lt;p data-end=&quot;226&quot; data-start=&quot;185&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;C++로 알고리즘 문제를 풀다 보면 자연스럽게 이런 코드를 작성하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; endl;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;338&quot; data-start=&quot;259&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;줄바꿈을 할 때 endl을 사용하는 것은 매우 흔한 습관이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그런데 코딩테스트 관련 글을 보다 보면 이런 이야기를 자주 접하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-end=&quot;367&quot; data-start=&quot;340&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;367&quot; data-start=&quot;342&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;&quot;endl 대신 \n을 사용하라.&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-end=&quot;418&quot; data-start=&quot;369&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;418&quot; data-start=&quot;369&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;둘 다 줄바꿈을 하는데 왜 굳이 \n을 써야 할까?&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;정말 성능 차이가 있는 걸까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;441&quot; data-start=&quot;420&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;궁금해서 직접 실험을 통해 확인해봤다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-end=&quot;464&quot; data-start=&quot;448&quot; data-section-id=&quot;7m40un&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;endl과 &quot;\n&quot;의 차이&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;491&quot; data-start=&quot;466&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;표면적으로 보면 두 방식은 같은 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1773048348996&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cout &amp;lt;&amp;lt; &quot;Hello&quot; &amp;lt;&amp;lt; endl;
cout &amp;lt;&amp;lt; &quot;Hello\n&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;566&quot; data-start=&quot;549&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;둘 다 출력 후 줄바꿈을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;591&quot; data-start=&quot;568&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하지만 내부 동작에는 중요한 차이가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;동작 방식&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;666&quot; data-start=&quot;593&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;666&quot; data-start=&quot;615&quot;&gt;
&lt;tr data-end=&quot;645&quot; data-start=&quot;615&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;624&quot; data-start=&quot;615&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;endl&lt;/span&gt;&lt;/td&gt;
&lt;td data-end=&quot;645&quot; data-start=&quot;624&quot; data-col-size=&quot;sm&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;줄바꿈 + 출력 버퍼 flush&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;666&quot; data-start=&quot;646&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;655&quot; data-start=&quot;646&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td data-end=&quot;666&quot; data-start=&quot;655&quot; data-col-size=&quot;sm&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;줄바꿈만 수행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;688&quot; data-start=&quot;668&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;여기서 핵심은 &lt;b&gt;flush&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-end=&quot;709&quot; data-start=&quot;695&quot; data-section-id=&quot;1tlgazn&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;출력 버퍼와 flush&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;753&quot; data-start=&quot;711&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;cout으로 출력한다고 해서 데이터가 바로 화면에 나타나는 것은 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;796&quot; data-start=&quot;755&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;C++의 출력은 **버퍼(buffer)**라는 임시 저장 공간을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;815&quot; data-start=&quot;798&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;동작 흐름은 대략 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1773048300163&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cout &amp;rarr; 버퍼에 저장 &amp;rarr; 버퍼가 차면 한 번에 출력&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;889&quot; data-start=&quot;857&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이렇게 하는 이유는 &lt;b&gt;입출력 성능을 높이기 위해서&lt;/b&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;934&quot; data-start=&quot;891&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;하지만 &lt;b&gt;flush&lt;/b&gt;는 이 버퍼를 &lt;b&gt;즉시 비우고 출력하도록 강제&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1773048306748&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cout &amp;rarr; 버퍼 &amp;rarr; flush &amp;rarr; 즉시 출력&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1015&quot; data-start=&quot;971&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;문제는 endl이 &lt;b&gt;줄바꿈을 할 때마다 flush를 실행한다는 점&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1060&quot; data-start=&quot;1017&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;즉 출력이 많을수록 flush가 계속 발생하면서 성능이 크게 떨어질 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-end=&quot;1079&quot; data-start=&quot;1067&quot; data-section-id=&quot;qutzci&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이해하기 쉬운 비유&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;1108&quot; data-start=&quot;1081&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이 상황을 택배 배송으로 비유하면 이해하기 쉽다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;1121&quot; data-start=&quot;1110&quot; data-section-id=&quot;zblyep&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;endl 방식&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1773048276130&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;물건 1개 넣음 &amp;rarr; 바로 배송
물건 1개 넣음 &amp;rarr; 바로 배송
물건 1개 넣음 &amp;rarr; 바로 배송&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;1194&quot; data-start=&quot;1183&quot; data-section-id=&quot;zq17b4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;\n&quot; 방식&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1773048286806&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;물건을 모음 &amp;rarr; 박스가 가득 참 &amp;rarr; 한 번에 배송&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1255&quot; data-start=&quot;1233&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;당연히 두 번째 방식이 훨씬 효율적이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-end=&quot;1279&quot; data-start=&quot;1262&quot; data-section-id=&quot;1n5gw8x&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실제로 얼마나 차이가 날까?&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;1320&quot; data-start=&quot;1281&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;이론적으로는 느리다고 하지만 &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실제로 얼마나 차이가 나는지 궁금했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1359&quot; data-start=&quot;1322&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그래서 &lt;b&gt;100만 번 출력하는 간단한 테스트 코드&lt;/b&gt;를 작성했다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1773047905674&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;bits/stdc++.h&amp;gt;
using namespace std;

int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);

int N = 1000000;

// endl 테스트
auto start1 = chrono::high_resolution_clock::now();
for (int i = 0; i &amp;lt; N; i++) {
cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
}
auto end1 = chrono::high_resolution_clock::now();
double time1 = chrono::duration&amp;lt;double&amp;gt;(end1 - start1).count();

// &quot;\n&quot; 테스트
auto start2 = chrono::high_resolution_clock::now();
for (int i = 0; i &amp;lt; N; i++) {
cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;\n&quot;;
}
auto end2 = chrono::high_resolution_clock::now();
double time2 = chrono::duration&amp;lt;double&amp;gt;(end2 - start2).count();

cerr &amp;lt;&amp;lt; &quot;endl: &quot; &amp;lt;&amp;lt; time1 &amp;lt;&amp;lt; &quot;초\n&quot;;
cerr &amp;lt;&amp;lt; &quot;\\n: &quot; &amp;lt;&amp;lt; time2 &amp;lt;&amp;lt; &quot;초\n&quot;;
cerr &amp;lt;&amp;lt; &quot;차이: &quot; &amp;lt;&amp;lt; time1 / time2 &amp;lt;&amp;lt; &quot;배\n&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-end=&quot;2171&quot; data-start=&quot;2164&quot; data-section-id=&quot;74zg0u&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;측정 결과&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;2178&quot; data-start=&quot;2173&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;실행 환경&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2211&quot; data-start=&quot;2180&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2187&quot; data-start=&quot;2180&quot; data-section-id=&quot;1658dej&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;macOS&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2196&quot; data-start=&quot;2188&quot; data-section-id=&quot;1cpimbq&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;g++-15&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2211&quot; data-start=&quot;2197&quot; data-section-id=&quot;18q6fvg&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;-O2 최적화 옵션&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2228&quot; data-start=&quot;2213&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;측정 결과는 다음과 같았다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;endl: 약 1.037초&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;\n&quot;: 약 0.066초&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2271&quot; data-start=&quot;2269&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;즉, &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;endl이 약 15배 이상 느렸다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;2331&quot; data-start=&quot;2298&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;같은 100만 번 출력인데도 성능 차이가 꽤 크게 나타났다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-end=&quot;2354&quot; data-start=&quot;2338&quot; data-section-id=&quot;1n37ap6&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코딩테스트에서 중요한 이유&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;2388&quot; data-start=&quot;2356&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;코딩테스트에서는 출력이 매우 많은 문제들이 종종 등장한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;2395&quot; data-start=&quot;2390&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;예를 들어&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;2432&quot; data-start=&quot;2397&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2413&quot; data-start=&quot;2397&quot; data-section-id=&quot;1lnicbj&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;N이 &lt;b&gt;100,000&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;2432&quot; data-start=&quot;2414&quot; data-section-id=&quot;ntrbz4&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;혹은 &lt;b&gt;1,000,000&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;2499&quot; data-start=&quot;2434&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;같이 출력이 반복되는 경우, endl을 사용하면 &lt;b&gt;flush가 반복 실행되면서 시간 초과가 발생할 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;2534&quot; data-start=&quot;2501&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그래서 나는 알고리즘 풀이에서 아래와 같이 설정을 했다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1773048191239&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  ios::sync_with_stdio(false);  // C/C++ 입출력 동기화 해제 &amp;rarr; 속도 &amp;uarr;
  cin.tie(NULL);                 // cin-cout 연결 해제 &amp;rarr; 불필요한 flush 방지&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2602&quot; data-start=&quot;2592&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;그리고 출력할 때는 아래와 같이&lt;span style=&quot;font-family: 'Noto Sans Light'; color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&quot;\n&quot;을 사용하는 것이 일반적이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;pre id=&quot;code_1773048158605&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot;\n&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h1 data-end=&quot;2671&quot; data-start=&quot;2667&quot; data-section-id=&quot;yim43j&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;정리&lt;/span&gt;&lt;/h1&gt;
&lt;p data-end=&quot;2706&quot; data-start=&quot;2673&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;C++에서 endl과 &quot;\n&quot;의 차이는 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;방식 특징&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;2786&quot; data-start=&quot;2708&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;2786&quot; data-start=&quot;2730&quot;&gt;
&lt;tr data-end=&quot;2765&quot; data-start=&quot;2730&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2739&quot; data-start=&quot;2730&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;endl&lt;/span&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2765&quot; data-start=&quot;2739&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;줄바꿈 + flush (버퍼 즉시 비움)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;2786&quot; data-start=&quot;2766&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2775&quot; data-start=&quot;2766&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;2786&quot; data-start=&quot;2775&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;줄바꿈만 수행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;2839&quot; data-start=&quot;2788&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;출력이 적다면 큰 차이는 없지만 &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;대량 출력에서는 성능 차이가 매우 커질 수 있다고 생각한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;2839&quot; data-start=&quot;2788&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;2939&quot; data-start=&quot;2897&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;작은 습관 하나지만 &lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;시간 초과를 막는 중요한 차이&lt;/b&gt;가 될 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <category>C++</category>
      <category>endl</category>
      <category>공공돌</category>
      <category>백준</category>
      <category>입출력 최적화</category>
      <category>코딩 테스트</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/187</guid>
      <comments>https://sheep1sik.tistory.com/187#entry187comment</comments>
      <pubDate>Mon, 9 Mar 2026 18:28:04 +0900</pubDate>
    </item>
    <item>
      <title>자식 컨트롤러 누락으로 인한 이벤트 미작동</title>
      <link>https://sheep1sik.tistory.com/186</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 상황&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rx 바인딩도 정상적으로 되어 있고, 버튼 액션도 설정했지만, &lt;b&gt;버튼을 눌러도 로그가 찍히지 않고 이미지도 변경되지 않음&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 setChecked(_: Bool)이나 @objc 메서드들이 호출되지 않는 상태.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;원인 분석&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 체크박스가 포함된 InfoRowView는 WorkingConditionsContainerViewController의 view에 존재함.&lt;/li&gt;
&lt;li&gt;하지만 &lt;b&gt;최종 부모 컨트롤러에서 해당 VC를 자식 뷰컨트롤러로 등록하지 않고 view만 addSubview()&lt;/b&gt; 하여 붙였음.&lt;/li&gt;
&lt;li&gt;이로 인해 viewDidLoad()가 호출되지 않았고, 내부에서 설정된 &lt;b&gt;Rx 바인딩 및 addTarget 등의 액션 로직이 실행되지 않음&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;해결 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WorkingConditionsContainerViewController를&amp;nbsp;자식&amp;nbsp;컨트롤러로&amp;nbsp;명시적으로&amp;nbsp;등록하고,&amp;nbsp;그&amp;nbsp;뷰를&amp;nbsp;container에&amp;nbsp;붙이도록&amp;nbsp;수정&lt;/p&gt;
&lt;pre id=&quot;code_1753257525085&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;extension UIViewController {
    func add(_ child: UIViewController, to container: UIView) {
        addChild(child)
        container.addSubview(child.view)
        child.view.snp.makeConstraints { $0.edges.equalToSuperview() }
        child.didMove(toParent: self)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 부모 컨트롤러에서 다음과 같이 호출&lt;/p&gt;
&lt;pre id=&quot;code_1753257554285&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;add(workingConditionsContainerViewController, to: workingConditionsContainer)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>트러블 슈팅</category>
      <category>IOS</category>
      <category>SWIFT</category>
      <category>UIKit</category>
      <category>공공돌</category>
      <category>트러블 슈팅</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/186</guid>
      <comments>https://sheep1sik.tistory.com/186#entry186comment</comments>
      <pubDate>Wed, 23 Jul 2025 17:00:30 +0900</pubDate>
    </item>
    <item>
      <title>체크박스를 클릭해도 이미지가 바뀌지 않음</title>
      <link>https://sheep1sik.tistory.com/185</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;문제 상황&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;checkBox.isSelected = isChecked 호출이 동작하지 않음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그도 찍히지 않음.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;원인 분석&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setChecked(_:)는 호출되었지만, 해당 메서드가 뷰 계층이 제대로 올라가지 않은 상태에서 동작하고 있었음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 버튼에 target-action이 제대로 설정되지 않았음.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;해결 방법&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;checkBox.addTarget(_:action:for:)는 뷰 외부(컨트롤러 또는 초기화 시점)에서 설정&lt;/li&gt;
&lt;li&gt;InfoRowView 내에서 .checkBox 타입일 경우에만 touchUpInside 설정&lt;/li&gt;
&lt;li&gt;타겟 등록 이후 setChecked(_:) 호출로 UI 갱신&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1753257323109&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// MARK: - setStyles
    func setStyles(type: InfoRowType) {
        switch type {
        case .checkBox(let isChecked):
            checkBox.isSelected = isChecked
            checkBox.addTarget(self, action: #selector(didTapCheckBox), for: .touchUpInside)
        case .labelWithChevron(let value):
            valueLabel.text = value
        case .labelWithButton(let title):
            actionButton.setTitle(title, for: .normal)
        case .colorWithChevron(let color, let title):
            colorDotView.backgroundColor = color
            titleLabel.text = title
            
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1753257356840&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// MARK: - Public Methods
    func setChecked(_ isChecked: Bool) {
        checkBox.isSelected = isChecked
    }
    
    func isChecked() -&amp;gt; Bool {
        return checkBox.isSelected
    }
    
    @objc private func didTapCheckBox() {
        checkTappedRelay.accept(())
    }&lt;/code&gt;&lt;/pre&gt;</description>
      <category>트러블 슈팅</category>
      <category>IOS</category>
      <category>SWIFT</category>
      <category>UIKit</category>
      <category>공공돌</category>
      <category>트러블 슈팅</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/185</guid>
      <comments>https://sheep1sik.tistory.com/185#entry185comment</comments>
      <pubDate>Wed, 23 Jul 2025 16:56:24 +0900</pubDate>
    </item>
    <item>
      <title>[ iOS ] Apple 로그인 클라이언트 구현 (UIKit + Rx + Clean Architecture)</title>
      <link>https://sheep1sik.tistory.com/184</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이 글은 UIKit 기반 앱에서 Apple 로그인을 구현하는 전 과정을 다룹니다.&lt;br /&gt;RxSwift, MVVM, 클린 아키텍처, 서버 연동을 기준으로 작성되었습니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;307&quot; data-start=&quot;276&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. Apple Developer 계정 로그인&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;409&quot; data-start=&quot;309&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;387&quot; data-start=&quot;309&quot;&gt;&lt;a href=&quot;https://developer.apple.com/account&quot;&gt;https://developer.apple.com/account&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1753171449151&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;로그인 - Apple&quot; data-og-description=&quot;&quot; data-og-host=&quot;idmsa.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/account&quot; data-og-url=&quot;https://idmsa.apple.com/IDMSWebAuth/signin?appIdKey=891bd3417a7776362562d2197f89480a8547b108fd934911bcbea0110d07f757&amp;amp;path=%2Faccount%2F&amp;amp;rv=1&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/account&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/account&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;로그인 - Apple&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;idmsa.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;440&quot; data-start=&quot;416&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. App ID 생성 (식별자)&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;718&quot; data-start=&quot;442&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;503&quot; data-start=&quot;442&quot;&gt;좌측 메뉴 &amp;rarr; &lt;b&gt;Certificates, IDs &amp;amp; Profiles&lt;/b&gt; &amp;rarr; &lt;b&gt;Identifiers&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;541&quot; data-start=&quot;504&quot;&gt;&lt;b&gt;+&lt;/b&gt; 버튼 클릭 &amp;rarr; App IDs &amp;rarr; &lt;b&gt;App&lt;/b&gt; 선택&lt;/li&gt;
&lt;li data-end=&quot;569&quot; data-start=&quot;542&quot;&gt;&lt;b&gt;Description&lt;/b&gt;: 앱 이름 입력&lt;/li&gt;
&lt;li data-end=&quot;643&quot; data-start=&quot;570&quot;&gt;&lt;b&gt;Bundle ID&lt;/b&gt;: Xcode에서 사용하는 것과 &lt;b&gt;정확히 일치&lt;/b&gt;하도록 입력 (예: com.example.app)&lt;/li&gt;
&lt;li data-end=&quot;691&quot; data-start=&quot;644&quot;&gt;&lt;b&gt;Capabilities&lt;/b&gt;에서 &lt;b&gt;Sign In with Apple&lt;/b&gt; 체크&lt;/li&gt;
&lt;li data-end=&quot;718&quot; data-start=&quot;692&quot;&gt;&lt;b&gt;Continue &amp;rarr; Register&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&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;div data-message-model-slug=&quot;gpt-4o&quot; data-message-id=&quot;a367c7de-b137-441e-a6a9-21326bdb0d97&quot; data-message-author-role=&quot;assistant&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-end=&quot;825&quot; data-start=&quot;795&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Service ID 생성 (웹 인증용)&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1274&quot; data-start=&quot;827&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;872&quot; data-start=&quot;827&quot;&gt;&lt;b&gt;Identifiers&lt;/b&gt; &amp;rarr; &lt;b&gt;+&lt;/b&gt; &amp;rarr; &lt;b&gt;Services IDs&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;918&quot; data-start=&quot;873&quot;&gt;&lt;b&gt;Identifier&lt;/b&gt;: 예: com.example.app.login&lt;/li&gt;
&lt;li data-end=&quot;965&quot; data-start=&quot;919&quot;&gt;&lt;b&gt;Description&lt;/b&gt;: 예: Apple Login for MyApp&lt;/li&gt;
&lt;li data-end=&quot;995&quot; data-start=&quot;966&quot;&gt;생성 후 목록에서 해당 Service ID 선택&lt;/li&gt;
&lt;li data-end=&quot;1018&quot; data-start=&quot;996&quot;&gt;&lt;b&gt;Configure&lt;/b&gt; 버튼 클릭&lt;/li&gt;
&lt;li data-end=&quot;1047&quot; data-start=&quot;1019&quot;&gt;&lt;b&gt;Sign in with Apple&lt;/b&gt; 체크&lt;/li&gt;
&lt;li data-end=&quot;1087&quot; data-start=&quot;1048&quot;&gt;&lt;b&gt;Primary App ID&lt;/b&gt;: 방금 생성한 App ID 선택&lt;/li&gt;
&lt;li data-end=&quot;1155&quot; data-start=&quot;1088&quot;&gt;&lt;b&gt;Web domain&lt;/b&gt;: 앱에서 사용할 서버 도메인 입력 (예: &lt;a href=&quot;https://your-domain.com&quot;&gt;https://your-domain.com&lt;/a&gt;)&lt;/li&gt;
&lt;li data-end=&quot;1260&quot; data-start=&quot;1156&quot;&gt;&lt;b&gt;Return URL&lt;/b&gt;: 서버에서 Apple 인증 처리를 받을 콜백 URL 입력 (예: &lt;a href=&quot;https://your-domain.com/api/auth/apple/callback&quot;&gt;https://your-domain.com/api/auth/apple/callback&lt;/a&gt;)&lt;/li&gt;
&lt;li data-end=&quot;1274&quot; data-start=&quot;1261&quot;&gt;저장 후 Done&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;1301&quot; data-start=&quot;1281&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. Auth Key 생성&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;1467&quot; data-start=&quot;1303&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;1322&quot; data-start=&quot;1303&quot;&gt;좌측 메뉴 &amp;rarr; &lt;b&gt;Keys&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;1337&quot; data-start=&quot;1323&quot;&gt;&lt;b&gt;+&lt;/b&gt; 버튼 클릭&lt;/li&gt;
&lt;li data-end=&quot;1375&quot; data-start=&quot;1338&quot;&gt;&lt;b&gt;Key Name&lt;/b&gt;: 예: Apple Login Key&lt;/li&gt;
&lt;li data-end=&quot;1404&quot; data-start=&quot;1376&quot;&gt;&lt;b&gt;Sign In with Apple&lt;/b&gt; 체크&lt;/li&gt;
&lt;li data-end=&quot;1441&quot; data-start=&quot;1405&quot;&gt;&lt;b&gt;Configure&lt;/b&gt; &amp;rarr; Primary App ID 선택&lt;/li&gt;
&lt;li data-end=&quot;1467&quot; data-start=&quot;1442&quot;&gt;완료 후 Key 다운로드 (.p8 파일)&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-end=&quot;1521&quot; data-start=&quot;1469&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;1521&quot; data-start=&quot;1471&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Auth Key는 단 한 번만 다운로드 가능하므로 안전한 곳에 보관하세요.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;1553&quot; data-start=&quot;1528&quot; data-ke-size=&quot;size23&quot;&gt;5. 클라이언트에서 필요한 값 정리 및 백엔드 공유&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;저의 경우 Slack을 통해서 백엔드분에게 아래와 같이 공유 드렸습니다 !&amp;nbsp;&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-07-22 오후 5.16.17.png&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;1196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bF9LyC/btsPtzTfaKy/iHTZzZ9bm553tIMauNsyQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bF9LyC/btsPtzTfaKy/iHTZzZ9bm553tIMauNsyQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bF9LyC/btsPtzTfaKy/iHTZzZ9bm553tIMauNsyQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbF9LyC%2FbtsPtzTfaKy%2FiHTZzZ9bm553tIMauNsyQk%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;603&quot; height=&quot;1073&quot; data-filename=&quot;스크린샷 2025-07-22 오후 5.16.17.png&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;1196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;373&quot; data-start=&quot;358&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 프로젝트 설정&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;420&quot; data-start=&quot;375&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1-1. Sign in with Apple Capabilities 추가&lt;/b&gt;&lt;/h3&gt;
&lt;p data-end=&quot;463&quot; data-start=&quot;422&quot; data-ke-size=&quot;size16&quot;&gt;Xcode에서 Apple 로그인 기능을 사용하려면 해당 권한이 필요합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;613&quot; data-start=&quot;465&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;511&quot; data-start=&quot;465&quot;&gt;Xcode &amp;gt; Target &amp;gt; &lt;b&gt;Signing &amp;amp; Capabilities&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;535&quot; data-start=&quot;512&quot;&gt;+ Capability 버튼 클릭&lt;/li&gt;
&lt;li data-end=&quot;564&quot; data-start=&quot;536&quot;&gt;&lt;b&gt;Sign In with Apple&lt;/b&gt; 선택&lt;/li&gt;
&lt;li data-end=&quot;564&quot; data-start=&quot;536&quot;&gt;자동으로 .entitlements 파일이 생성되며 아래 내용이 포함되어야 함&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1753170810059&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;key&amp;gt;com.apple.developer.applesignin&amp;lt;/key&amp;gt;
&amp;lt;array&amp;gt;
    &amp;lt;string&amp;gt;Default&amp;lt;/string&amp;gt;
&amp;lt;/array&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;1348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLtyet/btsPuKsESrY/0lzcTwLbitdkrHAg580ftk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLtyet/btsPuKsESrY/0lzcTwLbitdkrHAg580ftk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLtyet/btsPuKsESrY/0lzcTwLbitdkrHAg580ftk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLtyet%2FbtsPuKsESrY%2F0lzcTwLbitdkrHAg580ftk%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;736&quot; height=&quot;551&quot; data-origin-width=&quot;1800&quot; data-origin-height=&quot;1348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;747&quot; data-start=&quot;721&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. Apple 로그인 버튼 UI 추가&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-end=&quot;773&quot; data-start=&quot;749&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2-1. Apple 로그인 버튼 생성&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;LoginView&lt;/h4&gt;
&lt;pre id=&quot;code_1753170878492&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import UIKit
import SnapKit
import Then
import AuthenticationServices

final class LoginView: UIView {
    // MARK: - Properties
    
    // MARK: - UI Components
    
    var appleLoginButton = ASAuthorizationAppleIDButton().then {
        $0.cornerRadius = 8
        $0.translatesAutoresizingMaskIntoConstraints = false
    }

    // MARK: - Initializer
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        configure()
    }
    
    @available(*, unavailable, message: &quot;storyboard is not supported.&quot;)
    required init?(coder: NSCoder) {
        fatalError(&quot;init(coder:) has not been implemented.&quot;)
    }
    
    // MARK: - Public Methods
}

private extension LoginView {
    // MARK: - configure
    func configure() {
        setHierarchy()
        setStyles()
        setConstraints()
    }
    
    // MARK: - setHierarchy
    func setHierarchy() {
        addSubview(appleLoginButton)
    }
    
    // MARK: - setStyles
    func setStyles() {
        backgroundColor = .white
    }
    
    // MARK: - setConstraints
    func setConstraints() {
        appleLoginButton.snp.makeConstraints {
            $0.centerX.equalToSuperview()
            $0.bottom.equalToSuperview().inset(40)
            $0.height.equalTo(50)
            $0.width.equalTo(280)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. Apple 로그인 로직 구현 (AuthRepository)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1753171067959&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;final class AuthRepositoryImpl: AuthRepository {

    private var appleAuthDelegate: AppleAuthDelegate?

    func loginWithApple() -&amp;gt; Observable&amp;lt;Result&amp;lt;String, Error&amp;gt;&amp;gt; {
        return Observable.create { observer in
            let provider = ASAuthorizationAppleIDProvider()
            let request = provider.createRequest()
            request.requestedScopes = [.fullName, .email]

            let controller = ASAuthorizationController(authorizationRequests: [request])

            let delegate = AppleAuthDelegate { result in
                observer.onNext(result)
                observer.onCompleted()
            }

            self.appleAuthDelegate = delegate
            controller.delegate = delegate
            controller.presentationContextProvider = delegate
            controller.performRequests()

            print(&quot;Apple 로그인 요청 시작됨&quot;)
            return Disposables.create()
        }
    }

    func sendCodeToServer(code: String) -&amp;gt; Observable&amp;lt;Result&amp;lt;String, Error&amp;gt;&amp;gt; {
        let url = URL(string: &quot;https://your-server.com/api/auth/apple/callback&quot;)!
        var request = URLRequest(url: url)
        request.httpMethod = &quot;POST&quot;
        request.setValue(&quot;application/json&quot;, forHTTPHeaderField: &quot;Content-Type&quot;)

        let body = [&quot;code&quot;: code]
        request.httpBody = try? JSONSerialization.data(withJSONObject: body)

        return URLSession.shared.rx.response(request: request)
            .map { response, data in
                let resultBody = String(data: data, encoding: .utf8) ?? &quot;&quot;
                print(&quot;응답: \(response.statusCode), body: \(resultBody)&quot;)

                if 200..&amp;lt;300 ~= response.statusCode {
                    return .success(&quot;로그인 성공&quot;)
                } else {
                    return .failure(NSError(domain: &quot;auth&quot;, code: response.statusCode, userInfo: [NSLocalizedDescriptionKey: resultBody]))
                }
            }
            .catch { .just(.failure($0)) }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;AppleAuthDelegate 구현&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1753171138484&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;final class AppleAuthDelegate: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {

    private let completion: (Result&amp;lt;String, Error&amp;gt;) -&amp;gt; Void

    init(completion: @escaping (Result&amp;lt;String, Error&amp;gt;) -&amp;gt; Void) {
        self.completion = completion
    }

    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let credential = authorization.credential as? ASAuthorizationAppleIDCredential,
           let codeData = credential.authorizationCode,
           let code = String(data: codeData, encoding: .utf8) {
            print(&quot;인증 성공, code: \(code)&quot;)
            completion(.success(code))
        } else {
            completion(.failure(NSError(domain: &quot;apple&quot;, code: -1, userInfo: [NSLocalizedDescriptionKey: &quot;Code decode error&quot;])))
        }
    }

    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        completion(.failure(error))
    }

    func presentationAnchor(for controller: ASAuthorizationController) -&amp;gt; ASPresentationAnchor {
        return UIApplication.shared.windows.first ?? UIWindow()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. UseCase 구현&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1753171170310&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;final class LoginWithAppleUseCaseImpl: LoginWithAppleUseCase {
    private let repository: AuthRepository

    init(repository: AuthRepository) {
        self.repository = repository
    }

    func execute() -&amp;gt; Observable&amp;lt;Result&amp;lt;String, Error&amp;gt;&amp;gt; {
        return repository.loginWithApple()
            .flatMap { result in
                switch result {
                case .success(let code):
                    return self.repository.sendCodeToServer(code: code)
                case .failure(let error):
                    return .just(.failure(error))
                }
            }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. ViewModel &amp;amp; ViewController&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1753171294493&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Foundation
import RxSwift
import RxCocoa

protocol LoginViewModelInput {
    var appleLoginTapped: PublishRelay&amp;lt;Void&amp;gt; { get }
}

protocol LoginViewModelOutput {
    var loginResult: Observable&amp;lt;Result&amp;lt;String, Error&amp;gt;&amp;gt; { get }
}

final class LoginViewModel: LoginViewModelInput, LoginViewModelOutput {

    // Input
    let appleLoginTapped = PublishRelay&amp;lt;Void&amp;gt;()

    // Output
    let loginResult: Observable&amp;lt;Result&amp;lt;String, Error&amp;gt;&amp;gt;

    // Private
    private let loginUseCase: LoginWithAppleUseCase
    private let disposeBag = DisposeBag()
    private let loginResultRelay = PublishRelay&amp;lt;Result&amp;lt;String, Error&amp;gt;&amp;gt;()

    init(loginUseCase: LoginWithAppleUseCase) {
        self.loginUseCase = loginUseCase
        self.loginResult = loginResultRelay.asObservable()
        bind()
    }

    private func bind() {
        appleLoginTapped
            .do(onNext: { print(&quot;Apple 로그인 버튼 탭&quot;) })
            .flatMapLatest { [weak self] _ -&amp;gt; Observable&amp;lt;Result&amp;lt;String, Error&amp;gt;&amp;gt; in
                guard let self = self else { return .empty() }
                return self.loginUseCase.execute()
            }
            .bind(to: loginResultRelay)
            .disposed(by: disposeBag)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1753171364839&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import UIKit
import AuthenticationServices
import RxSwift
import RxCocoa

final class LoginViewController: UIViewController {
    
    // MARK: - Properties
    private let loginView = LoginView()
    private let viewModel: LoginViewModel
    private let disposeBag = DisposeBag()
    
    // MARK: - Initializer
    
    init(viewModel: LoginViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
    }
    
    @available(*, unavailable, message: &quot;Storyboard is not supported&quot;)
    required init?(coder: NSCoder) {
        fatalError()
    }
    
    // MARK: - Lifecycle
    
    override func loadView() {
        self.view = loginView
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configure()
    }
    
    @objc func didTapAppleLogin() {
        viewModel.appleLoginTapped.accept(())
    }
}

// MARK: - UI Methods

private extension LoginViewController {
    
    func configure() {
        setHierarchy()
        setStyles()
        setConstraints()
        setActions()
        setBinding()
    }
    
    func setHierarchy() {

    }
    
    func setStyles() {

    }
    
    func setConstraints() {

    }
    
    func setActions() {
        loginView.appleLoginButton.addTarget(self, action: #selector(didTapAppleLogin), for: .touchUpInside)
    }
    
    func setBinding() {
        viewModel.loginResult
            .observe(on: MainScheduler.instance)
            .subscribe(onNext: { [weak self] result in
                switch result {
                case .success(let code):
                    print(&quot;로그인 성공, 인증 코드: \(code)&quot;)
                    // TODO: &amp;rarr; 다음 화면으로 전환
                case .failure(let error):
                    print(&quot;로그인 실패: \(error.localizedDescription)&quot;)
                    // TODO: &amp;rarr; 사용자에게 Alert 등 UI 처리
                }
            })
            .disposed(by: disposeBag)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;참고 자료&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1753174365139&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;애플 로그인 설정하기&quot; data-og-description=&quot;참고: 같은 이름(닉네임)으로 중복 가입 방지 옵션을 해제해 주세요. 소셜 로그인 가입자는 대부분 가입된 플랫폼의 이름(닉네임)을 그대로 사용하는 경향이 있으며, 소셜 로그인 플랫&quot; data-og-host=&quot;imweb.me&quot; data-og-source-url=&quot;https://imweb.me/faq?mode=view&amp;amp;category=29&amp;amp;category2=47&amp;amp;idx=71719&quot; data-og-url=&quot;https://imweb.me/faq?category=29&amp;amp;category2=47&amp;amp;idx=71719&amp;amp;mode=view&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ceMhyV/hyZniAkr3G/NKdm5tCvHYxwaiQTL6RxZK/img.png?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260,https://scrap.kakaocdn.net/dn/VkXsN/hyZnbA9rAP/fm3au4B38Kr4phtw2aFJR1/img.png?width=960&amp;amp;height=640&amp;amp;face=0_0_960_640,https://scrap.kakaocdn.net/dn/48xeT/hyZnDc69Rd/yZEkrHsLqbK7iWcTxvJsik/img.png?width=1045&amp;amp;height=480&amp;amp;face=0_0_1045_480&quot;&gt;&lt;a href=&quot;https://imweb.me/faq?mode=view&amp;amp;category=29&amp;amp;category2=47&amp;amp;idx=71719&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://imweb.me/faq?mode=view&amp;amp;category=29&amp;amp;category2=47&amp;amp;idx=71719&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ceMhyV/hyZniAkr3G/NKdm5tCvHYxwaiQTL6RxZK/img.png?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260,https://scrap.kakaocdn.net/dn/VkXsN/hyZnbA9rAP/fm3au4B38Kr4phtw2aFJR1/img.png?width=960&amp;amp;height=640&amp;amp;face=0_0_960_640,https://scrap.kakaocdn.net/dn/48xeT/hyZnDc69Rd/yZEkrHsLqbK7iWcTxvJsik/img.png?width=1045&amp;amp;height=480&amp;amp;face=0_0_1045_480');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;애플 로그인 설정하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;참고: 같은 이름(닉네임)으로 중복 가입 방지 옵션을 해제해 주세요. 소셜 로그인 가입자는 대부분 가입된 플랫폼의 이름(닉네임)을 그대로 사용하는 경향이 있으며, 소셜 로그인 플랫&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;imweb.me&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1753174387715&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Sign in with Apple | Apple Developer Documentation&quot; data-og-description=&quot;Provide users the ability to sign in to your apps and websites using their Apple ID.&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/signinwithapple&quot; data-og-url=&quot;https://docs.developer.apple.com/documentation/signinwithapple&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hyscQ/hyZncmxNyS/cpJ5Zkds19KyOSf4Xd5My0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bIFqjb/hyZnjTuEB7/e98qrm7bwscYAFw5YVuhaK/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/signinwithapple&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/signinwithapple&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hyscQ/hyZncmxNyS/cpJ5Zkds19KyOSf4Xd5My0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bIFqjb/hyZnjTuEB7/e98qrm7bwscYAFw5YVuhaK/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Sign in with Apple | Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Provide users the ability to sign in to your apps and websites using their Apple ID.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1753174400033&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Sign in with Apple REST API | Apple Developer Documentation&quot; data-og-description=&quot;Communicate between your app servers and Apple&amp;rsquo;s authentication servers.&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/signinwithapplerestapi&quot; data-og-url=&quot;https://docs.developer.apple.com/documentation/signinwithapplerestapi&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/WLCoX/hyZnAm9UIi/ishbFeRvjxhKkk8d2Bvk2k/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ixjeB/hyZntauM1I/WjC9m320KYfVFFYJlJ1gM1/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/signinwithapplerestapi&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/signinwithapplerestapi&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/WLCoX/hyZnAm9UIi/ishbFeRvjxhKkk8d2Bvk2k/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ixjeB/hyZntauM1I/WjC9m320KYfVFFYJlJ1gM1/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Sign in with Apple REST API | Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Communicate between your app servers and Apple&amp;rsquo;s authentication servers.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS</category>
      <category>IOS</category>
      <category>SWIFT</category>
      <category>UIKit</category>
      <category>공공돌</category>
      <category>애플 로그인</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/184</guid>
      <comments>https://sheep1sik.tistory.com/184#entry184comment</comments>
      <pubDate>Tue, 22 Jul 2025 17:51:15 +0900</pubDate>
    </item>
    <item>
      <title>AutoLayout - 화면 겹침 현상 (StackView 내 CustomView 겹침)</title>
      <link>https://sheep1sik.tistory.com/183</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 상황&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div data-message-id=&quot;9901dbf0-a833-4155-a19a-1f7077c08ea0&quot; data-message-author-role=&quot;user&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZE93q/btsPotddnXy/DFt2Qp3CEIHezkFAytWVC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZE93q/btsPotddnXy/DFt2Qp3CEIHezkFAytWVC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZE93q/btsPotddnXy/DFt2Qp3CEIHezkFAytWVC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZE93q%2FbtsPotddnXy%2FDFt2Qp3CEIHezkFAytWVC0%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;453&quot; height=&quot;340&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UIStackView 내부에 WorkplaceContainerView, PayContainerView를 배치했음에도 불구하고, 두 뷰가 겹쳐서 출력되는 현상이 발생&lt;/li&gt;
&lt;li&gt;내부 요소들이 정상적으로 구성되었음에도 StackView가 자식 뷰의 높이를 인식하지 못해 UI가 깨짐&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;원인 분석&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UIStackView는 자식 뷰의 &lt;b&gt;명시적인 높이 제약 또는 intrinsic content size&lt;/b&gt;가 없는 경우, 뷰의 높이를 0으로 인식함&lt;/li&gt;
&lt;li&gt;WorkplaceContainerView와 PayContainerView 모두 내부에 UI를 배치한 container 뷰만 있고, 해당 뷰의 하단 요소를 기준으로 전체 높이를 계산하는 제약이 빠져있었음&lt;/li&gt;
&lt;li&gt;distribution을 .equalSpacing으로 설정한 것도 자식 뷰 간의 간격 계산을 비정상적으로 만들 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;해결 방안&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 컨테이너 뷰(WorkplaceContainerView, PayContainerView)의 하단에 다음 제약을 추가하여, &lt;b&gt;자신의 높이를 내부 container 기준으로 결정&lt;/b&gt;하도록 유도&lt;/li&gt;
&lt;li&gt;StackView의&amp;nbsp;&lt;b&gt;distribution&lt;/b&gt;을&amp;nbsp;&lt;b&gt;.fill&lt;/b&gt;로&amp;nbsp;변경하여&amp;nbsp;높이&amp;nbsp;계산을&amp;nbsp;자동으로&amp;nbsp;처리하도록&amp;nbsp;수정&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1752747779693&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;self.snp.makeConstraints {
    $0.bottom.equalTo(container.snp.bottom)
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1752747862045&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;stackView.distribution = .fill&lt;/code&gt;&lt;/pre&gt;</description>
      <category>트러블 슈팅</category>
      <category>AutoLayout</category>
      <category>IOS</category>
      <category>SWIFT</category>
      <category>공공돌</category>
      <category>트러블 슈팅</category>
      <author>Sheep1sik</author>
      <guid isPermaLink="true">https://sheep1sik.tistory.com/183</guid>
      <comments>https://sheep1sik.tistory.com/183#entry183comment</comments>
      <pubDate>Thu, 17 Jul 2025 19:24:45 +0900</pubDate>
    </item>
  </channel>
</rss>