<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>p-intelligence.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 11 Aug 2023 07:19:55 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. p-intelligence.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/p-intelligence" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[번역]What’s new in the Jetpack Compose August ’23 release]]></title>
            <link>https://velog.io/@p-intelligence/%EB%B2%88%EC%97%ADWhats-new-in-the-Jetpack-Compose-August-23-release</link>
            <guid>https://velog.io/@p-intelligence/%EB%B2%88%EC%97%ADWhats-new-in-the-Jetpack-Compose-August-23-release</guid>
            <pubDate>Fri, 11 Aug 2023 07:19:55 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>곧 출시될 8월의 컴포즈 Bill of Materials의 일환으로 젯팩 컴포즈 1.5를 출시한다. 젯팩 컴포즈는 플레이 스토어, 드롭박스, 에어비앤비와 같은 앱에서 사용되는 안드로이드의 현대적이고 네이티브한 UI 툴이다. 이번 업데이트에는 주로 성능 개선에 중점을 두었으며, 2022년 10월 업데이트부터 시작한 모디파이어 리팩토링이 이번 업데이트에 적용됐다.</p>
<p>2021년 컴포즈 1.0에서는 올바른 표준 api 구축하여 안정적인 기반을 제공하는데 중점을 두었다. 구글은 더 강한 양질의 api를 필요로 했으며, 사용이 쉽고 안정적이어서 개발자들이 프로덕션 환경에서 사용할 수 있도록 했다. 지속적인 api 개선에서 성능 향상은 최우선이며, 이번 업데이트에서는 많은 성능 개선 사항이 도입됐다.</p>
<h2 id="모디파이어-성능">모디파이어 성능</h2>
<p>상술한 바와 같이 이번 업데이트에서 대규모 성능 개선이 이루어졌는데 컴포지션(앱 ui를 설정하고 컴포저블을 실행하여 재생성하는 일련의 과정) 시간이 최대 80% 단축됐다. 이는 컴포즈 첫 출시에 표준 api가 올바르게 구축되어 나타난 결과이며, 컴포즈로 작성된 앱 대부분이 이러한 이점을 누릴 수 있다.</p>
<p>구글에서는 성능 회귀를 모니터링하고, 성능 향상 투자에 이용되는 벤치마크 스위트를 보유 중이다. 초기 1.0 배포 이후에는 <strong>무엇을 개선할 수 있는가</strong>에 중점을 두었고, 벤치마크를 예상보다 더 많은 시간을 투자해 모디파이어를 구체화하고 있음을 알 수 있었다. 모디파이어는 컴포즈 트리 대부분을 차지하며, 이로 인해 컴포즈의 컴포지션 시간에서 가장 많은 부분을 차지하게 됐다. 더 효율적인 디자인으로 모디파이어를 리팩토링한 작업은 2022년 10월에 출시됐다.</p>
<p>2022년 10월 업데이트에서는 최하위 모듈인 컴포즈 ui에서 신규 api 출시와 성능 개선이 이루어졌다. 모디파이어는 서로 빌드되기에 다음 배포(2023년 3월)애서는 컴포즈 파운데이션에서 최하위 모디파이어의 마이그레이션을 시작했다. 해당 작업에는 <code>graphicsLayer</code>, 최하위 포커스 모디파이어, <code>padding</code>과 <code>offset</code>이 포함되어 있다. 이러한 최하위 모디파이어들은 <code>Clickable</code>과 같은 많은 모디파이어들에 의해 사용되며, <code>Text</code>와 같이 프레임워크 컴포저블에서도 사용된다. 2023년 3월 업데이트에서 모디파이어를 이전하면 이러한 컴포넌트에 성능 개선이 이루어질 수 있지만, 실제로 큰 효과를 볼 수 있는 것은 고수준의 모디파이어들과 컴포저블 자체를 신규 모디파이어 시스템으로 이전할 때이다.</p>
<p>이번 업데이트에서는 <code>Clickable</code> 모디파이어를 신규 모디파이어 시스템으로 마이그레이션하기 시작하여 컴포지션 시간이 최대 80% 단축됐다. 특히 버튼과 같이 클릭 가능한 요소를 포함하는 지연 목록(lazy list)에서 유용하다. <code>Clickable</code>에서 사용되는 <code>Modifier.indication</code>은 아직 마이그레이션 단계에 있으며, 향후 업데이트에 추가적인 개선이 있을 것으로 예상된다.</p>
<p>이 작업의 일환으로 원래 리팩토링에서 다루지 않은 <code>composed</code> 모디파이어에 대한 사용 사례를 확인하고, <code>CompositionLocal</code> 인스턴스를 사용하는 <code>Modifier.Node</code>를 생성하기 위한 신규 api를 추가했다.</p>
<p>현재 자신의 모디파이어를 신규 <code>Modifier.Node</code> api로 마이그레이션 절차에 관한 문서는 미작성 상태이며, 마이그레이션을 하려면 <a href="https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/ModifierSamples.kt">샘플 코드</a>를 참고하길 바란다.</p>
<p>변경 사항에 대한 자세한 내용은 Android Dev Summit &#39;22의 <a href="https://youtu.be/BjGX2RftXsU">Compose Modifiers deep dive</a>를 확인하실 바란다.</p>
<h2 id="메모리">메모리</h2>
<p>이번 업데이트에는 메모리 사용에 대한 여러 개선 사항이 포함되어 있다. 다양한 컴포즈 api 간에 발생하는 할당을 조사하여 많은 영역, 특히 그래픽 스택과 벡터 리소스를 불러올 때 총 할당량을 감소시켰다. 이는 컴포즈의 메모리 풋프린트를 줄일 뿐만 아니라, 메모리 할당 시간을 줄이고 가비지 수집을 감소시켜 성능이 직접적으로 향상됐다.</p>
<p>또한, <code>ComposeView</code>를 사용할 때 발생하는 메모리 누수에 대해 개선을 진행했다. 이로 인해 모든 앱은 긍정적인 영향을 받을 것이며, 특히 멀티 액티비티 아키텍처나 대량의 view/compose 상호 운용을 사용하는 앱에 큰 이점으로 다가올 것이다.</p>
<h2 id="text">Text</h2>
<p><code>BasicText</code>는 모디파이어 작업을 지원하는 신규 렌더링 시스템으로 이동됐으며, 이로 인해 초기 컴포지션 시간이 평균적으로 22% 감소했으며, 텍스트가 포함된 복잡한 레이아웃의 한 벤치마크에서는 최대 70%까지 감소되었다.</p>
<p>다음을 포함한 여러 텍스트 관련 api가 안정화됐다.</p>
<ul>
<li><code>TextMeasurer</code>와 그에 관한 api</li>
<li><a href="https://android-review.googlesource.com/c/platform/frameworks/support/+/2485834"><code>LineHeightStyle.Alignment</code> (topRatio)</a></li>
<li><code>Brush</code></li>
<li><code>DrawStyle</code></li>
<li><code>TextMotion</code></li>
<li><code>DrawScope.drawText</code></li>
<li><code>Paragraph.paint</code> (brush, drawStyle, blendMode)</li>
<li><code>MultiParagraph.paint</code> (brush, drawStyle, blendMode)</li>
<li><code>PlatformTextInput</code></li>
</ul>
<h2 id="핵심-기능에-대한-개선-및-수정">핵심 기능에 대한 개선 및 수정</h2>
<p>이번 업데이트에는 상술한 기능 외에도 핵심 api의 신규 기능과 개선점도 존재한다.</p>
<ul>
<li><code>LazyStaggeredGrid</code> 안정화</li>
<li><code>toComposePaint</code>를 대체하는 <code>asComposePaint</code> api가 추가됐으며, 리턴된 객체는 원본 <code>android.graphics.Paint</code>를 래핑하기 위해 사용된다.</li>
<li><code>SubcomposeLayout</code>에 선행 검사를 지원하는 <a href="https://cs.android.com/androidx/platform/tools/dokka-devsite-plugin/+/master:testData/compose/samples/ui/samples/SubcomposeLayoutSample.kt;l=56">IntermediateMeasurePolicy</a> 추가</li>
<li>소프트 키보드가 나타나기 전에 키 이벤트를 가로채는 <a href="https://android-review.googlesource.com/c/platform/frameworks/support/+/2480419">onInterceptKeyBeforeSoftKeyboard</a> 모디파이어 추가</li>
</ul>
<h2 id="원문">원문</h2>
<ul>
<li><a href="https://android-developers.googleblog.com/2023/08/whats-new-in-jetpack-compose-august-23-release.html">What’s new in the Jetpack Compose August ’23 release</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[번역]What's new in Kotlin 1.9.0]]></title>
            <link>https://velog.io/@p-intelligence/%EB%B2%88%EC%97%ADWhats-new-in-Kotlin-1.9.0</link>
            <guid>https://velog.io/@p-intelligence/%EB%B2%88%EC%97%ADWhats-new-in-Kotlin-1.9.0</guid>
            <pubDate>Thu, 03 Aug 2023 04:55:57 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>코틀린 1.9.0 릴리즈가 올해 7월 6일에 출시되으며 JVM용 K2 컴파일러 또한 베타 버전이 되었다.
아래는 코틀린 1.9.0의 주 특성이다.</p>
<ul>
<li>코틀린 K2 컴파일러 업데이트</li>
<li>열거형 클래스의 value 기능에 대한 안정적인 대체</li>
<li>개방형 범위 <code>..&lt;</code> 연산자 안정화</li>
<li>regex 캡쳐 그룹을 이름으로 가져오는 신규 공통 함수</li>
<li>상위 디렉토리 생성을 위한 새 경로 유틸리티</li>
<li>코틀린 다중 플랫폼에서 gradle 환경 설정 캐시 미리보기</li>
<li>코틀린 다중 플랫폼에서 Android Target 지원 변경</li>
<li>Kotlin/Native에서 사용자 지정 메모리 할당자 미리보기</li>
<li>Kotlin/Native의 라이브러리 연결</li>
<li>Kotlin/Wasm size 관련 최적화</li>
</ul>
<h2 id="지원-ide">지원 IDE</h2>
<p>코틀린 1.9.0을 지원하는 IDE는 아래와 같다.</p>
<table>
<thead>
<tr>
<th align="center">IDE</th>
<th align="center">지원하는 버전</th>
</tr>
</thead>
<tbody><tr>
<td align="center">IntelliJ IDEA</td>
<td align="center">2022.3.x, 2023.1.x</td>
</tr>
<tr>
<td align="center">Android Studio</td>
<td align="center">Giraffe (223), Hedgehog (231)</td>
</tr>
</tbody></table>
<p>또한, 코틀린 1.9.0은 추후에 출시될 IntelliJ IDEA 2023.2에도 지원될 것이다.</p>
<pre><code class="language-text">코틀린 아티팩트와 종속성을 다운로드하려면 Maven Central Repository를 사용하도록 Gradle 설정을 필수로 구성해야 한다.</code></pre>
<h2 id="코틀린-k2-컴파일러-업데이트">코틀린 K2 컴파일러 업데이트</h2>
<p>K2 컴파일러는 Kotlin/Native 및 다중 플랫폼 프로젝트에 대한 기본적인 지원이 있다.</p>
<h3 id="k2-컴파일러와-kapt-컴파일러-플러그인의-호환성">K2 컴파일러와 kapt 컴파일러 플러그인의 호환성</h3>
<p>k2 컴파일러와 kapt 플러그인을 같은 프로젝트에서 사용할 수 있지만, 몇 가지 제한 사항이 존재한다. <code>languageVersion</code>을 2.0으로 설정했음에도 kapt 컴파일러는 구식 컴파일러를 사용한다.</p>
<p><code>languageVersion</code>이 2.0으로 설정된 프로젝트에서 kapt 컴파일러 플러그인을 실행하면 kapt는 자동으로 1.9로 전환되고 특정 버전 호환성 검사를 비활성화한다. 이 동작은 아래의 명령 인수를 포함하는 것과 같다.</p>
<ul>
<li><code>-Xskip-metadata-version-check</code></li>
<li><code>-Xskip-prerelease-check</code></li>
<li><code>-Xallow-unstable-dependencies</code></li>
</ul>
<p>이러한 검사는 kapt 작업에만 사용이 불가능하다. 타 컴파일 작업은 k2 컴파일을 계속 사용할 것이다.</p>
<h3 id="프로젝트에서-k2-컴파일러-사용">프로젝트에서 K2 컴파일러 사용</h3>
<p>코틀린 1.9.0부터 2.0까지 <code>kotlin.experimental.tryK2=true</code> gradle 속성으로 k2 컴파일러를 테스트할 수 있다. 혹은 아래의 명령어를 실행해 테스트할 수 있다.</p>
<pre><code class="language-bash">$ ./gradlew assemble -Pkotlin.experimental.tryK2=true
</code></pre>
<p>해당 gradle 속성은 자동으로 언어 버전으로 2.0으로 설정하고, 현재 컴파일러와 비교하여 k2 컴파일러를 사용해 컴파일한 코틀린 태스크의 수로 빌드 리포트를 업데이트한다.</p>
<pre><code class="language-text">##### &#39;kotlin.experimental.tryK2&#39; results (Kotlin/Native not checked) #####
:lib:compileKotlin: 2.0 language version
:app:compileKotlin: 2.0 language version
##### 100% (2/2) tasks have been compiled with Kotlin 2.0 #####</code></pre>
<h3 id="gradle-build-리포트">Gradle build 리포트</h3>
<p>gradle build 리포트는 코드 컴파일에 현재 컴파일러의 사용 여부와 k2 컴파일러의 사용 여부가 표시된다. 코틀린 1.9.0에서는 해당 정보를 gradle 빌드 스캔에서 확인할 수 있다.
<img src="https://velog.velcdn.com/images/p-intelligence/post/2da4ef07-cd1c-43c7-82b2-bc7c1fcc03b4/image.png" alt="gradle build report 1"></p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/c3cd3670-d2aa-4491-967c-98be55229495/image.png" alt="gradle build report 2"></p>
<p>프로젝트에서 사용된 코틀린 버전 또한 빌드 리포트에서 찾을 수 있다.</p>
<pre><code class="language-text">Task info:
  Kotlin language version: 1.9</code></pre>
