なになれ

IT系のことを記録していきます

AIをフル活用して「自分が本当に欲しかった麻雀練習アプリ」を作った話

この記事はChatGPTを用いて校正しています。

作ったアプリはこちら

麻雀ソロ一索

麻雀ソロ一索

  • Hiroshi Oda
  • ゲーム
  • 無料
apps.apple.com

ずっと「こんな麻雀の練習アプリがあったらいいのに」と思っていたのですが、とうとう自分で作ってしまいました。 しかも、イデアからリリースまで約1ヶ月。

AI が本格的に使えるようになった今、アイデアを形にするハードルは本当に下がったんだな、と実感しました。

私は普段ソフトウェアエンジニアをしていますが、スマホアプリの開発経験はほぼゼロ。 さらに、アプリ開発って

  • 企画
  • デザイン
  • 実装
  • ストア準備

……と、とにかく幅広い作業が必要です。

正直、これを一人で全部やるのは厳しかったと思います。 今回、AI が相棒として大活躍したおかげで何とか実現できたので、そのプロセスをまとめておきます。


企画づくりは ChatGPT と一緒に

まずは ChatGPT に壁打ちするところからスタートしました。

麻雀はルールが明確なゲームだからか、返ってくる提案の精度がとても高くて驚きました。

最初のざっくりした相談がこちら:

1人でできる麻雀の練習アプリを作りたいです。ランダムな配牌からツモって上がりを目指す感じがいいのですが、どう思いますか?

すると ChatGPT からは、

「めちゃくちゃ良いです!まずは対戦相手なしの練習特化型が良いですね。必要な機能は……」

と、MVP(最小構成)から実装方針、テスト戦略まで、一気にまとめて提案してくれました。

そこからは、ChatGPT と会話しつつ

  • 履歴機能が欲しい
  • モバイルアプリでやりたい
  • 18巡以内にテンパイできなければ終了したい

など、自分の“こうしたい”を足していき、仕様書の原型が完成していきました。


アプリ名も ChatGPT と決めた

アプリ名も一緒に考えました。

「ソロ」を入れたい 一索(イーソー)を使ったロゴにしたい

という条件を伝えたところ、

「麻雀ソロ一索」

という案が返ってきて、響きも見た目もよかったのでそのまま採用。

こういう“ネーミングの壁打ち”も AI は驚くほど便利です。


実装は Codex CLI におまかせ

企画で作った仕様書を丸ごと渡して、実装は Codex CLI にお願いしながら進めました。

基本はシンプルで、

  1. 仕様書を渡す
  2. コードを生成してもらう
  3. 動かしてみる
  4. バグがあれば直してもらう

というサイクルをひたすら回しました。

特に麻雀のアルゴリズム部分(シャンテン計算など)は テストコードを書きながら Codex に補助してもらう というスタイルが相性抜群でした。


UI デザインは “AI で方向性を探し、Figma でまとめる”スタイル

実装が進んでいく一方、UI は完全に後回しだったので、最初はかなり素っ気ないデザインでした。

「さすがにこれは…」と思い、ここでも ChatGPT に麻雀画面のサンプル画像を作ってもらい、 色味や立体感の出し方を参考にしながら Figma で整え直しました。

サンプル画像

AI が作る牌の絵柄はところどころ怪しいのですが、雰囲気作りのヒントとしては十分役に立ちました。

最終的にできたメイン画面がこちら:

自前でゼロからデザインを考えるより、圧倒的にスムーズでした。


リリース準備も全部 AI に相談しながら

アプリを App Store に出すには、実装だけでなく

などなど、やるべきことが山ほどあります。

ここも ChatGPT と Codex CLI に相談しつつ、一つずつ潰していきました。

例えば「何が必要か教えて」と質問すると、

  • 必須の書類
  • SDK バージョン
  • ストア申請の手順
  • ライセンス表示の作り方

などを、フェーズ分けして分かりやすく教えてくれます。

文章作成や説明文の草案も AI が作ってくれるので、非常に助かりました。


おわりに:AI 時代の「一人プロダクト開発」

今回の経験を通じて、

AI の力で「一人でプロダクトを作る」ことが本当に可能になった

と確信しました。

逆に言えば、みんなが作れるようになった分、

  • どんなアイデアを形にするのか
  • 何に価値があるのか
  • どう差別化するのか

といった “考える力” がますます重要になっていくと思います。

今回は、そうした気づきを得られたという意味でも、とても良い体験でした。

