🚀

Claude Codeと1ヶ月で自作ライブラリをマルチプラットフォーム化した話という内容で記事を書こうとしたら想像より難しかった件

に公開

タイトル通りなんですが、自作ライブラリを拡張した話をClaude Codeに書かせてみたら予想以上に難しく、なかなか自分の思い通りの内容で記事を書いてくれなかったので、それをむしろ記事にしてしまうことにしました。

この出だしだとAI批判の記事っぽくなってしまうんですが、実際はもうAIが手放せないくらい日頃からガッツリAI使って仕事させてもらってます。ただ、人間少し便利になるとどんどん欲が出てくるもので、そんな心境も含めて軽く記事にしてみました。
記事の後半に実際にAIに作ってもらった記事もそのまま貼っているので、そちらも合わせて読んでいただければ幸いです。
自分はそもそも文章を書くことが苦手で、書きたい内容はあっても実際に記事にするのが億劫で諦めることも多いんですが、AI君を使えばサクッとできてしまうんじゃないかと思い、冒頭の内容で記事を書かせてみました。
最初に指示したのは「実際に作成したライブラリのリンクを貼って、それについて先のタイトルで記事を書いて」という内容だったんですが、もちろんこれだけでは上手くいくはずもなく、かなり見当違いな内容で書かれてしまったので、文章を選択しながら一箇所ずつ指示をして修正しました。
自分がまだまだAIを使いこなせていないことは重々承知ですが、指示して修正していってもなかなか自分の思い通りのトーンにならず、さらにはこれは大丈夫だろうと思ったコードサンプルの部分も全くダメで、こりゃアカンとなってしまったわけです。

特にコードサンプルについては、実際のサンプルアプリのコードまできちんと読ませて書かせたんですが、実際の実装通りにはならず、結局まるっきりコピペのような感じで貼ってもらうだけになりました。

そのまま記事を修正していても埒が明きそうにない上に、苦手な記事作成にあまり時間を費やす気にもなれず方針転換したわけですが、なぜこんなことになってしまったのか自分なりの理由を考えてみたところ:

  • 指示が大雑把すぎた
    記事を書くことにした背景なども細かく教えてあげれば、もう少しマシだったかもしれない

  • やらせたいことが非常に高度だった
    普通は記事を書く、もしくはコードを書くというどちらか一方をやらせるが、今回はそれを同時に、しかもライブラリという汎用的で複雑な仕組みを理解する必要があった

のではないかという結論になりました。

AIの現在の成長速度はまさに日進月歩という感じで、少し目を離すと全くレベルが違うところに到達しているので、あっという間にこの程度のことは簡単にこなしてしまうようになるのかもしれません。ただ、現状の自分くらいのAI理解度だと、畑違いの複数の作業を同時にやらせようとすると上手くいかないですね。

もちろん現時点でもしっかりと使いこなせば可能だと思いますし、自分が使いこなせていない様々な便利ツールについての情報も教えてもらったりしているので、今後AIの成長に負けないように自分自身も成長していきたいと思います。

というわけで、以下がAIに作成してもらった自作ライブラリの記事(本来一番書きたかった内容)になります。
内容は実際の実装とずれている箇所が少々ありますが、その辺りは生温かい目で見ていただければと思いますm(_ _)m

この記事はClaude Codeを使って執筆しています

はじめに

約1ヶ月前、UIKit専用だった自作ライブラリを、Claude Codeの力を借りて大幅に拡張しました。結果として、iOS/Android両プラットフォーム、さらにはVSCode拡張機能まで含む包括的なエコシステムを構築できたので、その経験を共有します。

元々のライブラリ:SwiftJsonUI

最初に作成していたのはSwiftJsonUIという、JSONからUIKitのビューを動的に生成するライブラリです。

開発の背景

GitHubの履歴を見返すと、SwiftJsonUIを最初に作成したのは約7年前でした。当時のiOS開発環境には大きな不満を抱えていました:

  • Xcodeでの UI作成が非効率的:Interface Builderは直感的に見えて、実際は複雑で扱いにくい
  • Auto Layoutの複雑さ:Constraintの設定が煩雑で、特に動的なUIには不向き
  • コピペが困難:Interface Builderベースの開発では、UIコンポーネントの再利用やコピペが非常に不便