<h3 id="현재-k2-컴파일러-제한-사항">현재 K2 컴파일러 제한 사항</h3>
<p>gradle 프로젝트에서 k2를 활성화하면 아래와 같은 경우, gradle 버전 8.3 미만을 사용하는 프로젝트에 영향을 미칠 수 있는 몇 가지 제한 사항이 존재한다.</p>
<ul>
<li><code>buildSrc</code>에서 소스 코드 컴파일</li>
<li>gradle 플러그인 컴파일이 포함된 빌드</li>
<li>gradle 버전 8.3 미만을 사용하는 프로젝트에서 타 gradle 플러그인을 컴파일</li>
<li>gradle 플러그인 종속성 빌드</li>
</ul>
<p>위에서 언급한 문제 중 하나가 발생했을 경우, 다음 단계를 수행하여 해결할 수 있다.</p>
<ul>
<li><code>buildSrc</code>, 모든 gradle 플러그인 및 해당 종속성에 대한 언어 버전을 설정<pre><code class="language-kotlin">kotlin {
  compilerOptions {
      languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9)
      apiVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9)
  }
}</code></pre>
</li>
<li>프로젝트의 gradle 버전을 8.3으로 업데이트</li>
</ul>
<h2 id="언어">언어</h2>
<p>코틀린 1.9.0에서는 상술한 새로운 기능에 대한 안정화를 진행하고 있다.</p>
<h3 id="열거형-클래스의-value-기능-대체">열거형 클래스의 value 기능 대체</h3>
<p>코틀린 1.8.20에서 열거형 클래스에 대한 <code>entries</code> 프로퍼티는 실험 기능으로 도입됐다.
<code>entries</code> 프로퍼티는 합성 <code>value()</code> 함수를 안정적으로 대체한다.(<code>value()</code> 함수는 지원되지만 공식 문서에서는 <code>entries</code> 프로퍼티 사용을 권장)</p>
<pre><code class="language-kotlin">enum class Color(val colorName: String, val rgb: String) {
    RED(&quot;Red&quot;, &quot;#FF0000&quot;),
    ORANGE(&quot;Orange&quot;, &quot;#FF7F00&quot;),
    YELLOW(&quot;Yellow&quot;, &quot;#FFFF00&quot;)
}

fun findByRgb(rgb: String): Color? = Color.entries.find { it.rgb == rgb }</code></pre>
<p>열거형 클래스의 <code>entries</code> 프로퍼티에 대한 내용은 <a href="https://kotlinlang.org/docs/whatsnew1820.html#preview-of-data-objects-for-symmetry-with-data-classes">What&#39;s new in Kotlin 1.8.20</a>을 참고하길 바란다.</p>
<h3 id="데이터-클래스와의-데이터-객체-대칭">데이터 클래스와의 데이터 객체 대칭</h3>
<p><a href="https://kotlinlang.org/docs/whatsnew1820.html#preview-of-data-objects-for-symmetry-with-data-classes">코틀린 1.8.20에 도입</a>된 데이터 객체선언은 안정화가 되었다. 여기에는 데이터 클래스와의 대칭을 위해 추가된 함수인 <code>toString()</code>, <code>equals()</code>, <code>hashCode()</code> 함수가 포함된다.</p>
<p>해당 기능은 데이터 객체 선언과 함께 편리하게 사용할 수 있기에 <code>sealed</code> 계층(sealed 클래스나 sealed 인터페이스 계층)에 특히 유용하다. 아래의 예제에서 <code>EndOfFile</code>을 일반 개체 대신 데이터 개체로 선언하면 재정의할 필요 없이 <code>toString()</code> 함수를 자동으로 포함한다. 이는 함께 제공되는 데이터 클래스 정의와 대칭을 유지한다.</p>
<pre><code class="language-kotlin">sealed interface ReadResult
data class Number(val number: Int) : ReadResult
data class Text(val text: String) : ReadResult
data object EndOfFile : ReadResult

fun main() {
    println(Number(7)) // Number(number=7)
    println(EndOfFile) // EndOfFile
}</code></pre>
<p>자세한 내용은 <a href="https://kotlinlang.org/docs/whatsnew1820.html#preview-of-data-objects-for-symmetry-with-data-classes">What&#39;s new in Kotlin 1.8.20</a>을 참고하길 바란다.</p>
<h3 id="인라인-value-클래스에-본문이-있는-보조-생성자-지원">인라인 value 클래스에 본문이 있는 보조 생성자 지원</h3>
<p>코틀린 1.9.0부터 인라인 value 클래스에 본문이 있는 보조 생성자를 사용할 수 있다.</p>
<pre><code class="language-kotlin">@JvmInline
value class Person(private val fullName: String) {
    // 코틀린 1.4.30부터 허용
    init {
        check(fullName.isNotBlank()) {
            &quot;Full name shouldn&#39;t be empty&quot;
        }
    }
    // 코틀린 1.9.0부터 기본적으로 허용
    constructor(name: String, lastName: String) : this(&quot;$name $lastName&quot;) {
        check(lastName.isNotBlank()) {
            &quot;Last name shouldn&#39;t be empty&quot;
        }
    }
}</code></pre>
<p>이전에 코틀린은 인라인 클래스에서 공개 기본 생성자만 허용했다. 결과적으로 기본 값을 캡슐화하거나 일부 제한된 값을 나타내는 인라인 클래스를 만드는 것은 불가능했다.
코틀린이 개발되며 이러한 문제가 수정되었다. 코틀린 1.4.30에서는 <code>init</code> 블록에 대한 제한이 해제되었고 코틀린 1.8.20에서는 본문이 있는 보조 생성자의 미리보기가 제공되었다. 이제 기본적으로 사용할 수 있게 됐다. <a href="https://github.com/Kotlin/KEEP/blob/master/proposals/inline-classes.md">이 페이지</a>에서 코틀린 인라인 클래스의 개발 과정에 대한 내용이 기술되어 있다.</p>
<h2 id="kotlinjvm">Kotlin/JVM</h2>
<p>코틀린 1.9.0부터 컴파일러는 jvm 20에 해당하는 바이트코드 버전으로 클래스를 생성할 수 있다. 또한 <code>JvmDefault</code> 어노테이션 및 레거시 <code>-Xjvm-default</code> 모드는 더 이상 사용되지 않는다.</p>
<p>코틀린 1.5부터 <code>JvmDefault</code> 어노테이션은 사용되지 않으며 <code>-Xjvm-default</code> 모드(all 및 all-compatibility)를 우선하는 방식으로 대체되었다. 코틀린 1.4에 도입된 <code>JvmDefaultWithoutCompatibility</code>와 코틀린 1.6에 도입된 <code>JvmDefaultWithCompatibility</code>와 함께, 이러한 모듈들은 <code>DefaultImpls</code> 클래스의 생성에 대한 포괄적인 제어를 제공하며, 이전 코틀린 코드와의 원활한 호환성을 보장한다.</p>
<p>결과적으로 코틀린 1.9.0에서는 <code>JvmDefault</code> 어노테이션이 지원되지 않기 때문에 사용 시, 오류가 발생하며, 추후 코틀린에서 제거될 예정이다.</p>
<h2 id="kotlinnative">Kotlin/Native</h2>
<p>코틀린 1.9.0 릴리즈는 <a href="https://kotlinlang.org/docs/native-memory-manager.html#garbage-collector">Kotlin/Native 메모리 관리자</a>에게 견고성과 성능 향상을 위한 추가적인 개선점을 제공한다.</p>
<h3 id="사용자-지정-메모리-할당기-미리보기">사용자 지정 메모리 할당기 미리보기</h3>
<p>코틀린 1.9.0은 사용자 지정 메모리 할당기에 대한 미리보기를 제공한다. 해당 할당 시스템은 Kotlin/Native 메모리 관리자의 런타임 성능을 향상시킨다.</p>
<p>현재 kotlin/native의 객체 할당 시스템은 효율적인 Garbage Collection(이하 gc)을 위한 기능이 없는 범용 할당기를 사용한다. 이를 보완하기 위해 gc가 할당된 모든 객체를 단일 목록으로 병합하기 전에 스레드-로컬의 링크드 리스트를 유지한다. 해당 접근 방식에는 아래와 같은 성능 저하가 있다.</p>
<ol>
<li>스위핑 순서는 메모리 로컬리티가 부족하고, 대부분의 경우 메모리 액세스 패턴이 분산되며 이는 잠재적인 성능 문제로 직결된다.</li>
<li>링크드 리스트에는 각 개체에 대한 추가 메모리가 필요하며 특히 작은 개체를 많이 처리할 때 메모리 사용량이 증가한다.</li>
<li>할당된 개체의 단일 리스트는 스윕을 병렬화하기 어렵게 만든다. 이로 인해 뮤테이터 스레드가 gc 스레드보다 빠르게 개체를 할당할 때 메모리 사용 문제가 발생할 수 있다.</li>
</ol>
<p>이러한 문제를 해결하기 위해 코틀린 1.9.0에서 사용자 지정 할당기 미리보기를 도입한다. 시스템 메모리를 페이지로 분할하여 순차적으로 독립적인 스위핑이 가능하다. 각 할당은 페이지 내 블록이 되고, 페이지는 블록의 크기를 추적한다. 서로 다른 페이지 유형은 다양한 할당 크기에 최적화되어 있으며 메모리 블록들의 연속적인 배열은 할당된 모든 블록들을 통해 효율적인 반복을 보장한다.</p>
<p>스레드가 메모리를 할당할 때 할당 크기에 따라 적합한 페이지를 검색한다. 스레드는 다양한 크기 범주에 대한 페이지 집합을 유지한다. 일반적으로 현재 페이지는 주어진 크기에 대한 할당을 수용할 수 있다. 그렇지 않으면 스레드는 공유 할당 공간에서 다른 페이지를 요청하게 되고, 해당 페이지는 이미 사용 중이거나 스위핑이 필요할 수 있으며, 먼저 생성되어야 할 수도 있다.</p>
<p>새로운 할당기는 복수의 할당 공간을 동시에 가질 수 있게 해주는데, 코틀린팀은 성능 향상을 위한 다양한 페이지 레이아웃을 실험적으로 사용할 수 있게 해준다.</p>
<p>새 할당기 설계에 대한 내용은 <a href="https://github.com/JetBrains/kotlin/blob/master/kotlin-native/runtime/src/custom_alloc/README.md">이 문서</a>를 참조하면 된다.</p>
<p><code>-Xallocator=custom</code>을 추가하면 사용할 수 있다.</p>
<pre><code class="language-kotlin">kotlin {
    macosX64(&quot;native&quot;) {
        binaries.executable()

        compilations.configureEach {
            compilerOptions.configure {
                freeCompilerArgs.add(&quot;-Xallocator=custom&quot;)
            }
        }
    }
}</code></pre>
<h3 id="메인-스레드의-objective-c-혹는-swift-객체-할당-해제-hook">메인 스레드의 Objective-C 혹는 Swift 객체 할당 해제 hook</h3>
<p>코틀린 1.9.0부터 objective-C 혹은 Swift 객체 할당 해제 hook는 객체가 코틀린에게 전달되면 메인 스레드에서 호출된다. kotlin/native 메모리 관리자가 이전에 objective-c 객체에 대한 참조를 처리하는 방식에 의해 메모리 누수 문제가 발생할 수 있었다. 새로운 동작은 메모리 관리자의 견고성을 향상시킬 수 있다.</p>
<p>예를 들어 인수로 전달되거나 함수에 의해 리턴되거나 컬렉션에서 검색될 때 코틀린 코드에서 참조되는 objective-c 객체를 생각해보면 코틀린은 objective-c 객체에 대한 참조를 보유하는 자체 객체를 생성한다. 코틀린 객체가 할당이 해제되면 kotlin/native 런타임은 <code>objc_release</code> 함수를 호출하여 objective-c 참조를 해제한다.</p>
<p>이전에는 kotlin/native 메모리 관리자가 <code>objc_release</code>를 special gc 스레드에서 실행했으며 그것이 마지막 개체의 참조라면 개체의 할당이 해제된다. objective-c 객체에 objective-c의 <code>delloc</code> 메소드나 swift의 <code>deinit</code> 블록과 같은 사용자 지정 할당 해제 hook가 있고 이러한 hook가 특정 스레드에서 호출된다면 문제가 발생할 수 있다.</p>
<p>일반적으로 메인 스레드의 객체 hook가 거기서 호출된다고 가정하기 때문에 kotlin/native 런타임은 메인 스레드에서도 <code>objc_release</code>를 호출한다. objective-c 객체가 메인 스레드의 코틀린에 전달되어 코틀린 peer 객체가 생성된 경우에 대해 설명한다. 일반 UI 애플리케이션의 경우, 메인 디스패치 대기열이 처리되는 경우에만 동작한다. 메인 큐가 아니거나 메인 스레드 이외에 타 스레드로 코틀린에 넘겨받았을 경우, 이전과 동일하게 special gc 스레드에서 <code>objc_release</code>가 호출된다.</p>
<h4 id="비활성화">비활성화</h4>
<p>문제가 발생했을 경우, 아래의 옵션을 사용해 <code>gradle.properties</code>에서 해당 동작을 비활성화할 수 있다.</p>
<pre><code class="language-kotlin">kotlin.native.binary.objcDisposeOnMain=false</code></pre>
<h3 id="kotlinnative에서-상수-값에-액세스할-때-객체-초기화하지-않음">Kotlin/Native에서 상수 값에 액세스할 때 객체 초기화하지 않음</h3>
<p>코틀린 1.9.0부터 kotlin/native 백엔드 <code>const val</code> 필드에 액세스할 때 객체를 초기화하지 않는다.</p>
<pre><code class="language-kotlin">object MyObject {
    init {
        println(&quot;side effect!&quot;)
    }

    const val y = 1
}

fun main() {
    println(MyObject.y) // 처음에는 초기화 없음
    val x = MyObject    // 초기화
    println(x.y)
}</code></pre>
<p>이 동작은 kotlin/jvm에 통합되어 구현은 자바와 일관하고 있어, 이 경우에는 객체 초기화가 진행되지 않는다. 이 변경으로 kotlin/native 프로젝트의 성능 향상도 기대해 볼 수 있다.</p>
<h3 id="kotlinnative에서-ios-시뮬레이터-테스트를-위한-독립-실행형-모드-구성-기능">Kotlin/Native에서 iOS 시뮬레이터 테스트를 위한 독립 실행형 모드 구성 기능</h3>
<p>기본적으로 kotlin/native iOS 시뮬레이터 테스트를 실행하는 경우 <code>--standalone</code> 플래그를 사용하여 수동 시뮬레이터 부팅 및 종료를 방지한다. 1.9.0에서는 독립 실행형 속성을 사용하여 gradle 작업에서 해당 플래그의 사용 여부를 설정할 수 있다. 기본적으로 <code>--standalone</code> 플래그가 사용되므로 독립 실행형 모드는 활성화된다.</p>
<p>아래의 코드는 <code>build.gradle.kts</code>에서 독립 실행형 모드를 비활성화하는 코드이다.</p>
<pre><code class="language-kotlin">tasks.withType&lt;org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest&gt;().configureEach {
    standalone.set(false)
}</code></pre>
<p>독립 실행형 모드를 사용하지 않도록 설정한 경우, 시뮬레이터를 수동으로 부팅해야 한다. cli에서 시뮬레이터를 부팅하려면 아래의 명령어를 사용하면 된다.</p>
<pre><code class="language-bash">$ /usr/bin/xcrun simctl boot &lt;DeviceId&gt;</code></pre>
<h3 id="kotlinnative-라이브러리의-연결">Kotlin/Native 라이브러리의 연결</h3>
<p>코틀린 1.9.0부터 kotlin/native 컴파일러는 코틀린 라이브러리와 링크 문제를 kotlin/jvm과 동일하게 처리하게 된다. 어느 서드파티 코틀린 라이브러리 작성자가 타 서드파티 코틀린 라이브러리에서 사용하는 실험적 API에 호환되지 않은 변경을 가하는 경우, 이러한 문제에 직면하게 된다.</p>
<p>타사 코틀린 라이브러리 간의 링크 문제가 발생하더라도 컴파일 도중 빌드가 실패할 일은 없다. 대신, jvm의 경우와 같이 이러한 에러는 런타임에서만 발생한다.</p>
<p>kotlin/native 컴파일러는 라이브러리 링크 문제를 감지하면 경고를 보고한다. 예를 들어 컴파일 로그에서 아래와 같은 경고를 발견했다고 했을 때</p>
<pre><code class="language-text">No function found for symbol &#39;org.samples/MyRemovedClass.doSomething|3657632771909858561[0]&#39;

Can not get instance of singleton &#39;MyEnumClass.REMOVED_ENTRY&#39;: No enum entry found for symbol &#39;org.samples/MyEnumClass.REMOVED_ENTRY|null[0]&#39;

Function &#39;getMyRemovedClass&#39; can not be called: Function uses unlinked class symbol &#39;org.samples/MyRemovedClass|null[0]&#39;</code></pre>
<p>프로젝트에서 아래의 동작을 추가로 구성하거나 비활성화할 수 있다.</p>
<ul>
<li><p>컴파일 로그에서 위와 같은 경고를 표시하지 않으려면 <code>-Xpartial-linkage-loglevel=INFO</code> 컴파일 옵션을 설정하면 된다. 해당 옵션은 경고 심각도를 info 레벨로 낮추어 표시한다.</p>
</li>
<li><p>컴파일 옵션을 <code>-Xpartial-linkage-loglevel=ERROR</code>로 설정하여 보고된 경고 심각도를 에러 레벨로 올려서 표시한다. 이 경우에는 컴파일이 실패하고 컴파일 로그에 모든 오류가 표시된다. 해당 옵션을 사용하면 링크 문제를 더 상세히 확인할 수 있다.</p>
</li>
<li><p>해당 기능으로 예기치 않은 문제가 발생하면 <code>-Xpartial-linkage=disable</code> 컴파일 옵션을 사용해 해당 기능을 해제할 수 있다.</p>
<pre><code class="language-kotlin">// gradle 빌드 파일을 통해 컴파일 옵션을 지정하는 예제
kotlin {
  macosX64(&quot;native&quot;) {
      binaries.executable()

      compilations.configureEach {
          compilerOptions.configure {

              // 경고 레벨을 info로 낮춤
              freeCompilerArgs.add(&quot;-Xpartial-linkage-loglevel=INFO&quot;)

              // 경고 레벨을 error로 높임
              freeCompilerArgs.add(&quot;-Xpartial-linkage-loglevel=ERROR&quot;)

              // 기능 비활성화
              freeCompilerArgs.add(&quot;-Xpartial-linkage=disable&quot;)
          }
      }
  }
}</code></pre>
</li>
</ul>
<h3 id="c언어-상호-운용의-묵시적-정수-변환을-위한-컴파일-옵션">C언어 상호 운용의 묵시적 정수 변환을 위한 컴파일 옵션</h3>
<p>kotlin/native의 안정화를 진행하면서, 묵시적 정수 변환이 가능한 c언어 상호운용 컴파일 옵션을 도입했다. 이전에는 묵시적인 정수 변환을 사용하기 위해 컴파일 옵션을 구성하지 않아도 됐으나 신중히 검토한 결과, 해당 기능에 대한 개선의 여지가 보였고 최고품질의 API를 구현하기 위해 의도치 않은 사용을 방지하기 위해 해당 컴파일 옵션을 도입했다.</p>
<p>아래의 코드에서는 묵시적 정수 변환으로 인해 <code>options</code>의 타입이 <code>UInt</code>이지만 0은 부호가 있는 정수(signed)임에도 <code>options = 0</code>이 할당되었다.</p>
<pre><code class="language-kotlin">val today = NSDate()
val tomorrow = NSCalendar.currentCalendar.dateByAddingUnit(
    unit = NSCalendarUnitDay,
    value = 1,
    toDate = today,
    options = 0
)</code></pre>
<p>네이티브 interop 라이브러리에서 묵시적 변환을 사용하려면 <code>-XXLanguage:+ImplicitSignedToUnsignedIntegerConversion</code> 컴파일 옵션을 사용해야 한다.
이는 아래의 코드와 같이 <code>build.gradle.kts</code>에서 구성할 수 있다.</p>
<pre><code class="language-kotlin">tasks.withType&lt;org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile&gt;().configureEach {
    compilerOptions.freeCompilerArgs.addAll(
        &quot;-XXLanguage:+ImplicitSignedToUnsignedIntegerConversion&quot;
    )
}</code></pre>
<h2 id="kotlin-멀티플랫폼">Kotlin 멀티플랫폼</h2>
<p>코틀린 1.9.0에서는 코틀린 멀티플랫폼의 DX(개발자 경험)의 향상을 위해 아래와 같은 업데이트가 진행됐다.</p>
<h3 id="안드로이드를-대상으로-한-지원-변경">안드로이드를 대상으로 한 지원 변경</h3>
<p>구글의 안드로이드팀이 코틀린 멀티 플랫폼에서 안드로이드를 지원하는 자체 gradle 플러그인을 제공할 예정이다.
또한, 새로운 솔루션에 대한 가능성을 열기 위해 1.9.0 버전에서 현재 코틀린 dsl의 <code>android</code> 블록의 이름을 변경한다. 빌드 스크립트에서의 <code>android</code> 블록을 <code>androidTarget</code>으로 변경해야 한다. 이는 추후에 출시될 구글 dsl의 <code>android</code> 이름을 확보하기 위한 일시적인 변경이다.</p>
<p>구글 플러그인은 다중 플랫폼 프로젝트에서 안드로이드를 사용할 때 권장되는 방안이다. 준비되면 필요한 마이그레이션 지침을 제공하여 이전과 동일하게 <code>android</code> 이름을 사용할 수 있게 될 것이다.</p>
<h3 id="신규-안드로이드-소스-세트-레이아웃이-기본적으로-활성화">신규 안드로이드 소스 세트 레이아웃이 기본적으로 활성화</h3>
<p>코틀린 1.9.0부터 신규 안드로이드 소스 세트 레이아웃이 기본 설정으로 적용된다. 이전의 디렉토리 네이밍 스키마가 혼동스러웠던 것을 대체했으며, 신규 레이아웃은 아래와 같은 이점을 제공한다.</p>
<ol>
<li>유형의 의미론 단순화 - 신규 안드로이드 소스 세트 레이아웃은 타 소스 세트 유형을 정확하고 일관되게 구분이 가능하도록 명명 규칙을 제공한다.</li>
<li>소스 디렉토리 레이아웃 개선 - 신규 레이아웃을 통해 <code>SourceDirectories</code> 배열이 보다 일관적이게 구성되어 코드를 조직화하고 소스 파일를 쉽게 찾을 수 있다.</li>
<li>명확해진 gradle 네이밍 스키마 - 이제 <code>KotlinSourceSets</code>와 <code>AndroidSourceSets</code>에서 더 일관되고 예측 가능한 스키마를 사용한다.</li>
</ol>
<p>신규 레이아웃은 android gradle 7.0 이상과 Android Studio 2022.3 이상의 버전의 환경에서 사용할 수 있다. <code>build.gradle(.kts)</code>에서 필요한 변경 사항을 반영하려면 <a href="https://kotlinlang.org/docs/multiplatform-android-layout.html">마이그레이션 가이드</a>를 참고하길 바란다.</p>
<h3 id="gradle-환경-설정-캐시-미리보기">Gradle 환경 설정 캐시 미리보기</h3>
<p>코틀린 1.9.0은 멀티플랫폼 라이브러리에서 <a href="https://docs.gradle.org/current/userguide/configuration_cache.html">gradle 환경 설정 캐시</a>를 지원한다. 라이브러리 개발자는 이미 빌드 성능의 향상으로 이점을 누릴 수 있다.</p>
<p>gradle 환경 설정 캐시는 환경 설정 단계의 결과를 후속 빌드에 재사용하여 빌드 프로세스의 속도를 향상시킨다. 해당 기능은 gradle 8.1 이후에 안정화었으며 이를 활용하려면 <a href="https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:usage">gradle 문서의 지침</a>을 참고하길 바란다.</p>
<h2 id="kotlinwasm">Kotlin/Wasm</h2>
<p>코틀린팀은 신규 kotlin/wasm을 대상으로 실험을 하고 있다. 이 릴리즈에서 성능과 용량 관련 최적화와 자바스크립트 상호 운용성이 업데이트됐다.</p>
<h3 id="용량-관련-최적화">용량 관련 최적화</h3>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/83144e96-4785-4638-af59-e4dba61a383d/image.png" alt="wasm 용량 최적화 그래프"></p>
<p>코틀린 1.9.0에서 웹 어셈블리 프로젝트 용량이 개선되었다. 위의 그래프는 1.8.20에서 작성된 <code>Hello World</code> 프로젝트와 1.9.0에서 작성된 <code>Hello World</code> 프로젝트의 용량을 나타내며, 코드의 용량이 1.8.20에 비해 1/10 수준으로 감소한 것을 확인할 수 있다.
이러한 용량 최적화로 코틀린 코드로 wsam 플랫폼에서 더 효율적인 리소스 활용과 향상된 성능이라는 결과를 가져오게 된다.</p>
<h3 id="자바스크립트-상호-운용성-업데이트">자바스크립트 상호 운용성 업데이트</h3>
<p>이번 업데이트에서는 kotlin/wasm의 코틀린과 자바스크립트 간 상호 운용성이 포함된다. kotlin/wasm은 실험적인 기능이기에 상호 운용성에 대한 일부 제한 사항이 적용된다.</p>
<h4 id="동적-타입-제한">동적 타입 제한</h4>
<p>코틀린 1.9.0부터 더 이상 kotlin/wasm에서 동적 타입을 지원하지 않는다. 이제 이러한 동적 타입은 새로운 범용 <code>JsAny</code> 타입으로 대체되어 js 상호 운용성을 용이하게 한다.</p>
<p>자세한 내용은 <a href="https://kotlinlang.org/docs/wasm-js-interop.html">이 문서</a>을 참고하길 바란다.</p>
<h4 id="비외부형-타입의-제한">비외부형 타입의 제한</h4>
<p>kotlin/wasm은 자바스크립트와 값을 교환할 때 특정 코틀린 정적 타입에 대한 변환을 지원한다. 이러한 지원되는 타입은 다음과 같다.</p>
<ul>
<li>기본형 타입: 즉 부호가 있는 숫자나 <code>Boolean</code>, <code>Char</code> 등</li>
<li><code>String</code></li>
<li>함수 타입</li>
</ul>
<p>기타 타입들은 변환 없이 불분명한 참조로 전달되어 자바스크립트와 코틀린의 하위 타입 사이에서 불일치가 발생했다.
이를 해결하기 위해 코틀린은 자바스크립트 상호 운용성이 잘 지원되는 타입으로 제한된다. 코틀린 1.9.0부터는 kotlin.wasm 자바스크립트 상호 운영성에서 오직 external, primitive, string과 함수 타입만을 지원한다. 더불어, kotlin/wasm 객체에 대한 핸들을 자바스크립트 상호 운용성에 사용하기 위해 별도의 명시적 타입인 <code>JsReference</code>가 도입됐다.</p>
<p>자세한 내용은 <a href="https://kotlinlang.org/docs/wasm-js-interop.html">kotlin/wasm과 자바스크립트 간의 상호 운용성</a> 문서를 참고하길 바란다.</p>
<h3 id="kotlin-playground의-kotlinwasm">Kotlin Playground의 Kotlin/Wasm</h3>
<p>코틀린 플레이그라운드는 kotlin/wasm 대상을 지원한다. kotlin/wasm을 대상으로 하는 코틀린 코드의 작성, 실행 및 공유가 가능하다.
<a href="https://play.kotlinlang.org/#eyJ2ZXJzaW9uIjoiMS45LjAiLCJjb2RlIjoiaW1wb3J0IGtvdGxpbi50aW1lLkV4cGVyaW1lbnRhbFRpbWVcbmltcG9ydCBrb3RsaW4udGltZS5tZWFzdXJlVGltZVxuXG5mdW4gbWFpbigpIHtcbiAgICBwcmludGxuKFwiSGVsbG8gZnJvbSBLb3RsaW4vV2FzbSFcIilcblxuICAgIGNvbXB1dGVBY2soMywgMTApXG59XG5cbnRhaWxyZWMgZnVuIGFjayhtOiBJbnQsIG46IEludCk6IEludCA9IHdoZW4ge1xuICAgIG0gPT0gMCAtPiBuICsgMVxuICAgIG4gPT0gMCAtPiBhY2sobSAtIDEsIDEpXG4gICAgZWxzZSAtPiBhY2sobSAtIDEsIGFjayhtLCBuIC0gMSkpXG59XG5cbkBPcHRJbihFeHBlcmltZW50YWxUaW1lOjpjbGFzcylcbmZ1biBjb21wdXRlQWNrKG06IEludCwgbjogSW50KSB7XG4gICAgdmFyIHJlcyA9IDBcbiAgICB2YWwgdCA9IG1lYXN1cmVUaW1lIHtcbiAgICAgICAgcmVzID0gYWNrKG0sIG4pXG4gICAgfVxuICAgIHByaW50bG4oKVxuICAgIHByaW50bG4oXCJhY2soJG0sICRuKSA9ICR7cmVzfVwiKVxuICAgIHByaW50bG4oXCJkdXJhdGlvbjogJHt0LmluV2hvbGVOYW5vc2Vjb25kcyAvIDFlNn0gbXNcIilcbn0iLCJwbGF0Zm9ybSI6Indhc20iLCJhcmdzIjoiIn0=">이곳</a>에서 확인이 가능하다.</p>
<p>kotlin/wasm을 활성하기 위해서는 브라우저에서 실험 기능을 활성화해야 한다. 이러한 기능을 활성화하는 방법은 <a href="https://kotlinlang.org/docs/wasm-get-started.html#troubleshooting">이 문서</a>에 나와있다.</p>
<h2 id="kotlinjs">Kotlin/JS</h2>
<p>이번 kotlin/js 업데이트에는 gradle 플러그인의 지원 중단과 es6에 대한 실험적 지원을 포함한다.</p>
<h3 id="kotlinjs-gradle-플러그인-지원-중단">Kotlin/JS Gradle 플러그인 지원 중단</h3>
<p>코틀린 1.9.0부터 <code>kotlin-js</code> gradle 플러그인 지원이 중단되었다. 대신 <code>js()</code>와 함께 <code>kotlin-multiplatform</code> 플러그인을 사용하는 것을 권장한다.</p>
<p>kotlin/js gradle 플러그인은 <code>kotlin-multiplatform</code> 플러그인을 그대로 복제해서 본질적으로 동일하다. 이러한 중복으로 인해 코틀린팀의 혼란과 유지보수 부담이 증가됐다.</p>
<p>마이그레이션 지침은 <a href="https://kotlinlang.org/docs/multiplatform-compatibility-guide.html#migration-from-kotlin-js-gradle-plugin-to-kotlin-multiplatform-gradle-plugin">코틀린 멀티플랫폼 호환성 가이드</a>를 참고하길 바란다.</p>
<h3 id="외부-열거형-지원-중단">외부 열거형 지원 중단</h3>
<p>코틀린 1.9.0에서는 코틀린 외부에 존재할 수 없는 <code>entries</code>와 같은 정적 열거형 멤버와 관련된 문제로 인해 외부 열거형을 사용하지 않는 것을 권장한다. 대신 외부 <code>sealed class</code>를 객체 하위 클래스와 같이 사용하는 것을 권장한다.</p>
<pre><code class="language-kotlin">// 이전
external enum class ExternalEnum { A, B }

// 이후
external sealed class ExternalEnum {
    object A: ExternalEnum
    object B: ExternalEnum
}</code></pre>
<p>객체 하위 클래스가 있는 외부 <code>sealed class</code>로 전환하면 기본 메소드와 관련된 문제를 피하면서 외부 열거형과 유사한 기능을 제공할 수 있다.</p>
<p>상술한 바와 같이 코틀린 1.9.0부터 외부 열거형 사용은 권장되지 않으며, 호환성과 향후 유지보수를 위해 외부 <code>sealed class</code> 구현하도록 코드를 업데이트하는 것이 좋다.</p>
<h3 id="es6-클래스-및-모듈에-대한-실험적-지원">ES6 클래스 및 모듈에 대한 실험적 지원</h3>
<p>이번 장에서는 업데이트에서는 es6 모듈과 es6 클래스 생성에 대한 실험적 지원에 대해 소개한다.</p>
<ul>
<li>모듈은 코드베이스를 단순화하고 용이한 유지보수가 가능토록 한다.</li>
<li>클래스를 사용하여 oop 원리를 통합하여 깔끔하고 직관적인 코드를 만들 수 있다.</li>
</ul>
<p>이러한 기능을 사용하기 위해서는 아래와 같이 <code>build.gradle.kts</code>를 구성해주어야 한다.</p>
<pre><code class="language-kotlin">kotlin {
    js(IR) {
            useEsModules() // es6 모듈 활성화
            browser()
        }
    }

// es6 클래스 생성 사용
tasks.withType&lt;KotlinJsCompile&gt;().configureEach {
    kotlinOptions {
        useEsClasses = true
    }
}</code></pre>
<p>자세한 내용은 <a href="https://262.ecma-international.org/6.0/">ecma 스크립트 2015(es6) 문서</a>를 참고하길 바란다.</p>
<h3 id="js-프로덕션-배포의-기본-경로-변경">JS 프로덕션 배포의 기본 경로 변경</h3>
<p>코틀린 1.9.0 이전 버전에서는 배포 대상이 되는 디렉토리가 <code>build/distributions</code>였다. 그러나 이는 gradle 아카이브의 일반적인 디렉토리이기에 이 문제를 해결하기 위해 코틀린 1.9.0의 기본 배포 디렉토리를 <code>build/dist/&lt;targetName&gt;/&lt;binaryName&gt;</code>으로 변경했다.</p>
<p>예를 들어 <code>productionExecutable</code>는 원래 <code>build/distributions</code> 디렉토리에 존재했으나 <code>build/dist/js/productionExecutable</code> 디렉토리로 변경됐다.</p>
<p>만약, 빌드 결과를 사용하는 파이프라인(pipeline)이 이미 구축되어 있다면 해당 디렉토리를 업데이트를 필수적으로 해주어야 한다.</p>
<h3 id="stdlib-js에서-orgw3c-임포팅-제거">stdlib-js에서 org.w3c 임포팅 제거</h3>
<p>코틀린 1.9.0 이후로 <code>stdlib-js</code>는 더 이상 <code>org.w3c</code> 임포팅을 사용하지 않는다. 다만, 해당 임포팅들은 별도의 gradle 종속성으로 이관됐다. 코틀린 멀티플랫폼 gradle 플러그인을 <code>build.gradle.kts</code>에 추가하면 표준 라이브러리와 같이 임포팅은 프로젝트에 자동으로 포함된다.</p>
<p>필요한 조정은 자동으로 처리되기 때문에 수동 작업이나 마이그레이션은 하지 않아도 된다.</p>
<h2 id="gradle">Gradle</h2>
<p>코틀린 1.9.0은 신규 gradle 컴파일러 옵션을 제공한다.</p>
<h3 id="classpath-속성-제거">Classpath 속성 제거</h3>
<p>코틀린 1.7.0에서 <code>KotlinCompile</code>의 <code>classpath</code>에 대한 지원 중단에 대해 언급한 바가 있다. 지원 중단 수준은 1.8.0에서 <code>ERROR</code>로 상향 조정되었고, 이번 업데이트에서 <code>classpath</code> 속성을 제거했다. 이제 컴파일에 필요한 라이브러리 목록은 <code>libraries</code>에 입력해야 한다.</p>
<h3 id="신규-컴파일러-옵션">신규 컴파일러 옵션</h3>
<p>코틀린 gradle 플러그인은 opt-ins와 컴파일러 프로그레시브 모드를 위한 신규 속성을 제공한다.</p>
<ul>
<li><code>optIn</code> 속성을 사용해 <code>optIn.set(listOf(a, b, c))</code>와 같은 문자열 목록의 전달이 가능하다.</li>
<li><code>progressiveMode.set(true)</code>로 프로그레시브 모드를 활성화할 수 있다.</li>
</ul>
<h3 id="kotlinjvm을-위한-프로젝트-레벨의-컴파일러-옵션">Kotlin/JVM을 위한 프로젝트 레벨의 컴파일러 옵션</h3>
<p>코틀린 1.9.0부터 코틀린 <code>kotlin</code> 환경 설정 블록 내에서 <code>compilerOptions</code> 블록을 사용할 수 있다.</p>
<pre><code class="language-kotlin">kotlin {
    compilerOptions {
        jvmTarget.set(JVM.Target_11)
    }
}</code></pre>
<p><code>compilerOptions</code> 블록은 컴파일러 옵션을 구성하는 것을 간편화를 돕는다. 그러나 몇 가지 주의 사항이 있다.</p>
<ul>
<li>해당 설정은 프로젝트 구성에서만 동작한다.</li>
<li>안드로이드 블록의 경우 해당 블록은 아래와 같은 개체를 구성한다.<pre><code class="language-kotlin">android {
  kotlinOptions {}
}</code></pre>
</li>
<li><code>android.kotlinOptions</code>와 <code>kotlin.compilerOptions</code> 환경 설정 블록은 서로 덮어쓴다. 최종적으로 빌드 파일에서 두 설정 중 가장 마지막으로 설정된 블록이 적용(빌드 시, 빌드 파일을 순차적으로 읽어들이기 때문)된다.</li>
<li><code>moduleName</code>이 프로젝트 레벨에서 설정된 경우 컴파일러로 전달할 때 값이 변경될 가능성이 있다. 메인 컴파일은 예외이지만, 테스트 소스와 같이 다른 유형의 경우에는 코틀린 gradle 플러그인에 의해 <code>_test</code> 접미사가 붙는다.</li>
<li><code>tasks.withType&lt;KotlinJvmCompile&gt;().configureEach {}</code>(혹은 <code>tasks.named&lt;KotlinJvmCompile&gt;(&quot;compileKotlin&quot;) {}</code>) 내부의 구성은 <code>kotlin.compilerOptions</code>와 <code>ndroid.kotlinOptions</code>를 모두 덮어쓴다.</li>
</ul>
<h3 id="kotlinnative-모듈명을-위한-컴파일러-옵션">Kotlin/Native 모듈명을 위한 컴파일러 옵션</h3>
<p>kotlin/native <a href="https://kotlinlang.org/docs/compiler-reference.html#native-library-path-nl-path">모듈명</a> 컴파일러 옵션을 코틀린 gradle 플러그인에서 쉽게 사용할 수 있다.</p>
<p>해당 옵션은 컴파일 모듈명을 지정하며 objective-c로 내보낼 때 선언에 이름 접두사를 추가하는데 사용할 수도 있다.</p>
<p>gradle 빌드 파일의 <code>compilerOptions</code> 블록에서 모듈명을 직접 설정할 수 있다.</p>
<pre><code class="language-kotlin">tasks.named&lt;org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile&gt;(&quot;compileKotlinLinuxX64&quot;) {
    compilerOptions {
        moduleName.set(&quot;my-module-name&quot;)
    }
}</code></pre>
<h3 id="코틀린-공식-라이브러리를-위한-별도의-컴파일러-플러그인">코틀린 공식 라이브러리를 위한 별도의 컴파일러 플러그인</h3>
<p>코틀린 1.9.0에 공식 라이브러리를 위한 별도의 컴파일러 플러그인을 도입했다. 이전에는 컴파일러 플러그인이 해당 gradle 플러그인에 내장되어 있어, 컴파일러 플러그인이 gradle 빌드의 코틀린 런타임 버전보다 높은 코틀린 버전으로 컴파일된 경우에 호환성 문제가 발생할 수 있었다.</p>
<p>이제 컴파일러 플러그인이 별도의 종속성으로 추가되므로 더 이상 구 버전의 gradle과의 호환성 문제에 부딪힐 일은 없을 것이다. 새로운 접근법의 다른 장점은 새로운 컴파일러 플러그인을 <a href="https://bazel.build/?hl=ko">바젤</a>과 같이 타 빌드 시스템과 함께 사용이 가능하다는 점이다.</p>
<p>아래는 maven central에 게시 중인 신규 컴파일러 플러그인이다.</p>
<ul>
<li>kotlin-atomicfu-compiler-plugin</li>
<li>kotlin-allopen-compiler-plugin</li>
<li>kotlin-lombok-compiler-plugin</li>
<li>kotlin-noarg-compiler-plugin</li>
<li>kotlin-sam-with-receiver-compiler-plugin</li>
<li>kotlinx-serialization-compiler-plugin</li>
</ul>
<p>각 플러그인은 <code>-embeddable</code> 버전이 있다. 예를 들어, <code>kotlin-allopen-compiler-plugin-embeddable</code>은 <code>kotlin-compiler-embeddable</code> 아티팩트와 함께 동작하도록 설계됐다. 이것이 스크립트 아티팩트의 기본 옵션이다.</p>
<p>gradle은 이러한 플러그인들을 컴파일러 인자로 추가하여 기존 프로젝트를 수정할 필요가 없다.</p>
<h3 id="지원되는-최소-버전">지원되는 최소 버전</h3>
<p>코틀린 1.9.0부터 지원되는 최소 안드로이드 gradle 플러그인의 버전은 4.2.2이다.</p>
<p>코틀린 gradle 플러그인과 gradle 버전의 호환성에 관래서는 <a href="https://kotlinlang.org/docs/gradle-configure-project.html#apply-the-plugin">이 문서</a>를 참고하길 바란다.</p>
<h3 id="kapt는-gradle에서-eager-task-미생성">kapt는 gradle에서 eager task 미생성</h3>
<p>1.9.0 이전에는 <a href="https://kotlinlang.org/docs/kapt.html">kapt 컴파일러 플러그인</a>이 코틀린 컴파일 작업의 구성된 인스턴스를 요청하여 eager task(즉시 생성되는 작업)을 생성했다. 이러한 동작은 1.9.0에 수정되었으며 <code>build.gradle.kts</code>에 기본 환경 설정을 사용하는 경우 설정은 해당 변경 사항의 영향을 받지 않는다.</p>
<p>사용자 지정 환경 설정을 사용하면 설정에 악영향을 미친다. 예를 들어 gradle의 tasks api를 사용해 <code>KotlinJvmCompile</code> 작업을 수정한 경우 빌드 스크립트에서 <code>KaptGenerateStubs</code> 작업 또한 유사하게 수정해야 한다.</p>
<p>예를 들어 스크립트에 <code>KotlinJvmCompile</code> 작업에 대해 아래와 같은 설정이 있는 경우</p>
<pre><code class="language-kotlin">tasks.named&lt;KotlinJvmCompile&gt;(&quot;compileKotlin&quot;) {
    // 사용자 지정 설정
}</code></pre>
<p>이 경우 <code>KaptGenerateStubs</code> 작업의 일부로, 동일한 수정이 포함되도록 해야 한다.</p>
<pre><code class="language-kotlin">tasks.named&lt;KaptGenerateStubs&gt;(&quot;kaptGenerateStubs&quot;) {
    // 사용자 지정 설정
}</code></pre>
<p>자세한 내용은 <a href="https://youtrack.jetbrains.com/issue/KT-54468/KAPT-Gradle-plugin-causes-eager-task-creation?_gl=1*1vl3m5v*_ga*MTI1OTM2NDc3OC4xNjg2MTEyMzQ4*_ga_9J976DJZ68*MTY5MDg2NDAwMi4yMy4xLjE2OTA4NjQwMTIuNTAuMC4w&amp;_ga=2.92347221.919061315.1690762222-1259364778.1686112348">YouTrack ticket</a>을 참고하길 바란다.</p>
<h3 id="jvm-대상-검증-모드의-프로그래밍-방식-구성">JVM 대상 검증 모드의 프로그래밍 방식 구성</h3>
<p>코틀린 1.9.0 이전에는 자바와 코틀린 간의 jvm 대상 비호환성 탐지를 조정하는 방법은 프로젝트의 루트 디렉토리의 <code>gradle.properties</code>에서 <code>kotlin.jvm.target.validation.mode=ERROR</code>를 설정하는 방법 1가지 밖에 없었다.</p>
<p>1.9.0에서는 <code>build.gradle.kts</code>에서 task 레벨에서도 설정이 가능하다.</p>
<pre><code class="language-kotlin">tasks.named&lt;org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile&gt;(&quot;compileKotlin&quot;) {
    jvmTargetValidationMode.set(org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode.WARNING)
}</code></pre>
<h2 id="표준-라이브러리">표준 라이브러리</h2>
<p>코틀린 1.9.0에서는 표준 라이브러리에 대한 몇 가지 큰 개선 사항이 있다.</p>
<h3 id="개방형-범위--연산자-안정화">개방형 범위 ..&lt; 연산자 안정화</h3>
<p>개방형 범위 연산자인 <code>..&lt;</code>는 코틀린 1.7.20에 처음 도입되어 1.8.0에 안정화가 되었다. 1.9.0에서는 개방형 범위를 다루는 표준 라이브러리 api도 안정화됐다.</p>
<p><code>..&lt;</code> 연산자는 개방 범위가 선언된 경우 이해가 쉬워진다. 오히려 <code>until</code> 중위 함수를 사용하면 상한값이 포함된 것으로 오해하는 실수를 쉽게 범할 수 있다.</p>
<p>아래는 <code>until</code> 함수를 사용한 예시이다.</p>
<pre><code class="language-kotlin">fun main() {
    for (number in 2 until 10) {
        if (number % 2 == 0) {
            print(&quot;$number &quot;)
        }
    }
    // 2 4 6 8
}</code></pre>
<p>그리고 아래는 <code>..&lt;</code> 연산자를 사용한 예시이다.</p>
<pre><code class="language-kotlin">fun main() {
    for (number in 2..&lt;10) {
        if (number % 2 == 0) {
            print(&quot;$number &quot;)
        }
    }
    // 2 4 6 8
}</code></pre>
<p>인텔리제이 2023.1.1부터는 <code>..&lt;</code> 연산자의 사용 가능한 경우를 강조하는 새로운 코드 검사 기능이 제공되며 해당 연산자로 수행 가능한 작업에 대한 내용은 <a href="https://kotlinlang.org/docs/whatsnew1720.html#preview-of-the-operator-for-creating-open-ended-ranges">What&#39;s new in Kotlin 1.7.20</a>를 참고하길 바란다.</p>
<h3 id="시간-api-안정화">시간 API 안정화</h3>
<p>1.3.50부터 신규 시간 특정 api에 대해 미리 소개한 바가 있다. 해당 api의 지속 시간 부분은 1.6.0에서 안정화됐고, 1.9.0에서 남은 시간을 측정하는 api도 안정화됐다.</p>
<p>구 api에서는 <code>measureTimeMillis</code> 함수와 <code>measureNanoTime</code> 함수가 제공되고 있었다만, 이것들은 직관적인 사용이 가능한 것이 아니다. 둘 다 다른 단위의 시간을 측정하는 것은 틀림없지만, <code>measureTimeMillisis</code>가 시간을 측정하기 위해 wall clock(실제 시간을 측정하는 시계를 뜻하며, 현재 시간을 알아내거나 경과 시간을 측정하는데 사용되는 시계가 이에 해당)을 사용해 시간을 측정하고, <code>measureNanoTime</code>은 단조 시간 소스를 사용(사실 둘 다 명확하지 않다고 한다)한다.
신규 시간 api는 상술한 문제와 기타 문제를 해결하여 api를 좀 더 용이하게 사용할 수 있게 한다.\</p>
<p>신규 시간 api를 사용하면 좀 더 쉽게 아래의 동작을 수행할 수 있다.</p>
<ul>
<li>원하는 시간 단위로 단조 시간 소스를 사용하여 코드 실행에 소요된 시간을 측정</li>
<li>특정 시점 표시</li>
<li>두 시점을 서로 비교하여 차이점 탐색</li>
<li>특정 시점 이후 경과된 시간 확인</li>
<li>현재 시간이 특정 시점을 지났는지 확인</li>
</ul>
<h4 id="코드-실행-시간-측정">코드 실행 시간 측정</h4>
<p>코드 블록의 실행 시간을 측정하려면 <code>measureTime</code> 인라인 함수를 사용하면 된다.</p>
<p>코드 블록의 실행 시간을 측정하고 코드 블록의 결과를 리턴하려면 <code>measureTimedValue</code> 인라인 함수를 사용하면 된다.</p>
<p>기본적으로 두 함수 모두 단조 시간 소스를 사용한다. 실경과 시간 소스를 사용하고자 해도 가능하다. 예를 들어, 안드로이드에서는 기본 시간 소스인 <code>System.nanoTime()</code>이 단말기가 활성화된 시간 동안에만 계산을 한다. 디바이스가 deep sleep 모드에 들어가면 시간 계산이 중단되기 때문에 디바이스가 절전된 상태에서도 시간을 계산하려면 <code>SystemClock.elapsedRealtimeNanos()</code>를 사용하면 된다.</p>
<pre><code class="language-kotlin">object RealtimeMonotonicTimeSource : AbstractLongTimeSource(DurationUnit.NANOSECONDS) {
    override fun read(): Long = SystemClock.elapsedRealtimeNanos()
}</code></pre>
<h4 id="시간-차의-측정-및-표시">시간 차의 측정 및 표시</h4>
<p>특정 시점을 표시하려면 <code>TimeSource</code> 인터페이스와 <code>markNow()</code> 함수를 사용하여 <code>TimeMark</code>를 생성하면 된다. 동일한 시간 소스에서 <code>TimeMark</code> 사이의 차이를 측정하려면 뺄셈 연산자<code>-</code>를 사용하면 된다.</p>
<pre><code class="language-kotlin">import kotlin.time.*

fun main() {
    val timeSource = TimeSource.Monotonic
    val mark1 = timeSource.markNow()
    Thread.sleep(500) // 0.5초 대기
    val mark2 = timeSource.markNow()

    repeat(4) { n -&gt;
        val mark3 = timeSource.markNow()
        val elapsed1 = mark3 - mark1
        val elapsed2 = mark3 - mark2

        println(&quot;Measurement 1.${n + 1}: elapsed1=$elapsed1, elapsed2=$elapsed2, diff=${elapsed1 - elapsed2}&quot;)
    }
    // 시간 표시를 서로 비교하는 것도 가능하다.
    println(mark2 &gt; mark1) // mark2가 mark2보다 늦게 캡쳐됐기 때문에 true가 출력된다.
}</code></pre>
<p>특정 시점이 지났는지 혹은 시간이 초과됐는지 확인하려면 <code>hasPassNow()</code> 및 <code>hasNotPassNow()</code> 확장 함수를 사용하면 된다.</p>
<pre><code class="language-kotlin">import kotlin.time.*
import kotlin.time.Duration.Companion.seconds

fun main() {
    val timeSource = TimeSource.Monotonic
    val mark1 = timeSource.markNow()
    val fiveSeconds: Duration = 5.seconds
    val mark2 = mark1 + fiveSeconds

    // 아직 5초가 지나지 않은 시점
    println(mark2.hasPassedNow())
    // false

    // 6초 대기
    Thread.sleep(6_000)
    println(mark2.hasPassedNow())
    // true
}</code></pre>
<h4 id="kotlinnative-표준-라이브러리-안정화">Kotlin/Native 표준 라이브러리 안정화</h4>
<p>kotlin/native를 위한 표준 라이브러리가 지속적으로 업데이트됨에 따라 표준 라이브러리가 적절한 조건을 만족하는지 검토가 필요하다고 판단되어 기존의 공개 서명(라이브러리나 API의 외부에서 접근 가능한 함수, 클래스, 인터페이스 등의 구성 요소)을 주의깊게 검토했다. 각 서명에 대해 아래와 같은 사항을 고려했다.</p>
<ul>
<li>고유한 목적을 가진다.</li>
<li>타 코틀린 api와 일관성이 있다.</li>
<li>jvm에 대응하는 기능과 유사하게 동작한다.</li>
<li>추후 대비가 가능하다.</li>
</ul>
<p>이러한 사항을 바탕으로 아래와 같은 결정을 내렸다.</p>
<ul>
<li>안정화</li>
<li>실험적 기능</li>
<li><code>private</code>으로 표시</li>
<li>동작 수정</li>
<li>다른 위치로 이관</li>
<li>지원 중단</li>
<li>사용 중단</li>
</ul>
<p>기존이 서명이 다음과 같은 경우</p>
<ul>
<li>타 패키지로 이동되었다면, 해당 서명은 기존 패키지에는 여전히 존재하지만 <code>WARNING</code> 레벨로 격하된다. 인텔리제이에서 코드 검사 시 자동으로 대체하는 것이 좋다.</li>
<li>사용 중단된 경우 deprecation 레벨은 <code>WARNING</code>이 된다.</li>
<li>사용 중단으로 표시되면 당장 사용은 가능하지만, 추후 교체된다.</li>
</ul>
<p>여기에 검토 결과 전부는 아니지만, 몇 가지 강조점이 있다.</p>
<ul>
<li>atomics api 안정화</li>
<li><code>kotlinx.cinterop</code>의 실험적 지정했으며 해당 패키지의 사용을 위해 다른 opt-in이 필요하다.</li>
<li><code>Worker</code> 클래스 및 관련 api의 사용 중단</li>
<li><code>BitSet</code> 클래스 사용 중단</li>
<li><code>kotlin.native.internal</code> 패키지의 모든 <code>public</code> api를 <code>private</code>로 전환하거나 타 패키지로 이관</li>
</ul>
<h4 id="묵시적-c-언어-호환성의-안정성-보증">묵시적 C 언어 호환성의 안정성 보증</h4>
<p>양질의 api 유지하기 위해 <code>kotlinx.cinterop</code>을 실험적인 상태로 유지하기로 결정했다. <code>kotlinx.cinterop</code>의 검증은 철저히 진행됐지만, 아직 완벽하지 않은 부분이 남아있기 때문이다. 해당 api에 대해 아직은 프로젝트에서 사용하는 특정 부분에 한하여 사용하는 것을 권장한다. 이렇게 하면 api를 안정화하는 과정에서의 마이그레이션 작업이 더 용이해질 것이다.</p>
<p>C 스타일의 포인터와 외부 api를 사용하려면 <code>@OptIn(ExperimentalForeignApi)</code>으로 opt-in해야 하며, 그렇지 않으면 코드는 컴파일되지 않는다.</p>
<p>objective-c/swift 상호 운용성을 다루는 <code>kotlinx.cinterop</code>의 나머지 부분을 사용하려면 <code>@OptIn(BetaInteropApi)</code>에서 선택해야 한다. opt-in 없이 해당 api를 사용하려면 코드가 컴파일은 되지만 컴파일러가 해당 동작에 대해 명확한 설명과 함께 경고를 생성한다.</p>
<p>해당 어노테이션에 대한 자세한 정보는 <a href="https://github.com/JetBrains/kotlin/blob/56b729f1812733cb6a79673684c2fa5c4c6b3475/kotlin-native/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Annotations.kt"><code>Annotations.kt</code></a>의 소스 코드를 참고하길 바란다.</p>
<p>또한, 이번 검토에 대한 모든 변경 내용에 대한 자세한 내용은 <a href="https://youtrack.jetbrains.com/issue/KT-55765?_gl=1*vso515*_ga*MTI1OTM2NDc3OC4xNjg2MTEyMzQ4*_ga_9J976DJZ68*MTY5MDk1MDM2My4yOS4xLjE2OTA5NTA2NTYuNjAuMC4w&amp;_ga=2.86964688.919061315.1690762222-1259364778.1686112348">YouTrack 티켓</a>을 참고하길 바란다.</p>
<h3 id="volatile-어노테이션-안정화">@Volatile 어노테이션 안정화</h3>
<p><code>var</code> 속성에 <code>@Volatile</code> 어노테이션을 사용하면 백킹 필드가 표시되므로 필드에 대한 읽기/쓰기는 원자적인 상태가 되며 쓰기는 항상 다른 스레드에서 볼 수 있도록 처리된다.</p>
<p>1.8.20 이전에는 <code>kotlin.jvm.Volatile</code> 어노테이션을 공통 표준 라이브러리에서만 사용할 수 있었다. 다만, 해당 어노테이션은 jvm에서만 유효하고, 타 플랫폼에서 사용하면 무시되어 오류가 발생했다.</p>
<p>1.8.20에서는 실험적인 공통 어노테이션인 <code>kotlin.concurrent.Volatile</code>을 도입했다. 해당 어노테이션은 jvm과 kotlin/native에서 미리 확인이 가능하다.</p>
<p>1.9.0에서는 <code>kotlin.concurrent.Volatile</code>가 안정화됐다. 멀티플랫폼 프로젝트에서 <code>kotlin.jvm.Volatile</code>을 사용 중이라면, <code>kotlin.concurrent.Volatile</code>로 마이그레이션하는 것을 권장한다.</p>
<h3 id="regex-캡쳐-그룹을-이름으로-가져오는-신규-공통-함수">Regex 캡쳐 그룹을 이름으로 가져오는 신규 공통 함수</h3>
<p>1.9.0 이전에는 각 플랫폼 별로 정규 표현식 매치에서 정규 표현식 캡쳐 그룹을 얻기 위한 고유 확장 함수는 있었으나, 공통 함수는 존재하지 않았다. 1.8.0 이전에는 공통 함수를 가질 수 없었는데 이는 표준 라이브러리가 아직 jvm 1.6과 1.7을 지원했기 때문이다.</p>
<p>1.8.0부터 표준 라이브러리는 jvm 1.8로 컴파일 됐으며, 1.9.0에서는 정규 표현식 매치의 그룹 이름을 사용해 해당 그룹의 내용을 검색하는데 사용하는 표준 함수 <code>groups</code>가 추가됐다. <code>groups</code>는 특정 캡쳐 그룹에 속하는 정규 표현식 매치 결과에 접근하고자 할 때 유용하게 사용할 수 있다.</p>
<p>아래는 세 캡쳐 그룹(도시, 주, 지역 코드)을 포함하는 정규식의 예제이다. 해당 그룹 이름을 사용하여 일치하는 값에 액세스할 수 있다.</p>
<pre><code class="language-kotlin">fun main() {
    val regex = &quot;&quot;&quot;\b(?&lt;city&gt;[A-Za-z\s]+),\s(?&lt;state&gt;[A-Z]{2}):\s(?&lt;areaCode&gt;[0-9]{3})\b&quot;&quot;&quot;.toRegex()
    val input = &quot;Coordinates: Austin, TX: 123&quot;

    val match = regex.find(input)!!
    println(match.groups[&quot;city&quot;]?.value)
    // Austin
    println(match.groups[&quot;state&quot;]?.value)
    // TX
    println(match.groups[&quot;areaCode&quot;]?.value)
    // 123
}</code></pre>
<h3 id="상위-디렉토리-생성을-위한-새-경로-유틸리티">상위 디렉토리 생성을 위한 새 경로 유틸리티</h3>
<p>코틀린 1.9.0에는 신규 <code>createParentDirectories()</code> 확장 함수가 추가됐다. 해당 함수를 사용하여 필요한 모든 상위 디렉토리에서 파일을 생성할 수 있다. <code>createParentDirectories()</code>에 파일 경로를 제공하면 해당 경로에 상위 디렉토리의 존재 여부를 확인하고 이미 존재할 경우에는 아무 동작도 하지 않지만, 그렇지 않으면 자동으로 생성한다.</p>
<p><code>createParentDirectories()</code>는 파일을 복사할 때 유용하게 사용할 수 있다. 아래와 같이 <code>copyToRecursively()</code> 함수와 같이 사용 가능하다.</p>
<pre><code class="language-kotlin">sourcePath.copyToRecursively(
   destinationPath.createParentDirectories(),
   followLinks = false
)</code></pre>
<h3 id="16진수의-포맷-및-파싱이-가능한-신규-hexformat-클래스">16진수의 포맷 및 파싱이 가능한 신규 HexFormat 클래스</h3>
<p>신규 <code>HexFormat</code> 클래스와 관련 확장 함수들은 현재 실험적 기능으로, 사용하기 위해서는 <code>@OptIn(ExperimentalStdlibApi::class)</code> 어노테이션을 사용하거나 컴파일 인자로 <code>-opt-in=kotlin.ExperimentalStdlibApi</code>를 사용해야 한다.</p>
<p>1.9.0에서는 <code>HexFormat</code> 클래스와 관련된 확장 함수가 실험적 기능으로 제공된다. 해당 기능은 숫자 값과 16진수 문자열 간의 변환을 한다. 구체적으로, 확장 함수를 사용하여 16진수 문자열과 <code>ByteArray</code> 혹은 타 숫자 타입(<code>Int</code>, <code>Short</code>, <code>Long</code>) 간의 변환이 가능하다.</p>
<p>예를 들어 아래와 같이 사용할 수 있다.</p>
<pre><code class="language-kotlin">println(93.toHexString()) // &quot;0000005d&quot;</code></pre>
<p><code>HexFormat</code> 클래스에는 <code>HexFormat{}</code> 빌더로 구성 가능한 서식 옵션이 포함되어 있다.</p>
<p><code>ByteArray</code>와 함께 작업하려는 경우 아래와 같은 옵션이 존재하며, 이는 속성으로 구성이 가능하다.</p>
<table>
<thead>
<tr>
<th align="center">옵션</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>upperCase</code></td>
<td align="center">16진수 숫자의 대소문자 여부를 설정한다. 기본적으로 <code>upperCase = false</code> 즉, 소문자로 설정되어 있다.</td>
</tr>
<tr>
<td align="center"><code>bytes.bytesPerLine</code></td>
<td align="center">한 줄당 최대 바이트 수</td>
</tr>
<tr>
<td align="center"><code>bytes.bytesPerGroup</code></td>
<td align="center">그룹당 최대 바이트 수</td>
</tr>
<tr>
<td align="center"><code>bytes.bytesSeparator</code></td>
<td align="center">바이트 사이의 구분자로, 기본적으로 구분자는 없다.</td>
</tr>
<tr>
<td align="center"><code>bytes.bytesPrefix</code></td>
<td align="center">각 바이트의 두 자리 16진수 표현 바로 앞에 있는 문자열로, 기본적으로 아무것도 없다.</td>
</tr>
<tr>
<td align="center"><code>bytes.bytesSuffix</code></td>
<td align="center">각 바이트의 두 자리 16진수 표현 바로 다음에 오는 문자열로, 기본적으로 아무것도 없다.</td>
</tr>
</tbody></table>
<p>아래와 같이 사용할 수 있다.</p>
<pre><code class="language-kotlin">val macAddress = &quot;001b638445e6&quot;.hexToByteArray()

// HexFormat{} 빌더를 사용해 16진수 문자열을 콜론으로 구분
println(macAddress.toHexString(HexFormat { bytes.byteSeparator = &quot;:&quot; }))
// &quot;00:1b:63:84:45:e6&quot;

// HexFormat{} 빌더로 아래의 작업을 수행
// * 16진수 문자열을 대문자로 변환
// * 바이트를 쌍으로 그룹화
// * 점으로 구분
val threeGroupFormat = HexFormat { upperCase = true; bytes.bytesPerGroup = 2; bytes.groupSeparator = &quot;.&quot; }

println(macAddress.toHexString(threeGroupFormat))
// &quot;001B.6384.45E6&quot;</code></pre>
<p>숫자형 타입을 다루는 경우, 아래와 같은 옵션들이 존재하며 이들은 속성을 통해 구성 가능하다.</p>
<table>
<thead>
<tr>
<th align="center">옵션</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center"><code>number.prefix</code></td>
<td align="center">16진수 문자열의 접두사, 기본값은 없다.</td>
</tr>
<tr>
<td align="center"><code>number.suffix</code></td>
<td align="center">16진수 문자열의 접미사, 기본값은 없다.</td>
</tr>
<tr>
<td align="center"><code>number.removeLeadingZeros</code></td>
<td align="center">16진수 문자열에서 선행하는 0의 제거 여부, 기본적으로 <code>number.removeLeadingZeros = false</code> 즉, 제거하지 않는다.</td>
</tr>
</tbody></table>
<p>아래와 같이 사용 가능하다.</p>
<pre><code class="language-kotlin">// HexFormat{} 빌더를 사용해 접두사가 &quot;0x&quot;인 16진수 구문을 해석
println(&quot;0x3a&quot;.hexToInt(HexFormat { number.prefix = &quot;0x&quot; })) // &quot;58&quot;</code></pre>
<h2 id="문서-업데이트">문서 업데이트</h2>
<p>코틀린 문서에 몇 가지 큰 수정이 있었다.</p>
<ul>
<li><a href="https://kotlinlang.org/docs/kotlin-tour-welcome.html">코틀린 투어</a> - 이론과 실습을 겸비한 장으로 코틀린 언어의 기초를 배울 수 있다.</li>
<li><a href="https://kotlinlang.org/docs/multiplatform-android-layout.html">안드로이드 소스 세트 레이아웃</a> - 신규 안드로이드 소스 세트 레이아웃에 대해 알아보자.</li>
<li><a href="https://kotlinlang.org/docs/multiplatform-compatibility-guide.html">코틀린 멀티플랫폼 호환성 가이드</a> - 코틀린 멀티플랫폼으로 프로젝트를 개발하는 동안 직면할 수 있는 호환되지 않는 변경 사항 가이드</li>
<li><a href="https://kotlinlang.org/docs/wasm-overview.html">코틀린 Wasm</a> - 코틀린 wasm에 대해 알아보고 코틀린 멀티플랫폼 프로젝트에서 사용 가능한 방법을 알아보자.</li>
<li><a href="https://kotlinlang.org/docs/wasm-libraries.html">코틀린 Wasm 프로젝트에 코틀린 라이브러리 의존성 추가</a> - 코틀린 wasm에서 지원되는 코틀린 라이브러리에 대해 알아보자.</li>
</ul>
<h2 id="코틀린-190-설치">코틀린 1.9.0 설치</h2>
<h3 id="버전-확인">버전 확인</h3>
<p>인텔리제이 2022.3.3 및 2023.1.1에서는 코틀린 플러그인을 자동으로 1.9.0으로 업데이트하는 것을 제안한다. 2023.2에서는 코틀린 1.9.0 플러그인이 자동으로 포함될 예정이다.</p>
<p>안드로이드 스튜디오 Giraffe(223)와 Hedgehog(231)은 곧 출시될 릴리즈에서 코틀린 1.9.0을 지원한다.</p>
<p>신규 command-line 컴파일러는 <a href="https://github.com/JetBrains/kotlin/releases/tag/v1.9.0">github release</a>에서 다운로드할 수 있다.</p>
<h3 id="gradle-설정-구성">Gradle 설정 구성</h3>
<p>코틀린 아티팩트와 종속성을 다운로드하려면 <code>setting.gradle(.kts)</code>를 업데이트하여 maven central 저장소를 사용해야 한다.</p>
<pre><code class="language-kotlin">pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}</code></pre>
<p>저장소가 지정되지 않은 경우 gradle은 현재 서비스 종료 상태인 jcenter 저장소를 사용하게 되고, 이는 코틀린 아티팩트에 관련하여 문제를 일으킬 수 있다.</p>
<h2 id="코틀린-190-호환성-가이드">코틀린 1.9.0 호환성 가이드</h2>
<p>코틀린 1.9.0은 <a href="https://kotlinlang.org/docs/kotlin-evolution.html#feature-releases-and-incremental-releases">기능 업데이트</a>이기 때문에, 이전 버전으로 작성된 코드와 호환되지 않을 수 있다. 코틀린 1.9.0에 대한 자세한 변경 사항은 <a href="https://kotlinlang.org/docs/compatibility-guide-19.html">코틀린 1.9.0 호환성 가이드</a>에서 확인 가능하다.</p>
<h2 id="원문">원문</h2>
<ul>
<li><a href="https://kotlinlang.org/docs/whatsnew19.html">What&#39;s new in Kotlin 1.9.0</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS CLI 설치]]></title>
            <link>https://velog.io/@p-intelligence/AWS-CLI-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@p-intelligence/AWS-CLI-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Thu, 29 Jun 2023 07:19:57 GMT</pubDate>
            <description><![CDATA[<h2 id="aws-cli란-무엇인가">AWS CLI란 무엇인가</h2>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/939caf0f-a345-46ea-b8fe-32ac2f00fac4/image.png" alt="AWS CLI 그림">
AWS CLI는 CLI Shell 명령어를 사용하여 AWS 서비스를 관리할 수 있는 <a href="https://github.com/aws/aws-cli">오픈소스</a> 도구이다.
AWS CLI를 통해 터미널에서 브라우저로 AWS 콘솔에서 작업하는 것과 동일하게 기능을 구현할 수 있다.<br>또한, AWS CLI를 다루는 것이 능숙해진다면 AWS 서비스의 Public API에 엑세스가 가능하며 리소스를 관리하거나 기능을 구현하는 Shell Script를 작성하여 작업을 자동화할 수 있다.   </p>
<p>AWS CLI의 명령 구조는 아래와 같다.</p>
<pre><code class="language-bash">$ aws &lt;command&gt; &lt;subcommand&gt; &lt;옵션이나 파라미터&gt;</code></pre>
<p>CLI에서 도움말 설명서를 보려면 아래의 명령어 중 하나를 입력하면 된다.<br>각각 AWS CLI, AWS CLI 명령어, AWS CLI 하위 명령어에 대한 도움말 설명서이다.</p>
<pre><code class="language-bash">$ aws help
$ aws &lt;command&gt; help
$ aws &lt;command&gt; &lt;subcommand&gt; help</code></pre>
<p>명령어에 대한 디버깅을 하고 싶으면 명령어를 아래와 같은 형식으로 작성한다.</p>
<pre><code class="language-bash">$ aws --debug &lt;command&gt; &lt;subcommand&gt; &lt;옵션이나 파라미터&gt;</code></pre>
<h2 id="aws-iam-계정-만들기">AWS IAM 계정 만들기</h2>
<p>이 장에서는 AWS CLI를 다루기 위해 필요한 IAM 계정 생성에 대한 내용을 다룬다.
IAM 계정과 엑세스 키를 가지고 있다면 이 장은 건너뛰어도 된다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/c6b71553-7920-4200-bc02-c611a3766df7/image.png" alt="IAM 대시보드"></p>
<p>AWS 콘솔에서 IAM 서비스에 들어간다.
위의 그림과 같이 IAM 대시보드에서 좌측의 메뉴에서 사용자로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/7dcfbf23-872c-4ad0-913e-fb868273da0b/image.png" alt="사용자"></p>
<p>사용자 메뉴로 이동해주었다면 사용자 추가를 눌러 IAM 계정을 추가해주어야 한다.
root 계정일 경우, 사용자 추가를 할 수 있지만 root 계정 이외에 IAM 계정으로 로그인하고 있다면 사용자 추가 권한이 없다면 이 작업을 할 수 없다는 것을 알아두어야 한다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/20a5a7ce-9ec9-49e2-86a6-f413ae3308c2/image.png" alt="사용자 추가1"></p>
<p>사용자 추가를 눌렀을 때 총 5단계를 거쳐야 사용자가 추가되는데 우선 1번째 단계이다.
사용자의 이름과 AWS 엑세스 유형을 선택하는 단계인데 여기서 그림 2와 같이 프로그래밍 방식 엑세스를 반드시 선택해주어야 한다.
이것을 선택해주어야 후에 엑세스 키가 발급되고 이를 통해 AWS CLI로 작업이 가능하다.
선택해주었다면 다음 단계로 넘어간다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/59919719-cd1a-4880-9db0-895edd0b5a5a/image.png" alt="사용자 추가2">
2단계는 권한 설정이다.
현재 생성 중인 계정이 AWS 내에서 어떤 서비스에 접근이 가능하며 얼만큼의 제어가 가능한지 지정해주는 단계이다.
필자는 Admin 권한을 넣어주었으나 원한다면 따로 권한 설정을 하는 것도 좋다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/a2d15c6a-a348-4303-9e95-c54c1e0d61d7/image.png" alt="사용자 추가3"></p>
<p>사용자의 태그를 지정하는 단계이다.
현재는 크게 중요한 부분은 아니기 때문에 설정하지 않고 다음으로 넘어가도 된다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/1e04f8a6-3030-4780-801a-ae82631adfae/image.png" alt="사용자 추가4"></p>
<p>생성 직전 검토 단계이다. 1~3단계까지 설정한 것을 검토하는데 이때 AWS 엑세스 유형에 프로그래밍 방식 엑세스가 반드시 있어야 한다.
그렇지 않다면 1단계로 돌아가 프로그래밍 방식 엑세스에 체크해주어야 한다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/1aa662f6-58a2-4fc0-bde3-7e8932036e68/image.png" alt="사용자 추가5"></p>
<p>이제 마지막 단계이다.
<code>.csv</code> 다운로드를 눌러 <code>.csv</code> 파일을 다운받는다.
이 파일에 AWS CLI나 AWS SDK로 AWS 서비스에 접근할 수 있는 엑세스 키가 있기 때문에 반드시 다운받아야 한다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/a4f67718-fa3f-4b19-b3ff-62ecd57d198c/image.png" alt="csv"></p>
<p>다운받은 <code>.csv</code> 파일을 열면 그림 8과 같이 사용자 이름, 엑세스 키 ID, 비밀 엑세스 키 등이 적혀있다.
이 파일에서 필요한 것은 엑세스 키 ID와 비밀 엑세스 키이다.
또한 이러한 엑세스 정보는 보안과 직결되므로 외부에 노출되지 않도록 개인이 잘 보관해야 한다.</p>
<h2 id="aws-cli-설치">AWS CLI 설치</h2>
<h3 id="windows에-설치">Windows에 설치</h3>
<p>OS는 Windows 10으로 하여 작업했으니 Windows 11과는 다소 차이가 있을 수 있다.
우선 <a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html">이 페이지</a>에서 AWS CLI2 설치파일을 다운받는다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/b4c831fb-af0a-4b4e-98b3-541a6bd7383d/image.png" alt="버전 확인"></p>
<p>설치가 완료되었다면 정상적으로 설치되었는지 확인하기 위해 Command Prompt나 Power Shell 등 CLI를 열어 AWS CLI의 버전을 확인한다.
정상적으로 설치가 되었다면 위의 그림과 같이 버전에 관한 정보를 확인할 수 있다.</p>
<pre><code class="language-bash">&gt; aws --version</code></pre>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/25a87d5a-79a1-4786-9aa6-f50567dd84fb/image.png" alt="configure"></p>
<p>AWS CLI를 사용하기 위해 명령어 <code>aws configure</code>를 입력하여 엑세스 키의 ID와 비밀 엑세스 키를 붙여넣고 작업할 리전과 출력 형식을 입력해준다.
출력 형식은 json, table, text, yaml, yaml-stream이 있다.
그 후, 아래의 명령어로 AWS CLI로 현재 계정에서 EC2로 접근 가능한 리전을 확인한다.
명령어가 위의 그림과 같이 결과를 잘 뱉으면 현재 계정으로 AWS CLI를 사용할 수 있다는 의미이다.</p>
<pre><code class="language-bash">&gt; aws ec2 describe-regions</code></pre>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/b588fb04-3b9f-4a6e-b9dd-7d815944436c/image.png" alt="configure edit"></p>
<p>설정을 변경하고 싶다면 명령어 <code>aws configure</code> 명령어를 입력하여 설정을 변경하거나 위의 그림과 같이 홈 디렉토리에 있는 <code>.aws</code> 디렉토리에서 <code>config</code> 파일과 <code>credentials</code> 파일을 수정해서 설정을 변경할 수 있다.
이렇게 Windows 환경에서 AWS CLI를 사용할 준비가 끝났다.</p>
<h3 id="linux에-설치">Linux에 설치</h3>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/7fecddac-e90a-47be-b296-3bccc2d21417/image.png" alt="awscli 압축 파일 download"></p>
<p>아래의 명령어로 AWS CLI 압축 파일을 다운받는다.
그 후, 압축 해제 명령어를 통해 다운받은 압축 파일의 압축을 해제한다.
압축 해제 명령어가 없다면 설치를 받아야 한다.</p>
<pre><code class="language-bash">$ curl &quot;https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip&quot; -o &quot;awscliv2.zip&quot;
$ unzip awscliv2.zip</code></pre>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/f08ff707-1c1a-406c-b0f6-f7298e9954bd/image.png" alt="권한 부여 및 심볼 링크 생성"></p>
<p>아래의 명령어를 통해 설치 프로그램을 실행하는 동시에 권한을 부여한다.
그럼 기본적으로 설치는 <code>/usr/local/aws-cli</code>에 되며 <code>/usr/local/bin</code>에 심볼 링크가 생성된다.
설치 프로그램을 실행 후, 실행한 디렉토리를 <code>-i</code> 옵션으로 복사할 디렉토리와 <code>-b</code> 옵션으로 심볼릭 링크로 연결해준다.
다음 명령어는 AWS CLI를 업데이트하는 명령어인데, 기존 심볼 링크 및 설치 관리자 정보를 추가하여 <code>--update</code> 파라미터를 포함한 install 명령을 구성한다.
마지막으로 AWS CLI 버전을 확인했을 때 위의 그림와 같이 버전 정보가 확인된다면 정상적인 설치가 완료된 것이다.</p>
<pre><code class="language-bash">$ sudo ./aws/install
$ sudo ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update
$ ls -l /usr/local/bin/aws
$ aws --version</code></pre>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/c5dd2c94-3b3d-4eb8-b343-87eba52b20b5/image.png" alt="configure"></p>
<p>엑세스 정보 설정은 Windows와 마찬가지로 <code>aws configure</code> 명령어로 진행한다. 엑세스 정보 설정 이후, 아래의 명령어로 EC2에 접근 가능한 리전을 확인한다. 결과가 잘 나오면 AWS CLI를 정상적으로 사용할 수 있다.</p>
<pre><code class="language-bash">$ aws ec2 describe-regions</code></pre>
<h3 id="macos에-설치">macOS에 설치</h3>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/748ce904-3780-4f36-913a-43f95884a032/image.png" alt="brew install"></p>
<p>macOS는 homebrew를 사용하면 명령어로 프로그램을 간단히 설치할 수 있다.
homebrew에서 AWS CLI를 설치하는 명령어는 아래와 같다.</p>
<pre><code class="language-bash">$ brew install awscli</code></pre>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/418576b8-7446-4ce4-b29c-0d87f1221d22/image.png" alt="버전 확인"></p>
<p>설치 후, 경로와 버전을 확인하면 위의 그림과 같은 결과가 나오는 것을 확인할 수 있다.
엑세스 정보 설정은 <code>aws configure</code> 명령어를 통해 설정하면 된다.</p>
<h2 id="그-외에-aws-cli를-다루는-방법">그 외에 AWS CLI를 다루는 방법</h2>
<p>이번 항목에서는 위에서 소개했던 방식 이외에 AWS CLI를 다루는 방식들을 소개한다.</p>
<h3 id="cloudshell">CloudShell</h3>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/cb587ff3-fe55-4a62-aedc-3aa9510a375b/image.png" alt="Cloud Shell"></p>
<p>CloudShell은 웹브라우저로 AWS 콘솔에 접근하여 직접 사용할 수 있다.
CloudShell은 AWS CLI2가 세팅되어 있는 상태라 별 다른 설정 없이 AWS CLI를 다룰 수 있으며 Python과 Node 런타임, Bash, PowerShell, git, ECS CLI, jq, npm, pip 등이 포함되어 있으며 향후 더 많은 기능이 제공될 예정이다.
CloudShell을 지원하는 리전은 <a href="https://docs.aws.amazon.com/ko_kr/cloudshell/latest/userguide/supported-aws-regions.html">이 페이지</a>에서 확인하면 된다.</p>
<p>이 외에 CloudShell에 대해서는 아래와 같이 간단히 정리해두었다.</p>
<blockquote>
<p><strong>스토리지</strong>: <code>$HOME</code>에 저장된 파일은 Cloud Shell 호출 간에도 유지되지만 그 이외에 설치한 SW는 유지되지 않으며 용량은 리전당 1GB로 제한된다.   </p>
<p><strong>요금</strong>: 리전 당 최대 10개의 Shell을 동시에 사용했을 때 무료로 사용이 가능하며 Cloud Shell에서 AWS CLI로 작업을 하여도 Cloud Shell은 과금이 되지 않는다.  </p>
<p><strong>시간 초과 및 지속성</strong>: 20분 동안 사용하지 않으면 세션이 만료된다.    </p>
<p><strong>네트워크 엑세스</strong>: 세션은 인터넷 아웃바운드 연결을 생성이 가능하지만, 인바운드 연결은 불가능하며 세션은 private VPC 서브넷 내의 리소스에 접근할 수 없지만 이 기능은 단기 로드맵에 존재한다.   </p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/3daabb20-7859-41ad-a294-844d4c1f4fcf/image.png" alt="AWS Console"></p>
<p>Cloud Shell을 사용하는 방법은 매우 간단하다.
AWS 콘솔에 접속해서 Cloud Shell을 지원하는 리전에서 위의 그림와 같이 우측 상단 Cloud Shell 아이콘을 클릭하면 된다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/5e050730-0b01-4307-81ba-775454044a93/image.png" alt="AWS Cloud Shell"></p>
<p>Cloud Shell는 AWS CLI가 기본으로 깔려있기 때문에 따로 세팅해줄 것은 거의 없다고 보면 된다.</p>
<h3 id="aws-shell">AWS Shell</h3>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/9ba97909-b970-436a-98b3-ec2a30721427/image.png" alt="AWS Shell">
AWS Shell은 AWS CLI 셸 프로그램으로 AWS CLI를 사용하는 사용자에게 도움되는 자동 완성, OS Shell 명령 실행, 실행한 명령의 결과를 text 편집기로 내보내기 등 편리한 기능이 탑재되어 있다.
AWS CLI만을 사용하면 간혹 옵션명이 헷갈리거나 기억나지 않는 경우가 있는데 AWS Shell을 사용하면 이러한 경우를 대폭 줄일 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/470c011a-3176-4a41-b83c-6a939b72be04/image.png" alt="install pip"></p>
<p>AWS Shell을 설치하기 위해서는 python과 pip가 필요한데 pip가 없는 사람은 설치를 해준다.
python이 없으면 마찬가지로 python을 설치해준다.
이미 설치되어 있는 사람들은 이곳을 무시하고 다음으로 넘어가면 된다.</p>
<pre><code class="language-bash">$ sudo apt install python3-pip -y</code></pre>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/f0c28d96-d6d2-412b-a627-57cf377a30b4/image.png" alt="aws-shell install"></p>
<p>pip를 통해 AWS Shell을 설치해준다.</p>
<pre><code class="language-bash">$ sudo pip install aws-shell</code></pre>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/d998e243-a62f-40ee-b0aa-365ad0183926/image.png" alt="aws-shell 실행"></p>
<p>설치가 완료되면 AWS Shell을 실행시켜준다.
실행하는 명령어는 <code>aws-shell</code>이다.
보통 터미널에서 AWS CLI를 사용하면 앞에 무조건 aws를 붙여야 하는데 AWS Shell에서는 앞에 aws를 붙일 필요가 없다.
즉 AWS Shell에서는 명령어를 작성할 때 맨앞의 접두사인 <code>aws</code>를 빼고 <code>&lt;command&gt; &lt;subcommand&gt; &lt;옵션이나 파라미터&gt;</code>와 같이 명령어를 작성할 수 있다. 또한 자동 완성 기능 또한 편리하기에 유용하다.
필자는 명령어가 정상적으로 동작하는지 확인하기 위해 명령어 하나를 실행시켜 보았다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/5b38cc1f-03c5-42e4-aee9-abdc4a5bd526/image.png" alt="명령어 동작 확인"></p>
<p>명령어는 잘 동작한다.
필자는 이미 계정 정보를 설정해두어서 잘 동작하는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/p-intelligence/post/7420ac05-5551-44f8-aae7-319e4905b64f/image.png" alt="aws-shell configure"></p>
<p>계정 정보의 설정을 하지 않고 AWS Shell만 설치한 사람은 위의 그림과 같이 AWS Shell 내에서 명령어 <code>configure</code>를 통해 설정이 가능하다.
AWS Shell에서 나가려면 <code>F10</code>을 누르면 나갈 수 있다.</p>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html">AWS docs - Installing or updating the latest version of the AWS CLI</a></li>
<li><a href="https://docs.aws.amazon.com/cloudshell/latest/userguide/welcome.html">AWS docs - What is AWS CloudShell?</a></li>
<li><a href="https://github.com/awslabs/aws-shell">Github Repo - aws-shell</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>