公開済みのChrome Extensionのタイトルを変更する

公開済みのChrome Extensionのタイトルを変更する方法について紹介します。

TL;DR

  • マニフェストファイルのnameを変更して、package.jsonのversionをあげて審査に出せばOK

github.com

経緯

ChromeSnack Timeという便利な拡張を公開しているんですが、名前からして何の拡張なのか分かりづらいというフィードバックがありました。
そのため、Snack Time というプロダクト名だけでなく、 Snack Time - Online Timerのようにタイマーであることを明記しようとしました。

タイトルを変更する

Chrome Extensionのタイトルは、Developer DashboardのStore Listingで編集はできませんが、どこから参照しているのかが分かります。

Title from package と書いてあり、審査に出したパッケージの何らかのファイルを参照していることが分かります。
結論をいえば、マニフェストファイルのnameを参照しているので、ここを変更すれば良いです。

公式のマニフェストについてのページにも分かりづらいですが、書いてありますね。

developer.chrome.com

私が開発しているChrome ExtensionはCRXJSを使っていて、Viteの設定ファイルから分離していないのでvite.config.tsを直接書き換えます。

 const manifest = defineManifest(async (env) => ({
   manifest_version: 3,
-  name: `${env.mode === "development" ? "[DEV] " : ""}Snack Time`,
+  name: `${env.mode === "development" ? "[DEV] " : ""}Snack Time - Online Timer`,
   version: version,
-  description: "This extension is a timer to help you keep your break time.",
+  description: "This extension is a timer on the website to help with timekeeping for meetings",
   permissions: ["activeTab", "scripting", "storage"],
   icons: {
     128: "images/icon.png",

あとは、package.jsonのversionをあげてアップロードし、審査が完了してリリースされればストアの表記が変更されます。

おわりに

今回は公開済みのChrome Extensionのタイトルを変更する内容について紹介しました。
そのうちストアの多言語化対応もやりたいので、実施するついでに紹介しますね。

テストでFactoryBotを使う理由・使わない理由

はじめに

先日、チームの若手エンジニアから「テストが成功しなくてデータがおかしい」という相談を受けました。
相談を受け一緒に調査を進めると、同じモデルに対してテストではFactoryBotでのデータ作成と、実際のアプリケーションでは作成ロジッククラスと作成ロジックが異なっていることが原因でした。

この問題をきっかけに、「FactoryBotをいつ使うべきか、いつ使うべきでないか」というテーマについて、その人に説明したことを共有していきます。

TL;DR

  • FactoryBotは単純なテストデータの作成に使う
  • 複雑な作成・更新ロジックが絡む場合は、専用のクラスやメソッドを使用する
  • FactoryBotで作成・更新ロジックを再実装しない

      # 悪い例: FactoryBotでも作成・更新ロジックを「再実装」
      FactoryBot.define do
        factory :order do
          after(:build) { |order| order.total = order.items.sum(&:price) * 1.1 }
        end
      end
    
      # 良い例: テストコードでも作成・更新ロジックはアプリケーションコードを利用
      order = OrderService.create_with_items(user, items)
    

FactoryBotを使う理由

まず、FactoryBotを使う理由ですが、一般的な考え方をすると以下のような利点があります。

  1. テストデータ作成の簡素化

     # 関連を含むデータを簡単に作成できる
     user_with_orders = create(:user_with_orders)
    
  2. データの一貫性担保

     factory :user do
       sequence(:email) { |n| "user#{n}@example.com" }
       name { "Test User" }
     end
    
  3. テストケースごとのカスタマイズ性(trait)

     # 状態の異なるデータを簡単に作成
     paid_order = create(:order, :paid)
     canceled_order = create(:order, :canceled)
    

非常に便利なので、Railsでのプロジェクトでは利用しないことはあまりないんじゃないでしょうか。
私も例に漏れず普段から便利に使っています。

FactoryBotを使わない理由

一方で、FactoryBotを使わない方が良いケースもあります。 特に複雑な作成・更新ロジックが絡む場合には、FactoryBotのみでデータを作成するのはあまり望ましくありません。

複雑な作成・更新ロジックが絡む場合

例えば、以下のようなケースを考えてみます。

# 本番環境でのオーダー作成ロジック
class OrderProcessor
  def self.create_subscription_order(user, plan)
    order = Order.new(user: user)
    
    # 複雑な作成・更新ロジック
    subscription = SubscriptionService.create_subscription(user, plan)
    order.subscription = subscription
    order.total = calculate_total_with_tax(plan.price)
    order.apply_initial_discount if user.first_order?
    order.save!
    
    NotificationService.send_welcome_email(user, subscription)
    order
  end
end

# FactoryBotで似たようなロジックを実装してしまう例
FactoryBot.define do
  factory :subscription_order do
    association :user
    association :subscription

    after(:build) do |order, evaluator|
      # 作成・更新ロジックの再実装
      order.total = order.subscription.plan.price * 1.1  # 税込計算
      order.discount = order.user.first_order? ? 1000 : 0
    end
  end
end

様々な組織で様々なプロジェクトに触れていると、このように作成ロジックと似たような処理が、FactoryBot側に再実装されているケースがあります。
これがFactoryBotを使わない方が良い例になります。 ※1

この場合の問題は簡単にまとめると2つあります。

  • 作成・更新ロジックの二重管理
    • 本番コードとテストコードで似たようなロジックが存在
    • どちらか一方の変更が他方に反映されない可能性
  • テストの信頼性低下
    • 微妙な計算の違いが発生する可能性
    • エッジケースの扱いが異なる可能性

今回相談を受けていたプロジェクトでも、このようなロジックの再実装が1つの要因になっていました。

さてこれを改善するならば、FactoryBotには単純なデータ作成のみを任せ、作成・更新ロジックは専用のクラスを呼び出すようにするという方針になります。
例えば

  it "processes subscription order correctly" do
    user = create(:user)
    plan = create(:premium_plan)
    
    # アプリケーションコードと同じロジックを使用してデータを作成
    order = OrderProcessor.create_subscription_order(user, plan)

    # ~~~    
  end

のように書いておくのが1つの例になります。
この方法だと、依存関係が増える一方でアプリケーションコードでは発生しえないデータの作成を抑制することができます。

まとめ

FactoryBotは非常に便利な一方、ただ素直に作成しているとアプリケーションコードと同一、もしくは似たような作成・更新ロジックを再実装することになってしまいます。
複雑でなくともリソースにまつわる作成・更新ロジックがクラスやメソッドがアプリケーションコードにある場合は、テストコードでも共通で利用し、ロジックの分散や、再実装の手間を減らしましょう。

冒頭で紹介した問題も、FactoryBotの実装をシンプルにし、作成・更新ロジックは本番コードを利用するように修正することで解決することができました。
テストが失敗する原因が「FactoryBotの設定が間違っている」ではなく「作成・更新ロジックの使い方が間違っている」という本質的な問題だったことに気づけたのは、良い学びとなると思います。

※1 FactoryBotから作成・更新ロジックを呼び出すようになっている場合は問題ないケースが多い

画面共有しながら使えるフローティングタイマー「Snack Time」を公開しました

オンラインミーティングで画面共有しながら使える、シンプルなタイマー拡張機能を公開しました。

chromewebstore.google.com

まず初めにインストールの方法と使い方について紹介し、その後開発の経緯や今後の展望について紹介します。

インストール

上記のリンクからChrome Web Storeに行き、右上のAdd to Chrome を押してください。

Chrome Web StoreからSnack Timeをインストール

その後、拡張機能一覧にあるSnack Timeをピン止めしておきましょう。 ピン止めしておくことで、より簡単にタイマーを起動することができます。

拡張機能のピン止め

ちゃんとピン止めされていればURLバーの横にある拡張機能欄に表示されます。

Snack Timeがピン止めされている

主な機能

Snack Timeの現時点での主な機能は以下になります。

  • フローティングタイマー
    • 開いているWebサイト上に位置調整が可能なタイマーを表示
    • またシンプルなUIなのであまり邪魔になりません
  • プリセットタイマー(Prestes)
    • 決まった時間のタイマーを簡単に起動
    • 下部の⚡ Custom を押すと、任意のを指定可能
  • タイマー履歴(Recent)
    • 実行したことのあるタイマーを起動するための履歴機能

です。

基本的な使い方

今回は、Presetsの3分のタイマーを起動する方法について紹介します。

  1. Snack Timeの拡張機能をクリックし、ポップアップを表示させる

    Snack Timeのポップアップ

  2. ポップアップの Presetsにある 03:00をクリックする

  3. タイマーが右上に表示され起動する

    タイマー起動

  4. タイマーを任意の位置に移動させる

    タイマーを移動

  5. 時間になるとアラームがなり、表記が Time's up!に変わる

    タイマーの終了

  6. 不要になったらCloseを押して消す

基本的な使い方は以上です。
ここからは開発の経緯や今後の展望について書いていきます。

開発の背景

私は所属している組織や、個人事業でのミーティングは基本的にオンラインで実施することが多いです。
そのため画面共有で議事録を表示しながら話していることが多いのですが、オンラインタイマーをいちいち検索するのが面倒だったため、ブックマークレットでタイマーを作っていました。

clock.zuki.dev

そのサイトのコードはアーカイブしているので更新していませんが、元々オンラインタイマーかChrome拡張を作る予定だったので、サクッと作っておきました。

実装時のポイント

今回のChrome拡張は、できる限りReact+MUIを使いたかったこともあり、

github.com

を参考にしながら、CRXJSを組み込んでいます。
そのため、拡張機能をクリックした時のPopupとOptionsの画面は、React+MUIが構築されており、統一感のある見た目とライト・ダークテーマがシステム設定によって切り替わるようになっています。
SnackTimeでは、最小限の構成になっているのでコードを直接見てもらった方が良いかもしれません。

github.com

CRXJS様様ですね。

Timerについて

実際に使ってみると分かりますが、現時点ではタイマーの見た目がMUIではありません。
これはタイマーの実装をWebサイト上に表示するためにchrome.scrtipting.executeScriptを利用しているための制約で、React+MUIが直接扱えません。
そのため、独自実装になってしまっています。

ここに関しては回避策を思いついていませんが、もしかしたらできるかもしれない方法は1つあるので、 そのうち実装されているかもしれません。

今後の展望

あまり凝った拡張でもないので、ユーザー影響がありそうな部分では以下を考えています。

  • 多言語対応
  • カスタマイズ機能の追加予定
    • プリセット値の変更
    • アラーム音の設定
    • タイマーのサイズ(文字を含む)

ユーザーフィードバックは、手間だとは思いますが、SnackTimeレポのIssuesか、 Xのcorrupt952まで連絡くれると助かります。

github.com

まとめ

今回はSnack TimeというChrome拡張を紹介しました。
特にリモートワーク環境でのオンラインミーティング時にタブのみ共有しているケースであれば有用だと思うので是非使ってみてください。

tmuxistを見直してv1リリースした話

個人でTmuxのセッション管理を行うためのツールとしてtmuxistというのを6年前から細々と開発・使用しています。

github.com

今回はそのtmuxistを区切りとしてv1リリースした話です。

TL;DR

  • 設定ファイルの位置を変更
    • $HOME/.config/tmuxist/{PROFILE}.toml -> $PWD/tmuxist.toml
    • Profile制の廃止
  • コマンド体系の整理
    • Profile制のためのedit, delete, list, printを廃止
    • start,attachをstartのみに統合
    • init, start, killの3種類のみ変更
  • これらを反映したものをv1としてリリースした

tmuxistとは

冒頭でも紹介しましたが、簡単に言うとTmuxinatorのようなツールになります。
2017年まではこちらを利用していたんですが、Rubyがインストールされていない環境で作業することが個人的には多くシングルバイナリで動作するようなものを探しており、当時はあまりなかったので自作していました。

github.com

実際にはTmuxinatorのような豊富な機能はなく、個人的にあれば十分な機能としては以下のようなものになります。

  • 指定した設定通りにウィンドウ・ペインが一括で起動
  • 各ペインでは指定したコマンドが自動実行

tmuxistはこれらを目指すために最小限で開発していたツールになります。

# v1では主なコマンドはこの3種類のみ

# 設定ファイルの作成
tmuxist init

# tmuxの起動・既存sessionへのアタッチ 
tmuxist start

# tmux sessionの停止
tmuxist kill

ユースケース

複数台のサーバー同時操作

最近はほぼ全ての環境がコンテナなので仕事でのユースケースとしては減りましたが、 自宅鯖は同じ構成が複数台でクラスタを組んでいます。
そういった構成の時に全く同じ操作を各サーバで利用したい場合に設定ファイルを要してtmuxist経由で起動して行うことが容易です。

# tmuxist.toml
[[windows]]
layout = "tiled"
sync = true
[[windows.panes]]
command="""
ssh server1
"""
[[windows.panes]]
command="""
ssh server2
"""
[[windows.panes]]
command="""
ssh server3
"""
[[windows.panes]]
command="""
ssh server4
"""

この例では

  1. 4つのペインをタイル表示
  2. ペインごとに各サーバへSSH接続
  3. 最後にペインの入力同期を有効

ということをしています。
こうすることで、複数台のサーバへの接続が容易でかつ同じ操作を行うことが容易にできます。

開発環境の起動

こちらのユースケースとしては、Foremanが近いかもしれません。
Foremanでは、Procfileに書かれた通りのコマンドを実行してプロセスを管理してくれます。
これと似たようなことをtmuxistでやろうということになります。

例えば、何らかのアプリを開発する場合、私はいつも

  • Window1 ... アプリケーション起動用
  • Window2 ... シェル操作用

といったWindowに分けて操作することが多いです。
これをtmuxistでは、

# tmuxist.toml
# Window1
[[windows]]
[[windows.panes]]
command="""
bundle install;
yarn install;
bin/dev
"""

# Window2
[[windows]]
[[windows.panes]]

のように定義することで簡単に起動することができます。

v0.0 -> v1.0までの変更内容

設定ファイル

元々のv0.0系では、$HOME/.config/tmuxist配下に{PROFILE_NAME}.tomlというファイルを管理する方式でした。
ですが、環境によってはユーザー名も違うこともあり、dotfilesでの同期がやや難しく、また別の人間が同じ構成を復元したい場合でも気軽にやりたいといったケースがでてきました。

そのため、v0.1系でコマンド実行時のカレントディレクトリにあるtmuxist.tomlを参照するように変更しました。
こうすることで同じレポであれば同じ設定で誰でも気軽に復元できるようになりました。

もちろん、これはメリデメありますが、マイクロサービスでの開発を行う場合にまとめて起動しやすくなるメリットを優先しての実装です。

そのうち任意のパスを指定して読み込めるようにするかもしれません。
tmuxist start -f $(closest tmuxist.toml)のような 形で。

コマンド体系

設定ファイルで説明したように元々$HOME/.config/tmuxistにProfileごとに設定ファイルを配置していた都合で、
設定ファイルの編集・削除・表示や、Profile一覧といったコマンドを実装していました。
しかし、v0.1系に伴って不要になったので削除しました。

また、v0.0系では起動のstartと、既存セッションへのattachが別々のコマンドとして存在しており、やや操作が煩雑になってしまたっため、これらを統合してstartのみにしました。
こうすることで自分を含めたユーザーが覚えるコマンドが少なくなるのでメリットになりますね。

まとめ

Tmuxを利用していて、いつも起動するパターンがある場合は、Tmuxinatorやこのtmuxistを使ってみてください。
自分が使う用のツールとして開発していることがメインで、特にIssueもないので自分が必要な時に必要な変更を行っていくと思いますが、
もし意見・要望があれば気軽に日本語で問題ないのでIssueをあげてください。

RBSファイルを自動生成したい

最近はRBSが浸透しつつつあり、私もSteepを使った開発を行うことが増えてきています。
今回はそういったユースケースrbs-inlineで定義を生成している場合にファイルに変更があったら自動で更新するような仕組みについての紹介です。

TL;DR

  • rbs-inline推奨のfswatchで問題が発生しないならこの記事を読む必要はない
  • Docker on WSLの環境でfswatch方式では意図しない動作が発生し利用が難しい
  • chokidarを利用して自作

rbs-inlineのオススメの方法

rbs-inlineでも自動生成する方法について書いてあり、fswatch`を使うのが良いとされています。

github.com

fswatch -0 lib | xargs -0 -n1 bundle exec rbs-inline --output

この方法なんですが、少なくともWSL環境化でのDockerコンテナ内では適切に動作しませんでした。
具体的には一度保存処理が走った後に無限にファイルイベントがトリガーされ続けるといった問題です。

こういった問題が発生しない場合は、これ以降は読む必要は特にありません。

chokidarを使って自作

chokidarというファイル監視用のライブラリが公開されています。
tailwindcssコマンドなどで利用されており、既にインストールされている場合もあるので、こちらを利用して実装していきます。
もしインストールされていない場合は、yarn add -D chokidarなどを実行してインストールしておいてください。

bin/rbs.js

node rbs.js app lib のように複数のディレクトリを監視対象としたいので、 process.argv.slice(2) を使って複数受け取るようにしています。

// bin/rbs.js
const chokidar = require('chokidar');
const { exec } = require('child_process');

// node rbs.js app libと指定した場合に['app','lib']が返ってくる
const watchDirs = process.argv.slice(2);
console.log(`Watching directories: ${watchDirs.join(', ')}`);

// watchDirs配下の.rbファイルを対象とする
const watcher = chokidar.watch(
  watchDirs.map(dir => `${dir}/**/*.rb`)
  , {
    ignored: /(^|[\/\\])\../,
    persistent: true,
  });

// 変更イベント時に該当ファイルに対してrbs-inlineを実行
watcher
  .on('change', path => {
    exec(`bundle exec rbs-inline --output ${path}`, (err, stdout, stderr) => {
      if (err) {
        console.error(err);
        return;
      }
      console.log(`Regenerated RBS for ${path} via rbs-inline`);
    });
  })

foremanなどを利用している場合はProcfile.devに対して以下のような行を追記し、bin/devで起動すれば後は自動生成されるようになります。

rbs: node bin/rbs.js app lib

まとめ

今回は実際に自分が使っている環境でのrbs-inlineの自動実行方法についての紹介でした。
今回は省略したんですが、特定のパスではrbs_railsを実行しており、コマンドのみで実行する場合と比べてコントロールが大分柔軟にできるやり方になります。

もし似たような現象で困っている人がいれば是非書いてみてください。 inotify系のツールは、ちょっと別の理由で使っていませんが、利用できる環境であればそちらを利用してみても良いかもしれません。

Railsプロジェクト向けの.devcontainer/Dockerfileの一例

未来の自分用のメモです。 

ベースイメージが存在していないToyアプリなどで利用することが多いDockerfileについて紹介します。
Railsで動作させることが前提ですが、空行で表現しているグループごとに説明します。

  1. Localeの設定
    • 設定しないとrails consoleなどでマルチバイト文字でエラー出がち
  2. Timezoneの設定
    • 設定してもしなくてもOK
  3. 各種パッケージのインストール
    • Rubyのビルドや利用したいDBのパッケージなどをインストール
    • 場合によってはツールなどもインストールしても良いかもしれない
  4. UserやWorkdirの設定
    • 移行のRUNがzshで動作することが前提になっているのでSHELLを指定
    • それ以外は特になし
  5. asdfのインストール
    • rbenvやnなどは利用せずasdfを使っている 
  6. RubyやNode.jsをインストール
    • .tool-versionsを解析して、plugin addやinstall、globalまで設定している
    • Globalにしている理由としてはVSCodeのSteep拡張の呼び出しの問題に対しての対策
  7. yarnのインストール
    • Railsだとyarnがデフォルトなので一応入れてる
    • npmで動くように変えてるなら不要

これらをまとめたのが以下になります。

FROM mcr.microsoft.com/devcontainers/base:bookworm

# Configure locales
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8

# Configure timezone
ENV TZ=Asia/Tokyo
RUN sudo ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# Install packages
RUN apt-get update && apt-get install -y \
    build-essential \
    curl \
    git \
    libssl-dev \
    zlib1g-dev \
    libyaml-dev \
    libreadline-dev \
    libncurses5-dev \
    libffi-dev \
    libgdbm-dev \
    libzmq3-dev \
    libsqlite3-dev \
    libpq-dev \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Configure user and workspace
USER vscode
WORKDIR /workspace
SHELL ["/bin/zsh", "-c"]

# Install asdf
ENV ASDF_VERSION=v0.14.1
RUN git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch $ASDF_VERSION \
    && echo '. "$HOME/.asdf/asdf.sh"' >> ~/.bashrc \
    && echo '. "$HOME/.asdf/asdf.sh"' >> ~/.zshrc

# Install tools via asdf
COPY .tool-versions /workspace/.tool-versions
RUN . $HOME/.asdf/asdf.sh \
    && cat .tool-versions | grep -v '#' | awk '{print $1}' | xargs -n 1 asdf plugin add
RUN . $HOME/.asdf/asdf.sh \
    && asdf install
# Set global versions
RUN . $HOME/.asdf/asdf.sh \
    && cat .tool-versions | grep -v '#' | xargs -n 2 asdf global

# Install yarn
RUN . $HOME/.asdf/asdf.sh \
    npm install -g yarn

CMD ["bash"]

実際のプロダクト開発ではベースイメージを用意しているケースが多いので、このまま利用できるわけではないですが、 あくまでToyアプリなどでは比較的利用しやすいかなと思います。

IaCを利用したクラウドリソース管理の4つの壁

今回の話はポエム寄りの話になります。

クラウドリソースの管理において、Infrastructure as Code(IaC)は今や欠かせない存在となっています。
しかし、IaCの導入や学習には見えない壁が存在します。
今回は、この壁についての持論について述べていきたいと思います。

4つの壁

IaCを導入・学習しようとする際、多くの人が「難しい」「よく分からない」と感じます。
しかし、その難しさの正体は実は複数の層に分かれていると私は考えています。
私は、これを「4つの壁」として捉えており、私が関係している組織ではしばしば同様の説明をしています。

  1. ツールの壁
  2. クラウドプロバイダの壁
  3. ツールとクラウドの統合の壁
  4. 組織のドメインの壁

これらの壁は、初めて触れる人には区別がつきにくく、そのため対処が難しくなっています。
では、具体例を交えながら、各壁について見ていきましょう。

ツールの壁

例えば、Terraformを使ってIaCを始めようとした場合、まず直面するのがこの「ツールの壁」です。

  • HCL(HashiCorp Configuration Language)の文法
  • Terraformの実行モデル(plan, apply, destroy)
  • 状態管理(state)の概念

これらはTerraform固有の概念であり、クラウドやインフラの知識があっても、一朝一夕には習得できません。
しかし、この部分を学ぶだけであれば、それほど苦ではないでしょう。

クラウドプロバイダの壁

次に立ちはだかるのが「クラウドプロバイダの壁」です。
AWSを例にとると:

  • 膨大なサービス群(EC2, S3, RDS, Lambda, etc.)
  • IAMによる複雑な権限管理
  • VPCを中心としたネットワーキング

これらの概念や設定の詳細は、AWSを利用する上で避けては通れません。
AWSGoogle Cloud、Azureなど、各サービスごとに概念が似ているようで似ていなかったり、各リソースごとに全くもって統一感のないAPIやリソース定義、ポリシーなど多くの認識すべき項目があります。
IaCでは、これらをコード化するので理解しなければならないので、4つの壁の中でも大きな壁の1つとも言えます。

ツールとクラウドの統合の壁

TerraformでAWSリソースを管理しようとすると、新たな壁が現れます。

  • AWS特有のリソース間依存関係をTerraformでどう表現するか
  • 特定のAWSサービスに対するTerraformプロバイダの制約
  • Terraformの実行モデルとAWSリソースの作成・更新フローの整合性

これらは、ToolとCloudの両方を理解していないと対処が難しい問題です。
いざ書こうとしても、Terraformでどう表現するのかが難しい点です。
ただし、1,2を理解できているなら、それほど苦ではないのですが、しばしば「クラウドプロパイダの壁」とこの壁は区別されないように思います。

組織のドメインの壁

最後に、見落とされがちなのが「組織のドメインの壁」です。

技術的には正しくても、組織の文脈で適切でない実装は、現実的には採用できません。
1,2,3で何とか表現方法を理解しても、この壁でどう書くべきか悩ましくなってしまう傾向が見られます。
本当に難しいですね。

ともに壁越えといこうじゃないか

これらの壁を認識したうえで、壁を超えていきましょう。
ここでは、2つのアプローチを簡単に紹介します。

ツールの壁・ツールとクラウドの統合の壁

CDK(Cloud Development Kit)とTypeScriptの組み合わせは、これらの壁を効果的に克服する強力なアプローチです。

  1. プログラミング言語の活用: TypeScriptの型安全性と豊富なエコシステムを活用し、より柔軟で堅牢なインフラ定義が可能になります。
  2. 高レベルの抽象化: CDKは低レベルのクラウドリソース設定を抽象化し、開発者が意図を直接表現できるようにします。
  3. ツールとクラウドの統合: CDKはAWSのベストプラクティスを組み込んだConstructsを提供し、ツールとクラウドの統合の壁を低くします。
  4. コード再利用性の向上: TypeScriptの機能を活用し、共通のパターンやロジックを容易に再利用できます。

適切にCDK+TypeScriptを利用することで、強力な補完を利用して、これらの障壁を大幅に低減することが見込めます。
私は今のところTerraform派ではありますが、相談を受けた組織の技術スタックによってはCDK+TypeScriptをまず進めることが多いです。

クラウドプロパイダの壁

この壁が1番難しいと言え、中々近道がないのが現状です。

  1. 段階的学習: クラウドサービスを一度に全て学ぼうとせず、基本的なサービス(コンピューティング、ストレージ、ネットワーキング)から始め、徐々に組織で利用しているサービスへと拡張していきます。
  2. ハンズオン実践: 公式のチュートリアルやハンズオンラボを活用し、実際に手を動かしながらサービスの挙動を学びます。
  3. アーキテクチャパターンの理解: クラウドプロバイダが提供する参照アーキテクチャやベストプラクティスを学び、適切なサービスの組み合わせ方を理解します。
  4. コミュニティの活用: オンラインフォーラムやローカルのユーザーグループに参加し、他の実務者から学びます。多くの場合、実際の運用経験に基づいた貴重な情報を得ることができます。
  5. 継続的な学習: クラウドサービスは常に進化しています。定期的にクラウドプロバイダのアップデート情報をチェックし、新しい機能や改善点を学び続けることが重要です。
  6. 認定資格の取得: クラウドプロバイダの公式認定資格の取得を目指すことで、体系的な学習が可能になります。

このように近道といえるようなものは正直ありません。
これらをメンバーが実施しやすいように組織として対策としては以下がオススメです。

  • サンドボックス環境を用意し、メンバーが検証や勉強に利用可能にする
  • 利用しているサービスを可視化しておき、学ぶべき範囲を狭める

これらの環境が整っているだけでも十分学ぶきっかけを用意することができています。

まとめ

IaCの導入における「見えない壁」を理解し、それぞれに適切に対応することは、クラウドリソース管理の複雑性に効果的に対処する上で非常に重要です。
どのアプローチを選択するにしても、これらの壁を認識した上で、段階的かつ継続的に改善を進めていくことが成功の鍵となります。

今回の話は、クラウドリソースについて焦点を絞りましたが、AnsibleやChef、Kubernetesといったツールなどにも似たような話があります。
もし導入や学習につまづく場合は、どういった壁があるのかを可視化したり、詳しい人に相談してみるといいかもしれませんね。