一方で、Android StudioでのXML形式のレイアウト定義は、テキストベースで扱いやすく、コピペも簡単でした。さらに、ちょうどその頃React Nativeに触れる機会があり、ホットリロード機能の便利さに感動したことも、このライブラリを作るきっかけになりました。

SwiftJsonUIの基本コンセプト

このライブラリの核となるアイデアは、JSONでUIを定義することです。例えば、以下のようなJSONを書くだけで:

{
  "type": "SafeAreaView",
  "id": "main_view",
  "width": "matchParent",
  "height": "matchParent",
  "background": "#FFFFFF",
  "child": [
    {
      "type": "Label",
      "id": "title_label",
      "text": "Welcome to your new view!",
      "textAlign": "center"
    }
  ]
}

対応するUIKitのビューが自動生成されます。これにより:

  • Constraintを意識しない開発:壊れやすいUIKitのAuto Layout Constraintを気にせずにUIを構築できる
  • ホットリロード的な開発体験:JSONを変更するだけでUIが更新
  • デザイナーとの協業:コードを書かなくてもUIの調整が可能

といったメリットが得られます。

実際に数年使ってみた結果

UIKit版を自社のiOSアプリ開発で使い始めてから数年。もう手放せないツールになっています。

実際に使ってみてどうだったか

正直、期待以上でした。UI実装の速度が大幅に向上しました。

今まで3〜4時間かけて作っていた画面が30分で完成するようになりました。Constraintのエラーに悩まされることもなくなり、デバッグ時間もほとんどゼロに。コードレビューも楽になりました。JSONのdiffは見やすくて、変更点が一目瞭然です。

特に印象的だったのは、iOS開発未経験のメンバーがすぐに使いこなせるようになったことです。Web開発から転向してきた人が、初日から「属性名が直感的で分かりやすいですね」と理解してくれました。Constraintの学習は一切不要で、フロントエンド開発の経験があれば自然に馴染めるようです。

でも、やりたいことはまだまだあった

とはいえ、やり残したことがたくさんありました。

AndroidのXMLへのパース機能も作りたかったのです。実は元々AndroidのXML仕様を参考にして作ったため、理論上は実現可能なはずでした。しかし個人開発では時間が取れず、Android側は特に困っていなかったこともあって、結局実現には至りませんでした。

さらにSwiftUIの登場により、「UIKitだけでは不十分かもしれない」という危機感も生まれました。しかし、それぞれのフレームワークに対応させるのは、考えただけで気が遠くなる作業量です。概算でも月200時間は必要そうで、本業もある中でそんな時間を確保するのは現実的ではありませんでした。

そこで登場したのがClaude Codeです。

1ヶ月でやったこと

1. SwiftUIへの対応

最初の拡張はSwiftUIへの対応でした。実装イメージは頭の中にありましたが、実装コストを考えると、なかなか開発に踏み切れませんでした。Claude Codeがいなければ、おそらく今でも「いつかやろう」リストに入ったままだったでしょう。

// UIKit版の実装例(MainViewController.swift)
import UIKit
import SwiftJsonUI

class MainViewController: BaseViewController {
    override var layoutPath: String {
        return "main"  // Layouts/main.jsonを読み込み
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(UIViewCreator.createView(layoutPath, target: self)!)
        binding.bindView()
    }
}

// SwiftUI版の実装例(ComponentsTestGeneratedView.swift)
import SwiftUI
import SwiftJsonUI

struct ComponentsTestGeneratedView: View {
    @EnvironmentObject var viewModel: ComponentsTestViewModel
    @StateObject private var dynamicViewModel = DynamicViewModel(jsonName: "components_test")
    
