【レポート+やってみた】projen – a CDK for software project configuration #CDK Day

先日のCDK Dayというイベントで、TypeScriptの構成ファイルを統合・継続管理できるprojenというプロジェクトが発表されていたので紹介します。前半で発表のレポート、後半では実際に動かした内容を記載しています。
2020.10.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

CX事業本部の佐藤智樹です。

先日(9月30日)にCDK Dayという世界中の開発者がCDKに関連する内容を語るコミュニティイベントがありました。そこで興味深い発表があったので紹介します。

TypeScriptで新規開発する際毎度作成が必要になる package.json、 tsconfig.jsonなどの構成ファイルを統合・継続管理できるツールの発表でした。

一部例を書くと、以下のような.projenrc.jsファイルを用意しておくだけで、package.jsonでAWS CDKのモジュールごとにversionを書く必要がなくなるそうです。

.projenrc.js

const { AwsCdkTypeScriptApp } = require('projen');

const project = new AwsCdkTypeScriptApp({
  cdkVersion: "1.63.0",
  name: "cdk"
});

project.synth();

AWS CDK更新に合わせてpackeage.jsonを毎度更新している方や新しいアプリを作成する際に毎回前のプロジェクトの設定ファイルをコピーしている方など、設定ファイルやパッケージの管理に悩んでる方へ今後参考になるかと思います。

まだ実験的なプロジェクトなので、試す際は破壊的変更があっても問題ない検証などで使うことをおすすめします。

前半部分は発表内容について記載し、後半は実際に試してみた内容を記載します。 適宜意訳している箇所がありますが、Google翻訳をベースに翻訳しています。

発表内容

発表者:Elad Ben-Israel (AWS CDKチームのコアメンバー)

動画:51:05頃~

概要

Modern real-world software projects require a growing set of tools: dependency management, ignore files, compilers, linters, testing tools, workflows, IDE integration, changelog, packaging, publishing, github actions. Each tool has with its own configuration files committed into the repo.

Wouldn't it be nice if we could model our projects through rich object-oriented APIs and have it synthesize all these config files for us?

projen - a CDK for software project configuration

意訳:

モダンなソフトウェアの開発では依存関係管理、ignoreファイル、コンパイラ、リンタ、テストツール、ワークフロー、IDE設定、変更履歴、パッケージング、CI/CDが使われます。それらの設定はそれぞれ独自の設定ファイルを持っています。

オブジェクト指向APIを使ってモデル化することで、それらの設定を統合することができたら素晴らしいと思いませんか?

背景

  • 高品質なソフトウェアを開発したい場合のハードルが日々上がっています
  • 例えばプロジェクトを開始する際、TypeScriptだとnpmやpackage.jsonが必要になります
  • その他にもガバレッジツールやユニットテスト、バージョン管理、CIビルド、セキュリティパッチライセンス、npm workflow scriptなどの設定が必要です。
  • 私は新しいプロジェクトに取り組む時、最近取り掛かっていたプロジェクトから設定ファイルを取得してから実装に取り掛かります。

  • Templating/Scaffolding/Generatorツールがあります。
  • yeomanやcreate-react-appなどです。
  • これらはk8s上でCDKを開始する際に問題があります。
  • 作成したアプリのリポジトリをクローンすると正しくない構成が大量に発生します。
  • 各構成ファイルは、生成ツールごとに独自のスタイルや形式があるからです。
  • これはソフトウェアではLeaky Abstractionと呼ばれています。

※参考: 研究テーマ:Leaky Abstraction に関するケーススタディ

  • projenでは上記の問題にCDKアプローチを採用します。
  • 現在はJS/TSで使用できます。将来的にはjsiiの言語のいずれかでも使用できるようにする予定です。

以降は、実際にprojen使ったデモが行われました。今回は自分の方で実際に使用して確認した内容を以降の章で記載します。

projen使ってみた

今回使用するコマンドの元リポジトリ

まずは動画と同じように以下のコマンドを実行します。

$ npx projen new
npx: 64個のパッケージを18.155秒でインストールしました。
projen new PROJECT-TYPE [OPTIONS]

Creates a new projen project

コマンド:
  projen new awscdk-app-ts     AWS CDK app in TypeScript.
  projen new awscdk-construct  AWS CDK construct library project.
  projen new cdk8s-construct   CDK8s construct library project.
  projen new jsii              Multi-language jsii library project.
  projen new node              Node.js project.
  projen new project           Base project.
  projen new typescript        TypeScript project.
  projen new typescript-app    TypeScript app.