Terraform1.5で追加されたimportブロックを試す

importブロックは宣言的に既存のリソースをTerraform管理下にできるTerraformの構文です。今まではterraform import で既存のリソースをTerraform管理下にできましたが、一つ一つのリソースしかインポートできずに面倒でした。また、今まではできなかったHCLのコードを生成することも可能になっています。
developer.hashicorp.com

実践

EC2のインスタンスAWSマネジメントコンソールから作成し、それをimportブロックでTerraform管理下にします。

まず、importブロックのコードを書きます。toにはインポート先となるresourceブロックのIDを指定します。
idにはインポートする個々のリソースを識別するIDを設定します。これはリソースの種類によって異なります。EC2の場合はインスタンスIDになります。

imports.tf

import {
  to = aws_instance.example
  id = "i-00000000000000000"
}

この状態でterraform planを実行すると、toにあたるインポート先がないためにエラーになります。そして、terraform plan -generate-config-out=generated.tfでコードを生成することができる旨のメッセージが表示されます。親切です。これに従って、HCLのコードを生成します。

EC2の場合は、コードを生成すると、設定がコンフリクトしている旨のエラーが出力されます。

│ Error: Conflicting configuration arguments
│
│   with aws_instance.example,
│   on generated.tf line 14:
│   (source code not available)
│
│ "ipv6_address_count": conflicts with ipv6_addresses
╵
╷
│ Error: Conflicting configuration arguments
│
│   with aws_instance.example,
│   on generated.tf line 15:
│   (source code not available)
│
│ "ipv6_addresses": conflicts with ipv6_address_count

ipv6_address_countipv6_addressesはどちらか一方あればよい値です。コード生成をした場合はどちらも出力されてしまいます。
どちらかの記述を削除して、terraform planterraform applyを実行します。そうすると、importすることができます。

コードの生成は完璧ではありませんが、かなりの部分のコードを補完してくれるため、便利です。

感想

terraform importで行っていた既存リソースのインポートをTerraformのコードでできるようになり、操作性がよくなったと思います。また、コードの生成も便利なので、これからはimportブロックを使った書き方を採用していきたいと思います。

おわりに

Udemy講座を公開しています。AWSやTerraformの入門から実践的な内容までを学べるものになっています。ぜひ受講ください。

ローカル上のAWS LambdaのコードをTerraform化する

ローカル上のAWS LambdaのコードをTerraform化する方法について説明します。
ローカルにあるコードをTerraform化するにあたってはコードのzipファイル化が必要など、そのあたりのポイントを説明します。

説明

以下が全体のコードになります。

lambda.tf

resource "aws_lambda_function" "example" {
  function_name    = "lambda-terraform-example"
  handler          = "main.lambda_handler"
  runtime          = "python3.8"
  filename         = data.archive_file.lambda_function_payload.output_path
  source_code_hash = data.archive_file.lambda_function_payload.output_base64sha256
  role             = aws_iam_role.lambda_exec.arn
}

resource "aws_iam_role" "lambda_exec" {
  name = "lambda_exec_example"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_exec_basic" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
  role       = aws_iam_role.lambda_exec.name
}

data "archive_file" "lambda_function_payload" {
  type        = "zip"
  source_dir  = "${path.module}/src"
  output_path = "${path.module}/lambda_function_payload.zip"
}

src/main.py

import json

def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

aws_lambda_functionのリソースにfilenameとsource_code_hashのパラメータを指定しているのがポイントです。こちらにはLambda関数コードが含まれるZIPアーカイブファイルのパスとハッシュを指定します。Lambda関数のソースコードを含むZIPアーカイブは、data archive_fileブロックで作成され、filenameおよびsource_code_hashパラメータに渡されます。

aws_iam_roleリソースは、Lambda関数が使用するIAMロールを作成します。このロールには、AWS Lambdaによる関数の実行に必要なポリシーが含まれます。最後に、aws_iam_role_policy_attachmentリソースを使用して、作成したIAMロールにAWSLambdaBasicExecutionRoleポリシーをアタッチしています。これは、Lambda関数が必要な最小限の権限を持つようにするためのものです。 path.module はTerraformで使用される予約済み変数の一つで、現在のモジュールのルートディレクトリへの絶対パスを表します。

これでローカル上のAWS LambdaのコードをTerraform化することができます。

おわりに

以下のUdemy講座を公開しています。AWSやTerraformの入門から実践的な内容までを学べるものになっています。ぜひ受講ください。

www.udemy.com