    var body: some View {
        if ViewSwitcher.isDynamicMode {
            // 動的モード:JSONから直接UIを生成
            DynamicView(jsonName: "components_test", data: viewModel.data.toDictionary())
                .environmentObject(dynamicViewModel)
        } else {
            // 静的モード:ビルド時に生成されたSwiftUIコード
            VStack(alignment: .leading, spacing: 0) {
                PartialAttributedText("Components Test", fontSize: 24)
                Toggle(isOn: $viewModel.data.toggle1IsOn) {
                    Text("Enable Notifications")
                }
                Slider(value: $viewModel.data.slider1Value, in: 0...1)
                // ... 他のコンポーネント
            }
        }
    }
}

設計は自分で考えましたが、とにかく助かったのは単純な作業量の削減です。UIKitではJSONからオブジェクトを生成する実装だけで済んだのに対し、SwiftUIでは生のコード生成とホットリロード用のDynamicコンポーネントを別々に作る必要があり、実装コストが2倍になりました。全てのコンポーネント(Label、Button、Image、Stackなど)に対してこの作業が必要でしたが、この膨大な実装をClaude Codeが効率的に処理してくれました。

2. Android版の開発:KotlinJsonUI

次の大きなステップは、KotlinJsonUIの開発でした。

iOS/Android両方の開発経験はあったものの、両プラットフォーム対応のライブラリを作るのは別次元の難しさがありました。しかしClaude Codeが以下の点で大きな助けとなりました:

  1. XMLレイアウトとJetpack Composeの両対応を提案
  2. 最新のKotlinの書き方を効率的に実装
  3. 複雑なGradleの設定も適切に処理

とても頼りになるパートナーとして活躍してくれました。

// Jetpack Compose版の実装例(HomeGeneratedView.kt)  
// XML版はJSONからAndroid XMLレイアウトファイルが自動生成される
@Composable
fun HomeGeneratedView(data: HomeData, viewModel: HomeViewModel) {
    if (DynamicModeManager.isActive()) {
        // 動的モード:JSONから直接UIを生成
        SafeDynamicView(
            layoutName = "home",
            data = data.toMap(viewModel),
            onError = { error -> Log.e("DynamicView", "Error: $error") },
            onLoading = { CircularProgressIndicator() }
        )
    } else {
        // 静的モード:ビルド時に生成されたComposeコード
        Column(modifier = Modifier.padding(16.dp)) {
            Text(
                text = data.title,
                fontSize = 24.sp,
                fontWeight = FontWeight.Bold
            )
            Button(
                onClick = { viewModel.onGetStarted() },
                colors = ButtonDefaults.buttonColors(containerColor = Color.Blue)
            ) {
                Text("Get Started")
            }
        }
    }
}

3. 共通JSONフォーマットの確立

iOS/Android両対応となると、JSONフォーマットの統一が重要です。Claude Codeと議論しながら、プラットフォーム固有の差異を吸収する仕組みを作りました:

{
  "type": "View",
  "orientation": "vertical",
  "padding": 16,
  "child": [
    {
      "type": "Label",
      "text": "Simple Test",
      "fontSize": 24,
      "fontColor": "black"
    },
    {
      "type": "Label",
      "text": "Testing basic components",
      "fontSize": 16,
      "fontColor": "medium_gray_4",
      "topMargin": 8
    },
    {
      "type": "Button",
      "text": "Test Button",
      "background": "medium_blue_3",
      "fontColor": "white",
      "topMargin": 16
    }
  ]
}

このJSONが、UIKit、SwiftUI、XML、Jetpack Composeの4つすべてで同じように表示されます。

4. VSCode拡張機能の開発

最後の仕上げは、swiftjsonui-helperというVSCode拡張機能の開発でした。

この拡張機能により:

  • オートコンプリート:コンポーネントやプロパティの候補を自動提案
  • テンプレート挿入:View、Label、Buttonなどのテンプレートをショートカットで挿入
  • ホバードキュメント:プロパティにマウスを乗せると説明や使用例を表示
  • JSONスキーマ検証.swiftjsonui.jsonファイルの型チェックとエラー表示
// VSCode拡張の実装(extension.ts)
import * as vscode from 'vscode';