オプション:
  --version  バージョンを表示                                                                        [真偽]
  --help     ヘルプを表示                                                                            [真偽]
  --synth    Synthesize after creating .projenrc.js                               [真偽] [デフォルト: true]
オプションではない引数が 0 個では不足しています。少なくとも 1 個の引数が必要です:

コマンドの結果を見ると引数の不足で失敗しています。CDK用の構成は「projen new awscdk-app-ts」で実行できるようです。

本記事でも動画と同様に、「projen new awscdk-app-ts」を実行します。 実行のために一旦作業用のディレクトリを作成してそちらに移動します。

$ mkdir my-project && cd my-project

プロジェクト用のファイルを作成します。一旦動画と同じように.projenファイルを生成します。

$ npx projen new awscdk-app-ts --no-synth
npx: 64個のパッケージを4.647秒でインストールしました。
? Created .projenrc.js for AwsCdkTypeScriptApp

すると以下のファイルが生成されます。

.projen.rc

const { AwsCdkTypeScriptApp } = require('projen');

const project = new AwsCdkTypeScriptApp({
  cdkVersion: "1.63.0",
  name: "my-project"
});

project.synth();

上記のファイルがCDKやpackage.jsonファイルなどを統合して管理するファイルになります。次は構成ファイルを生成してみます。

$ npx projen
npx: 64個のパッケージを4.513秒でインストールしました。
? Synthesizing project...
yarn install v1.21.1
info No lockfile found.
[1/4] ?  Resolving packages...
[2/4] ?  Fetching packages...
[3/4] ?  Linking dependencies...
[4/4] ?  Building fresh packages...
success Saved lockfile.
✨  Done in 32.87s.
? eslint: * => ^7.10.0
? eslint-import-resolver-node: * => ^0.3.4
? eslint-import-resolver-typescript: * => ^2.3.0
? eslint-plugin-import: * => ^2.22.1
? json-schema: * => ^0.2.5
? ts-node: * => ^9.0.0
? Synthesis complete

----------------------------------------------------------------------------------------------------
Commands ("yarn run COMMAND"):
  
BUILD
compile          Only compile
watch            Watch & compile in the background
build            Full release build (test+compile)
synth            Synthesizes your cdk app into cdk.out (part of "yarn build")
  
TEST
test             Run tests
test:watch       Run jest in watch mode
eslint           Runs eslint against the codebase
  
RELEASE
bump             Commits a bump to the package version based on conventional commits
release          Bumps version & push to master
deploy           Deploys your cdk app to the AWS cloud
  
MAINTAIN
projen           Synthesize project configuration from .projenrc.js
projen:upgrade   upgrades projen to the latest version
  
MISC
start            Shows this menu
  
Tips:
? Install Mergify in your GitHub repository to enable automatic merges of approved PRs
? Set `autoUpgradeSecret` to enable automatic projen upgrade pull requests
? The VSCode jest extension watches in the background and shows inline test results

すると、以下のようにpackage.jsonなどが生成されます。srcにスタックの構成が入ります。

$ tree -L 2 -I node_modules
.
├── LICENSE
├── cdk.json
├── package.json
├── src
│   └── main.ts
├── test
│   └── main.test.ts
├── tsconfig.jest.json
├── tsconfig.json
├── version.json
└── yarn.lock

今後これらの構成ファイルは、.projen.rcファイル経由で操作することになります。 例えば、CDKのversionを変更したい場合は以下のように.projen.rcファイルを編集します。

const { AwsCdkTypeScriptApp } = require('projen');

const project = new AwsCdkTypeScriptApp({
  cdkVersion: "1.64.0",
  name: "my-project",
});

project.synth();

再度projenコマンドを実行するとcdkのversion更新がpackage.jsonに追加されることを確認できます。 (動画のようにcdkDependeciesで「@aws-cdk/aws-s3」のモジュールを追加することを試みたのですが失敗しました。問題が解決できれば今後追記します。)

$ npx peojen

所感

まだアルファ版なのでうまく動かない部分もあったのですが、課題で話されているようなことは良く起きているので今後の動向に注目したいと思い記事にしました。

自分自身も検証でCDKを動かす時に別のアプリから構成を流用するところから始まることが多いので、このように管理が統合でき継続的なアップデートもできるツールは魅力的だと感じます。

後、今回紹介し切れていないですが、package.jsonを手動で変更するとCIでこける設定なども入っています。気になった方はリポジトリのReadMeを参照してください。

今後安定して動くようになったら本格的に記事にしたいと思います。