const componentProperties: { [key: string]: string[] } = {
    'View': ['child', 'orientation', 'padding', 'spacing', 'background'],
    'SafeAreaView': ['child', 'orientation', 'safeAreaInsetPositions'],
    'Label': ['text', 'fontSize', 'fontColor', 'textAlign', 'lines'],
    'Button': ['text', 'onClick', 'background', 'fontColor', 'enabled'],
    'Image': ['src', 'url', 'contentMode', 'width', 'height'],
    'Table': ['child', 'background', 'scrollEnabled'],
    'Collection': ['child', 'cellClasses', 'headerClasses', 'footerClasses'],
    // 各コンポーネントのプロパティ定義
};

// オートコンプリートの実装
const completionProvider = vscode.languages.registerCompletionItemProvider(
    'json',
    {
        provideCompletionItems(document, position) {
            const linePrefix = document.lineAt(position).text.substr(0, position.character);
            
            // typeプロパティの補完
            if (linePrefix.includes('"type":')) {
                return Object.keys(componentProperties).map(
                    type => new vscode.CompletionItem(type)
                );
            }
        }
    }
);

Claude Codeが特に役立った場面

1. 膨大な実装作業の効率化

設計は自分で考えましたが、実装は本当に大変な作業でした。各コンポーネント(Label、Button、Image、View等)を4つのフレームワーク(UIKit、SwiftUI、Android XML、Jetpack Compose)それぞれに実装する必要がありました。Claude Codeが着実に実装作業を進めてくれたおかげで、本来なら数ヶ月かかる作業を1ヶ月で完了させることができました。

2. 反復的な実装パターンの適用

一つのコンポーネントの実装例を示せば、Claude Codeが同じパターンで他のコンポーネントも実装してくれました。「Labelはこう実装したから、Buttonも同じパターンで」というように、単調ながらも重要な作業を正確に処理してくれました。

3. テストコードとエラーハンドリング

「こういうエラーハンドリングを入れて」と指示すると、全てのコンポーネントに漏れなく適用してくれました。手作業だと見落としがちな部分も、Claude Codeなら確実に実装してくれます。

4. ドキュメント作成

各ライブラリのREADME、API仕様書、サンプルコードまで、Claude Codeが整備してくれました。特に英語のドキュメントは、ネイティブレベルの品質で書いてもらえたのが助かりました。

学んだこと

1. AIは実装の強力なパートナー

Claude Codeは実装作業の強力な助けとなりました。設計や仕様は自分で決めて、「これをこう実装して」と明確に指示すれば、正確に実装してくれます。単純作業から解放されて、設計や全体の方向性を考える時間が増えました。

2. 段階的な拡張が重要

一気に全てを作ろうとせず、UIKit→SwiftUI→Android→VSCode拡張機能と段階的に拡張したことで、各ステップでの学びを次に活かせました。

3. プロトタイピングの速度が競争力に

アイデアを即座に形にできる速度は、現代の開発において大きな競争力です。Claude Codeによって、1ヶ月という短期間で包括的なエコシステムを構築できました。

まとめ

Claude Codeとの1ヶ月は、私の開発人生で最も生産的な期間の一つでした。UIKit専用だったライブラリが、iOS/Android両対応、4つのUIフレームワーク対応、さらにはVSCode拡張機能まで含む総合的なソリューションに進化しました。

特に印象的だったのは、Claude Codeの実装速度と正確さです。同じパターンの実装を何度も繰り返す必要がある場合、人間なら疲れてミスをしそうなところを、Claude Codeは着実かつ正確に処理してくれました。

もしあなたも「作りたいけど工数が...」と悩んでいるプロジェクトがあるなら、Claude Codeと一緒に挑戦してみることをお勧めします。きっと想像以上の成果が得られるはずです。

リポジトリ

ぜひスターをつけていただけると励みになります!


この記事についての質問や、ライブラリの使用方法についてのお問い合わせは、各リポジトリのIssueまたはTwitter(もしあれば記載)までお気軽にどうぞ。

Discussion