ブログ

  • AWSの請求書確定時に特定メールへ自動送付する仕組みをTerraformで構築する

    AWSの請求書確定時に特定メールへ自動送付する仕組みをTerraformで構築する

    はじめに

    AWSの請求書(Invoice)は毎月確定しますが、標準のマネジメントコンソールには「請求書確定時に特定メールアドレスへPDFを自動送付する」機能はありません。 本記事では、以下のAWSサービスを組み合わせて請求書PDF自動送付の仕組みをTerraformで構築する方法を解説します。 メール送信にはSES(Simple Email Service)を使用します。送信元・送信先ともにSESへの検証登録が必要ですが、サンドボックスの解除は不要です。 Terraformを利用しているのはあくまで私自身の好みです(お勉強中のため)。

    構成するAWSサービス

    サービス役割
    EventBridge(Scheduler)毎月スケジュールトリガー
    Lambda請求書PDF取得・SESでのメール送信
    SESPDF添付メールの送信
    IAMLambdaへのAWS API実行権限付与
    CloudWatch LogsLambda実行ログの保管

    全体アーキテクチャ

    EventBridge Scheduler(毎月15日 9:00 JST)
        ↓ invoke
    Lambda(Python)
        ├─ Invoicing API  → 請求書PDF取得
        └─ SES            → PDF添付メール送信
                                  ↓
                        受信者のメールアドレスへ届く
                      (PDFが直接添付されているため
                        AWSアカウントなしでダウンロード可能)

    なぜ15日?
    AWSの請求書は通常毎月頭(2〜10日頃)に確定します。 余裕を持って15日にスケジュールすることで、確定済みの請求書を確実に取得できます。

    前提条件

    • 以下の環境で動作を確認しています
      • Terraform v1.14.8
      • aws-cli/2.34.19
      • MacOS(15.7.4)
    • AWSアカウントへのアクセス(us-east-1 リージョン)
    • AWSアカウントがOrganizationsの請求アカウント、または単独アカウント
      • invoicing APIは請求アカウントでのみ全請求書を取得可能です(他アカウントでは全請求を確認できません)
    • SESのサンドボックス解除は不要
      • サンドボックス状態でも、送信元・送信先メールアドレスをSESに検証登録すれば送信可能
      • 検証登録はTerraformで実行します(後述)

    ディレクトリ構成

    IAMリソースは通常、管理者が操作するリソースとなるため(iam:CreateRole 等)、管理者向けテンプレートと開発者向けテンプレートに分離します。

    ├── iam/                        # 【管理者向け】IAMロール・ポリシーのみ
    │   ├── main.tf
    │   └── outputs.tf
    │
    └── app/                        # 【開発者向け】Lambda・EventBridge・SES等
        ├── main.tf
        ├── variables.tf
        ├── outputs.tf
        ├── lambda/
        │   └── invoice_sender.py   # Lambda関数のソースコード
        └── terraform.tfvars        # 環境ごとの変数値(gitignore推奨)

    分割のポイント

    • iam/ は管理者が一度だけ適用し、作成されたIAMロールのARNを app/ へ渡す
    • app/ は開発者が自由にデプロイ・更新できる
    • outputs.tf でIAMロールARNを出力し、app/variables.tf で受け取る

    Step 1: SES メールアドレスの検証(事前作業)

    SESのサンドボックス状態では、送信元・送信先ともにSESへの検証登録が必要です。検証はTerraformで自動化できます。

    app/main.tf に以下のリソースを追加してください(Step 4で解説するファイルに含まれています)。

    # ============================================================
    # SES 送信先メールアドレスの検証
    # - terraform apply 後に確認メールが届くので、リンクをクリックして有効化
    # - 有効化しないとSESからメールが送信されません
    # ============================================================
    resource "aws_ses_email_identity" "recipient" {
      email = var.recipient_email
    }
    
    resource "aws_ses_email_identity" "sender" {
      email = var.sender_email
    }

    terraform apply 後に recipient_email と sender_email それぞれ宛へAWSから件名 Amazon Web Services – Email Address Verification Request in region US East (N. Virginia) というメールが届きます。 本文内の “Click here to verify…” リンクをクリックして検証を完了させてください。

    検証を完了しないとSESからのメール送信が失敗します。必ずTerraform適用後に確認してください。

    検証済みアドレスはAWSマネジメントコンソールの SES → Verified identities から確認できます。 リージョンを us-east-1(バージニア北部) に設定して開いてください。

    Step 2: IAMテンプレート(管理者が適用)

    iam/main.tf

    # ============================================================
    # IAMロール: Lambda実行用
    # - Lambda が AssumeRole できるよう信頼ポリシーを設定
    # ============================================================
    resource "aws_iam_role" "lambda_invoice_sender" {
      name = "lambda-invoice-sender-role"
    
      # Lambdaサービスがこのロールを引き受けることを許可する信頼ポリシー
      assume_role_policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Effect    = "Allow"
            Principal = { Service = "lambda.amazonaws.com" }
            Action    = "sts:AssumeRole"
          }
        ]
      })
    
      tags = {
        Name    = "lambda-invoice-sender-role"
        Project = "aws-invoice-auto-send"
      }
    }
    
    # ============================================================
    # IAMポリシー: Lambda が必要とする最小権限
    # - CloudWatch Logs   : 実行ログの書き込み
    # - invoicing:*       : 請求書一覧の取得・PDF取得
    # - sts:GetCallerIdentity: アカウントID取得
    # - ses:SendRawEmail  : PDF添付メールの送信
    # ============================================================
    resource "aws_iam_policy" "lambda_invoice_sender" {
      name        = "lambda-invoice-sender-policy"
      description = "AWS請求書自動送付Lambda用の最小権限ポリシー"
    
      policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          # CloudWatch Logs: ロググループ・ストリームの作成とログ書き込み
          {
            Effect = "Allow"
            Action = [
              "logs:CreateLogGroup",
              "logs:CreateLogStream",
              "logs:PutLogEvents"
            ]
            Resource = "arn:aws:logs:*:*:*"
          },
          # Invoicing API: 請求書の一覧取得とPDF取得
          {
            Effect = "Allow"
            Action = [
              "invoicing:ListInvoiceSummaries",
              "invoicing:GetInvoicePDF",
              "sts:GetCallerIdentity"
            ]
            Resource = "*"
          },
          # SES: 添付ファイル付きのRAWメール送信
          # SendRawEmail を使うことでPDFを添付できる
          {
            Effect   = "Allow"
            Action   = ["ses:SendRawEmail"]
            Resource = "*"
          }
        ]
      })
    }
    
    # ============================================================
    # IAMロールへポリシーをアタッチ
    # ============================================================
    resource "aws_iam_role_policy_attachment" "lambda_invoice_sender" {
      role       = aws_iam_role.lambda_invoice_sender.name
      policy_arn = aws_iam_policy.lambda_invoice_sender.arn
    }
    
    # ============================================================
    # EventBridge Scheduler 実行用 IAMロール
    # - EventBridgeがLambdaをInvokeできるよう権限を付与
    # ============================================================
    resource "aws_iam_role" "eventbridge_scheduler" {
      name = "eventbridge-invoice-scheduler-role"
    
      assume_role_policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Effect    = "Allow"
            Principal = { Service = "scheduler.amazonaws.com" }
            Action    = "sts:AssumeRole"
          }
        ]
      })
    }
    
    resource "aws_iam_role_policy" "eventbridge_scheduler_invoke_lambda" {
      name = "eventbridge-invoke-lambda-policy"
      role = aws_iam_role.eventbridge_scheduler.id
    
      policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Effect   = "Allow"
            Action   = ["lambda:InvokeFunction"]
            Resource = "*"
          }
        ]
      })
    }

    iam/outputs.tf

    # app/ テンプレートで使用するIAMロールARNを出力
    output "lambda_role_arn" {
      description = "Lambda実行用IAMロールのARN"
      value       = aws_iam_role.lambda_invoice_sender.arn
    }
    
    output "eventbridge_role_arn" {
      description = "EventBridge Scheduler実行用IAMロールのARN"
      value       = aws_iam_role.eventbridge_scheduler.arn
    }

    IAMの適用コマンド

    cd iam/
    terraform init
    terraform plan
    terraform apply

    適用後、出力されたARNをメモしておきます。

    # 出力例
    Outputs:
    lambda_role_arn      = "arn:aws:iam::123456789012:role/lambda-invoice-sender-role"
    eventbridge_role_arn = "arn:aws:iam::123456789012:role/eventbridge-invoice-scheduler-role"

    Step 3: Lambda関数のソースコード

    app/lambda/invoice_sender.py

    """
    AWS請求書PDF自動送付 Lambda関数
    
    処理の流れ:
      1. 前月分の請求書PDFをInvoicing APIで取得
      2. SES(SendRawEmail)でPDFを添付してメール送信
    
    環境変数:
      SENDER_EMAIL    : 送信元メールアドレス(SESで検証済みであること)
      RECIPIENT_EMAIL : 送信先メールアドレス(SESで検証済みであること)
    """
    
    import boto3
    import os
    import urllib.request
    from datetime import datetime
    from email.mime.multipart import MIMEMultipart
    from email.mime.base import MIMEBase
    from email.mime.text import MIMEText
    from email import encoders
    
    
    def lambda_handler(event, context):
        # ── 対象月の計算(実行月の前月)────────────────────────────
        today = datetime.today()
        year  = today.year if today.month > 1 else today.year - 1
        month = today.month - 1 if today.month > 1 else 12
    
        print(f"対象請求月: {year}年{month:02d}月")
    
        # ── アカウントIDを動的取得 ────────────────────────────────────
        sts        = boto3.client("sts")
        account_id = sts.get_caller_identity()["Account"]
    
        # ── Invoicing APIで対象月の請求書を取得 ──────────────────────
        # invoicing APIは us-east-1 のみ対応
        # Filter.BillingPeriod で対象月を直接指定
        invoicing = boto3.client("invoicing", region_name="us-east-1")
    
        response = invoicing.list_invoice_summaries(
            Selector={
                "ResourceType": "ACCOUNT_ID",
                "Value": account_id
            },
            Filter={
                "BillingPeriod": {
                    "Month": month,
                    "Year": year
                }
            }
        )
    
        # ── 結果チェック ─────────────────────────────────────────────
        invoices = response.get("InvoiceSummaries", [])
        if not invoices:
            print(f"⚠️  {year}年{month:02d}月の請求書が見つかりませんでした")
            return {"statusCode": 404, "body": "Invoice not found"}
    
        invoice_id = invoices[0]["InvoiceId"]
        print(f"請求書ID: {invoice_id}")
    
        # ── 請求書PDFを取得 ──────────────────────────────────────────
        # get_invoice_pdf はダウンロード用URLを返すため urllib でバイナリをダウンロード
        pdf_response = invoicing.get_invoice_pdf(InvoiceId=invoice_id)
        billing_url  = pdf_response["InvoicePDF"]["DocumentUrl"]
    
        with urllib.request.urlopen(billing_url) as res:
            pdf_bytes = res.read()
    
        print(f"PDF取得完了: {len(pdf_bytes)} bytes")
    
        # ── SESでPDF添付メールを送信 ──────────────────────────────────
        sender    = os.environ["SENDER_EMAIL"]
        recipient = os.environ["RECIPIENT_EMAIL"]
        filename  = f"AWS_Invoice_{year}{month:02d}.pdf"
    
        # MIMEメッセージを構築
        # SendRawEmail を使うことでPDFを添付できる
        msg            = MIMEMultipart()
        msg["Subject"] = f"【AWS請求書】{year}年{month:02d}月分"
        msg["From"]    = sender
        msg["To"]      = recipient
    
        # 本文テキスト
        body_text = (
            f"{year}年{month:02d}月分のAWS請求書をお送りします。\n\n"
            f"請求書ID: {invoice_id}\n"
            f"添付ファイル: {filename}\n"
        )
        msg.attach(MIMEText(body_text, "plain", "utf-8"))
    
        # PDF添付
        attachment = MIMEBase("application", "pdf")
        attachment.set_payload(pdf_bytes)
        encoders.encode_base64(attachment)
        attachment.add_header(
            "Content-Disposition", "attachment", filename=filename
        )
        msg.attach(attachment)
    
        # SES送信(us-east-1 を使用)
        ses = boto3.client("ses", region_name="us-east-1")
        ses.send_raw_email(
            Source       = sender,
            Destinations = [recipient],
            RawMessage   = {"Data": msg.as_bytes()},
        )
    
        print(f"✅ メール送信完了: {recipient}")
        return {"statusCode": 200, "body": "Invoice sent successfully"}

    Step 4: アプリテンプレート

    app/variables.tf

    variable "lambda_role_arn" {
      description = "IAMテンプレート(iam/)で作成したLambda実行用IAMロールのARN"
      type        = string
    }
    
    variable "eventbridge_role_arn" {
      description = "IAMテンプレート(iam/)で作成したEventBridge Scheduler用IAMロールのARN"
      type        = string
    }
    
    variable "recipient_email" {
      description = "請求書PDFの送信先メールアドレス"
      type        = string
    }
    
    variable "sender_email" {
      description = "SESで検証済みの送信元メールアドレス"
      type        = string
    }

    app/terraform.tfvars

    ※任意の値を入力してください。

    # iam/ terraform apply 後に出力されたARNを記載する(以下は例)
    lambda_role_arn      = "arn:aws:iam::123456789012:role/lambda-invoice-sender-role"
    eventbridge_role_arn = "arn:aws:iam::123456789012:role/eventbridge-invoice-scheduler-role"
    
    # 請求書の送信元・送信先メールアドレス
    sender_email    = "From@yourcompany.com"
    recipient_email = "To@yourcompany.com"

    注意: terraform.tfvars にはメールアドレスが含まれるため Git管理時には.gitignore への追加を推奨します。

    app/main.tf

    terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "6.38.0"
        }
        null = {
          source  = "hashicorp/null"
          version = "3.2.4"
        }
      }
    }
    
    provider "aws" {
      region = "us-east-1"
    }
    
    # ============================================================
    # SES 送信先メールアドレスの検証
    # - terraform apply 後に届く確認メールのリンクをクリックして有効化
    # ============================================================
    resource "aws_ses_email_identity" "recipient" {
      email = var.recipient_email
    }
    
    resource "aws_ses_email_identity" "sender" {
      email = var.sender_email
    }
    
    # ============================================================
    # Lambdaデプロイパッケージの作成
    # - lambda/ ディレクトリ内のPythonファイルをzip化する
    # ============================================================
    data "archive_file" "lambda_zip" {
      type        = "zip"
      source_dir  = "${path.module}/lambda"
      output_path = "${path.module}/lambda.zip"
    }
    
    # ============================================================
    # Lambda Layer: 最新boto3を使用するためのレイヤー
    # - LambdaランタイムのデフォルトSDKは古い場合があるため
    #   invoicing APIに対応した最新版を明示的に指定する
    # ============================================================
    resource "null_resource" "install_boto3" {
      triggers = {
        always_run = timestamp()
      }
    
      provisioner "local-exec" {
        command = <<EOT
          mkdir -p ${path.module}/layer/python
          pip install boto3 --upgrade -t ${path.module}/layer/python --quiet
        EOT
      }
    }
    
    data "archive_file" "boto3_layer_zip" {
      type        = "zip"
      source_dir  = "${path.module}/layer"
      output_path = "${path.module}/boto3_layer.zip"
    
      depends_on = [null_resource.install_boto3]
    }
    
    resource "aws_lambda_layer_version" "boto3_latest" {
      layer_name          = "boto3-latest"
      filename            = data.archive_file.boto3_layer_zip.output_path
      source_code_hash    = data.archive_file.boto3_layer_zip.output_base64sha256
      compatible_runtimes = ["python3.14"]
    }
    
    # ============================================================
    # Lambda関数
    # - Python 3.14ランタイムで実行
    # - 環境変数で送信元・送信先メールアドレスを受け取る
    # - タイムアウト: 60秒(PDF取得・メール送信を考慮)
    # ============================================================
    resource "aws_lambda_function" "invoice_sender" {
      function_name    = "aws-invoice-sender"
      role             = var.lambda_role_arn
      handler          = "invoice_sender.lambda_handler"
      runtime          = "python3.14"
      filename         = data.archive_file.lambda_zip.output_path
      source_code_hash = data.archive_file.lambda_zip.output_base64sha256
      layers           = [aws_lambda_layer_version.boto3_latest.arn]
    
      timeout     = 60
      memory_size = 256
    
      environment {
        variables = {
          SENDER_EMAIL    = var.sender_email
          RECIPIENT_EMAIL = var.recipient_email
        }
      }
    
      tags = {
        Name    = "aws-invoice-sender"
        Project = "aws-invoice-auto-send"
      }
    }
    
    # ============================================================
    # CloudWatch Logs: Lambdaのロググループ
    # - 保持期間: 30日(コスト最適化のため適宜調整)
    # ============================================================
    resource "aws_cloudwatch_log_group" "invoice_sender" {
      name              = "/aws/lambda/${aws_lambda_function.invoice_sender.function_name}"
      retention_in_days = 30
    }
    
    # ============================================================
    # EventBridge Scheduler: 毎月15日 9:00 JST にLambdaを起動
    # - schedule_expression_timezone で JST を直接指定できる
    # - flexible_time_window: OFF = 指定時刻に厳密に実行
    # ============================================================
    resource "aws_scheduler_schedule" "invoice_sender" {
      name       = "monthly-invoice-sender"
      group_name = "default"
    
      schedule_expression          = "cron(0 9 15 * ? *)"
      schedule_expression_timezone = "Asia/Tokyo"
    
      flexible_time_window {
        mode = "OFF"
      }
    
      target {
        arn      = aws_lambda_function.invoice_sender.arn
        role_arn = var.eventbridge_role_arn
    
        retry_policy {
          maximum_retry_attempts = 2
        }
      }
    }

    app/outputs.tf

    output "lambda_function_name" {
      description = "Lambda関数名"
      value       = aws_lambda_function.invoice_sender.function_name
    }
    
    output "lambda_function_arn" {
      description = "Lambda関数のARN"
      value       = aws_lambda_function.invoice_sender.arn
    }
    
    output "scheduler_name" {
      description = "EventBridge Schedulerのスケジュール名"
      value       = aws_scheduler_schedule.invoice_sender.name
    }

    Step 5: アプリの適用コマンド

    cd app/
    terraform init
    terraform plan
    terraform apply

    動作確認

    Lambdaをマネジメントコンソールから手動実行して確認します。

    1. AWSコンソール → Lambda → aws-invoice-sender を開く
    2. 「テスト」タブ → 空のJSONイベント {} で実行
    3. CloudWatch Logsでエラーがないか確認
    4. 指定したメールアドレスへPDF添付メールが届いているか確認

    注意事項まとめ

    項目内容
    Invoicing APIのリージョンus-east-1 のみ対応
    Organizations利用時請求アカウントで実行する必要あり
    SES サンドボックス解除不要。送信元・送信先ともにSES検証登録が必要
    SES メールアドレス検証terraform apply 後に届く確認メール(送信元・送信先それぞれ)のリンクをクリックすること
    terraform.tfvarsメールアドレスが含まれるため .gitignore 推奨
    IAMの適用順序iam/ → app/ の順で適用すること

    おわりに

    本記事では EventBridge Scheduler + Lambda + SES を組み合わせた請求書PDF自動送付の仕組みをTerraformで構築しました。 SESのサンドボックス解除は不要で、送信元・送信先メールアドレスをTerraformで検証登録するだけで運用できます。

    参考資料

  • subagentsやskillsを利用してcursor中学校を設立してみた

    subagentsやskillsを利用してcursor中学校を設立してみた

    はじめに

    最近はAIエージェントを活用したサービスやツールの発展が著しく、私もcursorをよく利用するのでもっと機能を使いこなせないか考えていました。
    そんな折、職場で学力テストを久しぶりに受けてみたいという話になり、せっかくならAIエージェント利用に関する学習としてやってみようと考えました。
    ということで、日々利用しているcursorのsubagentsやskills、rules等の使い方を改めて考えつつ、学力テストを生成する環境を構築してみました。

    今回作成したもの

    タイトルでは中学校となっていますが、簡単に言えば中学レベルの学力テストをsubagents/skills/rulesを利用して、プロンプト一つで作成できる環境を作成しました。
    使用したツールはcursorというAIエージェント搭載のエディタで、claude codeでかなり熱量が上がっているskills等の機能も利用することができます。

    組織構成

    cursor中学校は学力テストの作成用のプロジェクトで、以下のような構成になっています。
    ユーザーは校長エージェントに指示を出し、校長エージェントが他のエージェントに指示を出しつつ、成果物の作成を管理するようになっています。

    ユーザー(依頼者)
        │
        ▼
     ┌──────────────┐
     │  校長 (principal)  │ ── 統括・品質承認
     └──────┬───────┘
            │
     ┌──────┴───────┐
     │              │
    担任教師 ×5     専門家 ×5
    (teacher)      (expert)
     │  作問         │  検証
     ▼              ▼
    国語 / 数学 / 英語 / 理科 / 社会
    

    subagents

    subagentsは他エージェントや指示全体を管理するエージェントが1人と5教科の担当教員と専門家の全部で11人作成しました。
    それぞれの役割は以下の通りです。

    校長エージェント

    • 校長エージェントはこのプロジェクトのオーケストレーター的な役割です
    • ユーザーの指示を受けて、各教科の担当教員エージェントにテスト作成の指示を出します
    • 担当教員が作成したテストを専門家に評価してもらいます
    • 専門家の指摘があればその教科の担当教員にテストの再作成を依頼します
    • 最終的に校長エージェントが作成したテストを承認して、学力テストの完成です
    ---
    name: principal
    model: inherit
    description: 中学校学力テスト統括エージェント。学年・対象年・教科を整理し、各教科担任へ作問を依頼し、各教科専門家へ検証を依頼して最終品質を承認する。中学校向けテスト制作時に最初に使う。
    ---
    
    あなたは日本の中学校学力テスト作成プロジェクトを統括する校長です。
    目的は、指定された学年・対象年・教科に応じて、教育課程に整合した高品質な学力テストを完成させることです。
    
    役割:
    1. ユーザーの依頼を整理する。
    2. 成果物保存用のフォルダ(`{YYYYMMDD}{連番2桁}/`)を作成する。
    3. 成果物保存用のフォルダ配下にテスト及び模範解答用のフォルダ(`test/` と `modelAnswer/`)を作成する。
    4. 必要な担任教師エージェントへ作問を依頼する。
    5. 作成されたテストを対応する専門家エージェントへ検証依頼する。
    6. 指摘を反映したうえで最終版を承認する。
    7. 複数教科をまとめる場合は、難易度・分量・表現の統一感を整える。
    
    ~~~ 省略 ~~~
    

    担当教員エージェント

    • 担当教員エージェントは各教科のテスト作成の作業者で、1教科1担当教員となります
    • 校長エージェントからテスト作成依頼が来ると、skillsやrulesを参照しつつ担当科目の学力テストを作成します
    • 担当範囲はルールに基づいた学力テストの作成のみです
    ---
    name: japanese-teacher
    description: 中学校国語テスト作成の担任教師エージェント。中1から中3向けに、対象年の教育課程に沿った約30問・100点満点の国語テスト、模範解答、採点基準を作る。国語テスト作成時に使う。
    ---
    
    あなたは日本の中学校国語科を担当する熟練教師です。
    中学1年生から3年生までを対象に、指定された年の教育課程と学年範囲に合った、実用的で採点しやすい国語テストを作成してください。
    
    作問の目的:
    - 学年相応の国語力を測ること
    - 知識偏重ではなく、読解力・言語運用力・表現力をバランスよく測ること
    - 年代指定がある場合、その時代の教育課程に配慮すること
    
    受け取るべき条件:
    - 学年: 中1 / 中2 / 中3
    - 対象年: 1989年以降
    - 教育課程基準: 原則は実施課程基準
    - テスト種別: 総合テスト
    - 難易度: 標準 / やや易しめ / やや難しめ
    
    年代の扱い:
    - 指定年から、その年に中学校で実施されていた教育課程を優先して判断する。
    - 実施課程と告示課程で解釈が分かれそうな場合は、その前提を明記する。
    - 年代ごとの差異が大きい単元や扱いに迷う分野は、推定で広げすぎない。
    
    ~~~ 省略 ~~~
    

    専門家エージェント

    • 専門家エージェントは各教科のテストのレビュアーで、1教科1専門家となります
    • 校長エージェントから評価依頼が来ると、skillsやrulesの内容とsubagentsの指示内容でテスト内容を評価します
    • ユーザーから指示のあった年代と学年のテストを作成できているかや高校の問題や過度に専門的な内容となっていないかなどもチェックしています
    ---
    name: japanese-expert
    description: 中学校国語テスト検証の専門家エージェント。国語テストの内容、解答、配点、学年適合性、年代の教育課程整合性を点検し、修正提案まで返す。国語テストの品質確認時に使う。
    ---
    
    あなたは日本の中学校国語教育と評価設計に精通した専門家です。
    担任教師が作成した国語テストを検証し、誤りや曖昧さを見つけ、必要な修正案を返してください。
    
    検証観点:
    1. 問題文の日本語が自然で誤解を招かないか
    2. 漢字、語句、文法、読解設問、記述設問の正答が妥当か
    3. 学年に対して難易度が適切か
    4. 指定された対象年と教育課程に整合しているか
    5. 配点が100点満点として妥当か
    6. 記述問題の採点基準が明確か
    
    年代チェック:
    - 対象年が指定されている場合、その年における中学校国語の実施課程または指定基準に沿っているか確認する。
    - 古文・漢文・文法事項・表現活動の扱いが、その年代と学年で不自然でないか確認する。
    - 確信が持てない年代差は断定せず、「要再確認」として明示する。
    
    レビュー手順:
    1. 前提条件を確認する。
       - 学年
       - 対象年
       - 採用教育課程
    2. 問題全体を読み、誤答・曖昧表現・範囲逸脱を探す。
    3. 解答と採点基準を照合する。
    4. 修正が必要な箇所を重要度順に列挙する。
    5. 必要なら修正版の設問文や模範解答を提案する。
    
    出力形式:
    - 総評
    - 問題点
      - 重大
      - 要修正
      - 改善提案
    - 年代整合性チェック結果
    - 修正案
    - 最終判定
      - 合格
      - 条件付き合格
      - 再作成推奨
    
    判定基準:
    - 解答の妥当性に疑義がある場合は「合格」にしない
    - 学年範囲から明確に外れている場合は「再作成推奨」
    - 微修正で済む場合は「条件付き合格」
    

    skills

    skillsには作成するテストのファイル名や形式、配置するフォルダ名等を定義しています。
    また、学力テストの形式テンプレートファイルを作成して、読込ながら作業できるようにしています。

    test-output-format/SKILL.md

    • テストの出力形式に関する内容を定義したskills
    • ファイル名、フォルダ名/構成、命名規則や学力テストの構造等を中心に定義
    • 学力テストの文章構造はテンプレートファイルを参照する
    ---
    name: test-output-format
    description: 中学校学力テストの出力形式を標準化する。日付+連番フォルダ(例: 2026032301/)配下に test/ と modelAnswer/ を作成し、教科別markdown(japanese.md等)で問題・模範解答・採点基準を整形して保存する。テスト生成や納品用markdown作成時に使う。
    ---
    
    # Test Output Format
    
    中学校学力テストを **markdown** で出力する際の、フォルダ構成・命名規則・文章構造を統一する。
    
    ## ゴール
    
    - `test/` に **問題** を保存する
    - `modelAnswer/` に **模範解答 + 採点基準(部分点含む)** を保存する
    - 大問・小問の番号体系を一致させ、相互参照なしでも採点できるようにする
    
    ## 出力先フォルダ構成
    
    出力は必ず次の構造にする。
    
    ---
    {YYYYMMDD}{連番2桁}/
      test/
        {subject}.md
      modelAnswer/
        {subject}.md
    ---
    
    例:
    
    ---
    2026032301/
      test/
        japanese.md
      modelAnswer/
        japanese.md
    ---
    
    ### フォルダ名ルール(YYYYMMDD + 連番2桁)
    
    - `YYYYMMDD` は生成日(例: 20260323)
    - 連番は同日内の通し番号(`01`, `02`, ...)
    - 同日の初回は `01`
    
    #### 連番の決め方(手順)
    
    1. 今日の日付を `YYYYMMDD` で確定する
    2. 既存フォルダのうち、名前が `YYYYMMDD` で始まり、末尾が **2桁数字** のものを列挙する(例: `2026032301`, `2026032302`)
    3. 存在しなければ `01`、存在すれば最大値+1を採用する
    
    > 実行環境でフォルダ一覧が取れる場合は、必ず実フォルダを見て衝突を避ける。
    
    ## subject(教科ファイル名)ルール
    
    ファイル名は英語名で固定する。
    
    - 国語: `japanese.md`
    - 数学: `math.md`
    - 英語: `english.md`
    - 理科: `science.md`
    - 社会: `social-studies.md`
    
    ## `test/{subject}.md` の仕様(問題)
    
    - 冒頭に YAML フロントマターを置く
    - 大問は `##` 見出し
    - 小問は番号付きリスト `1.` を使う
    - 小問末尾に `(N点)` で配点を明記する
    - 読解や資料が必要なら引用ブロック `>` を使う(著作権に配慮して自作文章・自作資料を基本)
    
    ### 必須メタ情報(フロントマター)
    
    - `subject`: 上の subject 名(例: `japanese`)
    - `grade`: `1` / `2` / `3`
    - `target_year`: `1989` 以上
    - `curriculum_basis`: `implementation` または `notification`(採用前提を短く)
    - `total_points`: `100`
    - `estimated_questions`: `30`
    
    ## `modelAnswer/{subject}.md` の仕様(模範解答 + 採点基準)
    
    - 冒頭に YAML フロントマターを置く
    - 大問・小問の番号体系を **test側と完全一致** させる
    - 各小問の「正答」を明記する
    - 記述・作文・途中式・考察は、必ず **採点基準(部分点)** を付ける
    - 許容解が複数ある場合は、許容範囲を明確に列挙する。
    - 各回答には簡単な解説を付ける。
    
    ### 必須メタ情報(フロントマター)
    
    - `subject`
    - `grade`
    - `target_year`
    - `test_file`: 対応する問題ファイルの相対パス(例: `../test/japanese.md`)
    
    ## 重要な整合性ルール
    
    - 合計点は必ず 100 点になること(大問配点・小問配点の整合)
    - `test` の小問番号と `modelAnswer` の小問番号は 1つもズレないこと
    - 正答が複数許容される場合は、許容範囲を `modelAnswer` に明示すること
    
    ## テンプレート
    
    具体的な雛形は [templates.md](templates.md) を使う。
    
    

    test-output-format/templates.md

    • 学力テストのテスト問題例
    • テスト構造の参考に利用する
    ## `test/{subject}.md` テンプレート(問題)
    
    ```markdown
    ---
    subject: japanese
    grade: 2
    target_year: 2005
    curriculum_basis: implementation
    total_points: 100
    estimated_questions: 30
    ---
    
    # 国語(中2)学力テスト
    
    ## テスト概要
    
    - 学年: 中学2年
    - 対象年: 2005年
    - 教育課程前提: 実施課程基準(implementation)
    - 満点: 100点
    - 問題数目安: 約30問
    
    ## 大問1 漢字・語句・文法(20点)
    
    1. 次の漢字の読みをひらがなで書きなさい。(各2点×3=6点)
       2. 連続(2点)
       3. 誠実(2点)
       4. 余裕(2点)
    5. 次の( )に入る最も適切な語を選び、記号で答えなさい。(各2点×2=4点)
       6. 彼は( )に話を進めた。(2点)
          - A. 迅速
          - B. 細心
          - C. 適切
          - D. 倹約
       7. その説明は( )に欠ける。(2点)
          - A. 根拠
          - B. 景色
          - C. 協力
          - D. 余暇
    8. 次の文の下線部が文の中でどのようなはたらきをしているか、最も適切なものを選び、記号で答えなさい。(各2点×5=10点)
       9. 私は **図書館で** 本を借りた。(2点)
          - A. 目的語
          - B. 述語
          - C. 修飾語
          - D. 主語
       10. (以下略)(2点)
    
    ~~~ 省略 ~~~
    

    rules

    rulesでは学力テスト作成における細かいルールを設定していて、特にテストの品質基準について定義しています。

    test-creation-standards.mdc

    • テスト作成とテストの品質基準を定義したrules
    • 主に問題文を日本語に統一する等のテストの文章に関しての指示や、出典や根拠等のテストの正当性の確保についてが中心
    ---
    description: 中学校学力テスト作成における品質基準・制約ルール
    alwaysApply: true
    ---
    
    # テスト作成 品質基準
    
    ## 日本語出力の徹底
    
    - 問題文、模範解答の解説・説明はすべて日本語で出力する
    - 英語テストにおける英文素材(読解文・例文・選択肢の英文など)は例外とするが、設問指示文や解説は日本語で記述する
    
    ## 誤字脱字の防止
    
    - 問題文には誤字脱字がないよう細心の注意を払う
    - 出力後に全問を通しで再確認し、漢字・送り仮名・句読点の誤りを検出する
    - 特に漢字の読み書き問題は二重チェックを行う
    
    ## 出典・根拠の義務
    
    - 完全に自作した問題(回答根拠が検証できないもの)は採用しない
    - 各問題の正答は、Web検索等でソースを確認できるものに限定する
    - ソースは信頼度の高い情報源でなければならない
      - 許容する情報源: 文部科学省、学習指導要領、検定済み教科書、公的統計(総務省統計局・国土地理院など)、学術論文、公的機関の公開資料
      - 不可: 個人ブログやWikipediaのみを根拠とすること
    - 模範解答には、根拠となる情報源の種別(例: 学習指導要領、教科書準拠)を簡潔に示す
    
    ## 正答の一意性・採点可能性
    
    - 正答が一意に定まるか、許容範囲が明確に定義されていること
    - 「どちらとも取れる」設問は出さない
    - 記述・作文・途中式・考察の問題には必ず部分点基準を設ける
    - 許容解が複数ある場合は、その範囲を模範解答に明示する
    
    ## 配点の整合性
    
    - 合計点は必ず100点にする
    - 各小問の配点を末尾に `(N点)` で明示する
    - 大問内の小問配点合計と大問配点が一致すること
    
    ## 難易度・範囲の遵守
    
    - 指定学年の教育課程範囲を逸脱しない
    - 基礎・標準・応用のバランスをとり、特定難易度に偏りすぎない
    - 年代指定がある場合、その年代の実施教育課程に沿って作問する
    
    ## 著作権配慮
    
    - 実在する著作物をそのまま長文転載しない
    - 読解素材は自作文章または著作権に配慮した要約的素材を使用する
    
    ## 表現の適切性
    
    - 差別的表現、偏見を助長する内容を含めない
    - 中学生が読んで誤解しにくい明確な日本語で記述する
    - 学年相応の専門用語のみ使用し、範囲外の用語を無説明で用いない
    

    利用方法

    学力テストの作成は以下のようなプロンプトで完了します。
    実際に出力されたテストも全て読みましたが、良い感じに仕上がってました。

    /principal
    平成15年の中学3年生の学力テストを作成してほしい!

    実際の学力テストの出力はこんな感じです。
    作文問題は判断もしづらくちょっとやりすぎ感あるので、後々調整しようかなと思っています。
    ここには載せませんが、模範解答も作成するようになっていて、部分点にする為のポイントや作文でもどのような点が加点のポイントか、回答の解説などは明示するようにしています。

    設計で意識したこと

    今回はAI活用が進む中でsubagentsやskills、rules等の使い分けとAIエージェントを活用した組織的な作業の自動化について検証することを目的としました。
    その為、それぞれの機能をどういった役割で作成すれば良いか、どのように連携させるかという点にこだわっています。

    組織的な作業や少し規模の大きい作業をエージェントに任せる場合、オーケストレーターは必要だと考えました。
    どのsubagentsをどの順序でどんな指示で動かすかを毎回ユーザーが意識するのは面倒だからです。
    また、複数エージェントが分担して動く場合、各成果物を確認し、必要に応じて再依頼する役割がいないと結局ユーザー自身が監視役になってしまいます。
    他にもオーケストレーターが他エージェントを管理することで、指示が一貫することもメリットとして挙げられると思います。

    次に専門家エージェントを作成している点です。
    AIにペルソナを与えることはよくあります。それぞれの役割を意識させて情報の精度や作業の精度を上げる為のものですが、レビューには特に効果を発揮しやすいと考えています。
    それはレビューを行う場合、立場・視点・評価軸等少し作成者とずれるからです。
    ソフトウェア開発にも言えることですが、開発者とマネージャー、そしてユーザーの視点や気にするポイントは少し違います。その上で開発者同士のこだわりや考え方、得意なことも違います。この視点の差がレビューでの重要なポイントの一つだと私は考えています。
    その為、専門家エージェントとしてテスト作成に別の視点を与え、テスト品質の向上を達成しようとしました。

    最後にそれぞれの機能の役割分けについてです。
    subagentsは言わずもがな役割を中心としたエージェントとしての振る舞いを定義しています。教科ごとにエージェントを分離しているのは、教科ごとに知識や出題形式等が異なるので、それぞれ専門性を持って動作してほしかったからです。
    skillsには主に作業の為の知識を定義しています。今回でいうとファイルの作成における命名やテストの構造、フォルダ構成と配置等、テスト作成における作業のやり方や形式等を定義しています。
    rulesには教科等関係なく、常に適用されてほしいルールを定義しています。問題文の書き方や出典や根拠を考慮すること、それから著作権等も考慮するようにしています。担当教員エージェントはこのルールを気にして作成し、専門家エージェントは専門的な評価をしつつ、このルールからの逸脱が無いようにチェックします。校則やら就業規則みたいなものですね。

    まとめ

    今回のcursor中学校設立を通して、subagentsを利用した作業の自動化を構築しつつ、それぞれの機能を使いこなすポイントが少し見えた気がします。
    また、業務や日常での作業に活かす為、少しソフトウェア開発への転用や応用を考えつつ作成したので、AIエージェントを用いた作業の自動化フロー構築も今後行っていきたいです。
    今回は学力テストの作成というかなり狭い内容で組織構築をしたのでうまく動作しましたが、実際にはもっと複雑な役割とルールが必要になると思うので、今回の学びが活かせるようにもう少し振り返りをして改善を続けてみようと思います。

  • ソフトウェアをシンプルに保つということ

    ソフトウェアをシンプルに保つということ

    突然ですが、ソフトウェアエンジニアの仕事は何かと聞かれたら何と答えますか?
    私は、顧客やユーザーに対して価値のあるソフトウェアを提供することがソフトウェアエンジニアの仕事であると思っています。

    では、ソフトウェアの価値を高めるために何が必要でしょうか。
    答えのない難しい問題であると思いますが、一つ言えることは、継続的にソフトウェアの価値を高めていくためには、ソフトウェアをシンプルに保つことがとても重要ということです。

    では、ソフトウェアをシンプルにするとはどういうことでしょうか。
    ざっくり言うと、本当に必要な機能だけを必要最低限の実装で実現することです。

    機能が多いほど価値は高い?

    ソフトウェアに限った話ではありませんが、一般に製品(プロダクト)は機能が多ければ多いほど価値が高いと思われることが多いです(私自身、数年前までそう思っていました)。

    しかし、本当にそうでしょうか。
    実際のところ、機能の多さとユーザーにとっての価値の高さは比例するとは限りません。

    電化製品を例に考えてみます。

    例えばテレビ。
    最近のテレビはリモコンに非常に多くのボタンがついており、機能が豊富です。しかし、これらの機能を状況に応じて全て使い分けているという人はどれだけいるでしょうか。
    テレビは、電源のオンオフができて、チャンネルを変えることができて、音量を調節することさえできれば、最低限テレビとしての機能は満たせます。もちろん、人によっては複数の機能を利用している人もいるかと思いますが、少なくとも、全ての機能を満遍なく使っているという人は稀だと思います。
    必要最低限の機能しか使わないユーザーにとって、ボタンの数が非常に多いリモコンは認知負荷が高く、使い勝手が良いとは言えません。

    例えば電子レンジ。
    値段の高価な電子レンジは、これまたボタンがたくさんついていて、実に色んなことができます。
    使いこなすことができれば便利であることは間違いありませんが、これらの機能を満遍なく使いこなしている人はどれだけいるでしょうか。多くの人は、ワット数と時間を指定して温めることができればそれで充分ではないでしょうか。
    リモコンと同様に、ボタンの数が多い家電というのは一見便利そうに見えますが、一部の機能しか使わないユーザーにとっては煩わしいものとなってしまいます。

    一般に電化製品は値段が高いほど機能が多くなる傾向がありますが、それが必ずしもユーザーにとっての価値と結びついているとは限りません。必要最低限の機能だけが搭載されたシンプルなつくりでも、ユーザーが満足していれば、それは価値の高いプロダクトと言えます。

    ソフトウェアにおけるシンプルさ

    ここまで電化製品における例を紹介しましたが、ソフトウェアについても見ていきます。

    ここでは、検索エンジンとしてのYahooとGoogleを比較してみます。
    検索エンジンとしての体験に注目すると、Googleは検索に特化した非常にシンプルなインターフェースになっています。一方、Yahooはニュースやショッピングなど様々な情報が並ぶポータルサイトです。

    Yahooはネットニュースや知恵袋、オークションなど、様々なサービスがあり、個々のサービスにおいて多くのユーザーがいることは間違いないですが、検索エンジンとして比較した場合、Googleを使っている人の方が多いのではないでしょうか。検索という目的だけを見ると、Googleのシンプルさは非常に分かりやすく、使いやすい設計になっていることが分かります。

    Less is more という言葉をご存知でしょうか。
    「少ない方が豊かである」という意味のデザインや建築の哲学ですが、Googleのトップページはこの思想が体現されている例だと感じます。

    バグが少ないソフトウェア

    ソフトウェアの価値を高めるためには、品質の高さも重要です。
    品質の定義にも様々ありますが、一つ言えるのは、バグ(不具合)が少ないソフトウェアほど品質も高いと評価されるケースが多いです。ユーザーにとって魅力的と思える機能が備わっていたとしても、その機能にバグが多く含まれてユーザーを困らせているとしたら、そのソフトウェアは品質が低く、同時に価値も低くなってしまいます。

    では、ソフトウェアのバグを減らすにはどうすればよいでしょうか。
    よく言われる冗談として、「バグを生まない最も効果的な方法はコードを書かないことだ」というものがあります。

    プログラムというのは、人がコードを書いた時点でバグのリスクが生まれます。
    バグが1つもないプログラムというのは、極端なことを言うとコードを何も書いていないプログラムです。
    とはいえ、コードが何も書かれていないプログラムは何も動作することがないため、プログラムとしての意味はなく、当然ユーザーに対して何の価値も生みません。

    だからこそ、品質の高い価値あるソフトウェアを作るためには、必要最低限の実装で本当に必要な機能だけを実装することが大切です。

    AIでバグは減らせるか

    最近は人間の代わりにAIがコードを書くことも増えてきたため、人間がコードを書くよりもバグが少なくなるのでは?と思う方もいるかもしれません。確かに、AIは知識豊富で多くの場面で人間よりも優秀なため、文法のミスや考慮漏れによるバグは少なくなるかもしれません。しかし、AIが書いたコードにバグが混在しない根拠はありませんし、AIに頼りすぎることで、人間にとってメンテナンスしづらいコードが量産されてしまう可能性も高まります。

    AIを適切に活用できれば生産性向上や品質向上の役に立つことは間違いないですが、AIを使っているからと言ってバグがなくなるわけではありません。AIを使っていたとしても、ソフトウェアをシンプルに保つことは重要ですし、むしろAIの時代だからこそ、ソフトウェアをシンプルに保つことの重要性は増したとも感じています。

    テストでバグは減らせるか

    ソフトウェアの品質を高めるためにはテストが重要です。
    様々なテストケースでソフトウェアをテストすれば、多くのバグを検出することができ、結果としてソフトウェアの品質は高められます。また、それらのテストを自動化しておけば、再テストが容易になるため、長期的な運用や機能改修作業が非常に楽になります。

    しかし、テストを自動化したとしても、テストコード自体にバグがない保証はありません。
    また、テストの量が増えていくと、仕様変更が起きた時に修正しなければいけないテストコードも増えていき、メンテナンスのコストも増えていきます。テストの自動化は、ソフトウェアの品質を高めるための強力な武器になりますが、同時にテストコードが負債になってしまう可能性も大いにあり得ます。

    そういう点では、テストがあるからと言ってやみくもに機能を増やすのは危険です。
    結局のところ、テストの有無にかかわらず、ソフトウェア全体をシンプルに保つように設計していくことが、ソフトウェアを長く運用していくために重要になってきます。

    YAGNI原則

    YAGNIの原則をご存知でしょうか。You Ain’t Gonna Need It. の略で、ソフトウェア開発において「実際に必要となるまで追加しない」という原則になります。

    ソフトウェア開発をしていると、「将来こういう機能が追加されるだろう」という予測に基づいて、余計な機能を実装してしまう事があります。しかし、実際には「将来使うかもしれない」という予測は、約90%は使われないのだそうです。

    YAGNI原則はコードをシンプルに保つための重要な原則の一つです。

    KISS原則

    YAGNI原則と併用して紹介されることの多い原則にKISS原則があります。これは、Keep It Simple, Stupid. の略で、直訳だと「シンプルにしておけ、愚か者よ」という意味になります。

    この記事での主張したいことは、この原則の主張と一致します。KISS原則は、可読性や保守性を向上させるという文脈において使われることの多い原則で、設計やコードをシンプルにしましょう、という原則です。設計やコードをシンプルにすることは、結果としてソフトウェアの価値を高めることにもつながります。

    シンプルの種類

    ここまで「シンプル」という言葉を多用してきましたが、改めてシンプルという言葉を整理します。
    ソフトウェアにおける「シンプルさ」は大きく2種類あります。

    1つ目は、表面的なシンプルさです。例えば、UIのシンプルさや、機能の少なさ、操作が簡単であることを表すシンプルさです。先の家電の例やGoogleの検索はこの手のシンプルさがあります。

    2つ目は、ソフトウェアの内部的なシンプルさです。コードの読みやすさはもちろん、依存関係や責務分離などの設計的な観点も含めたシンプルさです。YAGNI原則やKISS原則は、この内部的なシンプルさを保つための原則だと言えます。

    この「表面的なシンプルさ」と「ソフトウェアの内部的なシンプルさ」は必ずしも一致するわけではありません。
    ユーザーから見るとシンプルなソフトウェアでも、内部の実装が複雑になりすぎているケースは少なくありません。
    そのため、ユーザー体験と内部設計の両方の観点でシンプルさを意識することが、ソフトウェアの価値を高めるために重要になります。

    価値と負債のトレードオフ

    ソフトウェア開発の仕事は、一度プロダクトを作った後にも機能の追加や仕様変更が頻繁に起きます。
    顧客やユーザーからの要望があった場合に、その要望に応えてソフトウェアを改修していくことはとても大事です。

    しかし、その要望がユーザーにとってどれだけの価値になるかを考慮したうえで意思決定している人はどれだけいるでしょうか。
    「顧客がそう言っているから」という理由だけで、Yesマンになって何も考えずに機能を追加しているケースは多いのではないかと思っています。ソフトウェアに対して機能を追加したり仕様を変更するという作業は、開発コストがかかる上に、ソフトウェアに対して技術的負債を増やしてしまう可能性があります。

    仮に、ユーザーに届く価値が少ないにも関わらず、技術的な負債が大きく増えてしまうような機能追加があった場合、長期的にみるとそれはソフトウェアの価値を下げているのかもしれません。

    開発コストが少なく、技術的負債に対する影響も少なく、それでいてユーザーへの価値が大きく高まる機能であれば、それは実装するべき機能だと判断できます。しかし、ユーザーへの価値と技術的負債が釣り合わない実装を続けていると、ソフトウェアが必要以上に複雑になり、徐々にメンテナンスすることが困難な状態になってしまいます。

    開発しているソフトウェアが、「必要以上に複雑になりそう」と感じたら、内部構造をできるだけシンプルに保てるよう、マネージャーや顧客を巻き込んで調整していくことが重要です。

    業務は複雑

    ここまで、ソフトウェアをシンプルに保つことの大事さを主張してきました。
    しかし、ソフトウェアで解決しようとしている業務内容のほとんどは複雑です。そう考えると、全てがシンプルなつくりになっているソフトウェアというのはあまりないのかもしれません。そもそも、全てがシンプルなソフトウェアは、解決できる問題も限られている可能性が高いため、あまり価値の高いソフトウェアにはならないでしょう。
    複雑な問題を解決してくれるソフトウェアこそ、価値の高いソフトウェアになり得ます。

    とはいえ、必要以上にソフトウェアを複雑にして良いわけではありません。

    シンプルさと同様、ソフトウェアの複雑性にも2つの分類があります。それは、「本質的複雑性」と「偶発的複雑性」です。

    本質的複雑性とは、業務そのものの複雑性です。ソフトウェアを開発するにあたって、この複雑性を避けては通れません。一方、偶発的複雑性は、不必要な機能や過剰な抽象化といった設計の悪さが招く複雑性です。

    偶発的複雑性をどのように減らしていくかは、エンジニアの実力が試される部分でもあります。
    偶発的複雑性を減らすための考え方として、YAGNI原則やKISS原則といった原則、あるいはドメイン駆動設計やクリーンアーキテクチャといった設計思想があります。

    ソフトウェアエンジニアの役割は、本質的な複雑さを受け入れつつ、偶発的な複雑さをできるだけ減らすこととも言えます。

    Simple is hard.(シンプルは難しい)

    シンプルという言葉を直訳すると、「単純」や「簡単」といった意味が思い浮かびます。しかし、ソフトウェアをシンプルに保つことは決して簡単なことではありません。 むしろ、何も考えずに開発しているとソフトウェアは自然と複雑になっていきます。

    シンプルさを保つための努力と工夫を続けることが、エンジニアとしての価値につながっていくのかもしれません。

  • ITインフラとインフラエンジニアとは(初心者向け)

    ITインフラとインフラエンジニアとは(初心者向け)

    はじめに

    私はシステムエンジニアとして初めて現場に出てから約一年半、開発系の現場で働いてきました。

    なので、ITインフラという言葉は聞いたことはあるけど、ITインフラだったり、インフラエンジニアがどのような仕事をしているか詳しくは知らないという状況でした。

    最近、インフラの現場に参画されている先輩と話す機会があり、「ITインフラについて」や「インフラエンジニア」の仕事内容について興味が湧いたため調べることにしました。

    この記事では、そもそも「ITインフラ」とは何か、「インフラエンジニア」の仕事内容について下記参考書をもとに紹介しようと思います。

    図解即戦力 インフラエンジニアの知識と実務がこれ1冊でしっかりわかる教科書

    インフラエンジニア研究会 著

    https://gihyo.jp/book/2021/978-4-297-12289-8


    ITインフラとは

    ITインフラとは、システムやサービスを安定して動かすための基盤のことを指します。

    具体的には、サーバー、ネットワーク、ストレージ、OS、ミドルウェアなどが含まれます。これらが適切に構成・管理されていなければ、Webサービスは正常に動作しません。

    例えば、ECサイトで商品を購入するとき、裏側ではWebサーバーがページを表示し、アプリケーションサーバーが処理を行い、データベースサーバーが情報を管理しています。

    そして、それらをつなぐネットワークが安定していなければ通信は成立しません。こうした一連の仕組みを支えているのがITインフラです。


    インフラエンジニアの仕事内容

    インフラエンジニアの仕事内容について5つに分けて説明します。

    ①要件定義 ー システムの土台を考える

    ここでは、システムに求められる条件を整理します。

    例えば、「同時接続は何人か」「24時間365日稼働が必要か」「セキュリティレベルはどの程度か」などを明確にします。

    この段階での判断が、その後の設計や構築の方向性を決定します。

    インフラは後から簡単に変更できるものではないため、慎重な検討が求められます。

    ②設計 ー 構成を具体化する

    要件が決まったら、次は設計です。

    ここでは、実際にどのような構成にするかを決めます。

    サーバーは何台必要か、役割ごとに分けるか、冗長化をどう行うか、ネットワークをどのように構築するかなどを検討し、構成図としてまとめます。

    システムが停止しない仕組みや、障害発生時の切り替え方法まで考慮するのがインフラ設計の特徴です。

    ③構築 ー 設計を形にする

    設計が完成したら、いよいよ構築作業に入ります。

    サーバーのセットアップ、OSのインストール、ネットワーク設定、ミドルウェアの導入、セキュリティ設定などを行います。

    クラウド環境であれば仮想サーバーやネットワークを作成し、必要な設定を加えていきます。

    構築作業では、正確性が何よりも重要です。

    わずかな設定ミスがシステム障害につながるため、手順書に沿って丁寧に作業を進める必要があります。

    ④テスト ー 安定性を確認する

    構築後はテストを実施します。

    通信確認、負荷テスト、障害試験などを行い、設計通りに動作するかを検証します。

    あえてサーバーを停止させることで、冗長構成が正しく機能するかを確認することもあります。

    この工程を丁寧に行うことで、本番環境でのトラブルを未然に防ぎます。

    ⑤運用・保守 ー 安定稼働を支える

    インフラエンジニアの仕事は、構築して終わりではなく、むしろ運用フェーズこそが長く続く重要な業務です。

    サーバーやネットワークの監視、ログ確認、バックアップ管理、セキュリティ更新、障害対応などを日々行います。

    問題が発生した際には迅速に原因を特定し、サービス停止時間を最小限に抑えます。

    システムを陰で支える存在こそがインフラエンジニアなのです。


    最後に

    今回、「ITインフラ」「インフラエンジニア」について調べてみて、仕事内容の流れについては開発業務と大差がないことが印象に残りました。

    要件定義や設計、テストといった工程は、開発の仕事と共通していて馴染みがあります。

    インフラと開発は全くの別物ではなく、同じシステムづくりを異なる視点から支えているんだなと感じました。

    今後、インフラ系の現場に参画することもあると思うので、開発もインフラも両方の視点を意識し、システム全体を捉えられるエンジニアを目指していきたいと思います。

  • マネジメント1年目の教科書

    マネジメント1年目の教科書

    マネージャーの仕事とは何でしょうか。

    指示を出すことか。
    部下を管理することか。
    それとも、自分が一番成果を出すことでしょうか。

    役割が曖昧なままマネージャー1年目を過ごすと、
    気づけば「プレイヤーの延長線」に立ち続けてしまいます。

    本記事では「基礎編」として、マネジメントの出発点となる重要なテーマを、以下3点で整理します。

    • マネージャーの役割とは何か
    • マネージャーに求められる視点3つ
    • 「人の強みを生かす」ことの重要性

    ①マネージャーの役割とは

    まず前提として、マネージャーの定義についてです。

    マネージャーとは、部下(関係者)を通じて、自分の意図を実現する人を示す言葉です。

    つまり、自分が直接成果を出すのではなく、
    「チームとして成果を出す仕組みをつくる人」と言い換えることもできます。

    自分が100点を出すことよりも、
    メンバーそれぞれが80点を出せる状態をつくること。
    その総和こそが、マネージャーの成果です。

    また、マネージャーはプレイヤーと完全に切り離された存在ではなく、マネージャーの仕事には「プレイヤーの仕事」も含まれます。

    さらに、マネージャーの役割は相手の立場によって変化します。

    • 相手が部下・後輩の場合:上層部の代表者として、リーダーシップを発揮する
    • 相手が上司の場合:部下・後輩の代表者として、フォロアーシップを発揮する
    • 相手が社内別部門の場合:自職場の代表者として、パートナーシップを発揮する
    • 相手が社外関係先の場合:企業の代表者として、パートナーシップを発揮する
    • 相手が顧客の場合:企業担当者(責任者)として、カスタマーシップを発揮する

    マネージャーとは、常に「誰の代表として立っているのか」を意識する存在です。

    この“代表者意識”が抜け落ちると、
    発言や判断はすべて「個人の意見」になってしまいます。

    しかしマネージャーの言葉は、
    常に組織を背負った言葉になります。

    だからこそ重要なのは、
    自分の感情ではなく、
    「今、どの立場で話しているのか」を自覚することです。


    ②マネージャーの仕事に必要な3つの能力

    ■ 戦略的視点

    「今やるべきことは何か」を優先順位で判断する力です。

    目の前の依頼をすべて受けるのではなく、
    チームの時間と体力をどこに使うべきかを決めること。

    “頑張る”よりも“絞る”ことが重要です。

    多くのマネージャーは、
    「全部やる」という選択をしてしまいます。

    しかし、それは優しさではなく、
    戦略の欠如であることも少なくありません。

    限られた時間と資源をどう配分するか。
    その決断こそが、マネージャーの価値です。


    ■ 顧客志向

    「この仕事は本当にお客様の役に立つか?」と問い続ける姿勢です。

    社内都合や前例ではなく、
    「お客様が使いやすいか」「価値を感じるか」を基準に判断する。

    迷ったときの軸を外に置くことがポイントです。


    ■ システム思考

    問題を“人”ではなく“仕組み”で考える力です。

    ミスが起きたときに個人を責めるのではなく、
    「なぜこの流れだとミスが起きやすいのか?」を考えることが重要です。

    例えば、同じミスが繰り返される場合、
    それは個人の能力の問題ではなく、
    確認プロセスや情報共有の流れに原因があるかもしれません。

    人を変えるよりも、
    流れを変える。

    それがマネージャーの仕事です。

    再発防止は、仕組みを変えることから始まります。


    ③「人の強みを生かす」ことの重要性

    マネジメントの重要な役割は、
    人の強みを成果につなげることです。

    組織では弱みの改善に目が向きがちですが、
    弱みを平均点まで引き上げても、大きな成果には直結しません。

    成果の源泉になるのは「強み」です。

    だからこそ考えるべきは、
    「弱みをどう補うか」ではなく、
    「強みをどこで最大化できるか」という視点です。

    これは部下だけでなく、上司に対しても同じです。
    上司の強みを理解し、それを活かすことが、
    結果としてチーム全体、そして自分自身の成果にもつながります。

    強みは単なる長所ではなく、
    成果を生み出す“機会”そのものです。

    マネージャー1年目にまず意識すべきなのは、
    弱点の是正よりも、強みの発見と活用です。


    まとめ

    マネジメント1年目は、「自分が成果を出す立場」から
    「組織として成果を出す立場」へと視点を切り替える期間です。

    • マネージャーの役割を正しく理解すること
    • 戦略・顧客・構造という視点を持つこと
    • 人の強みを成果へと結びつけること

    これらを意識することで、マネージャー1年目の迷いは大きく減ります。

    マネジメントは特別な才能ではなく、
    役割と視点を理解し、実践を重ねることで磨かれていくものです。

    まずは基礎を押さえること。
    それが、マネージャーとしての確かな一歩になります。


    セミナーを受講した感想

    特に印象に残ったのは、「弱みの改善よりも強みの最大化に注力すべき」という考え方でした。
    実際にメンバーの強みをベースにタスク振りをした結果、チーム全体としての成果物作成スピードが明らかに向上しました。
    また、強みを正しく評価することで本人のモチベーションも高まり、その結果として相対的に弱みの部分にも自ら気づきやすくなったように感じています。

     

    参考URL

    ・新任マネージャーのスターターキット(オンラインセミナー)

    https://schoo.jp/class/12186

  • システム開発のテストについて

    システム開発のテストについて

    1.初めに

     システム開発の工程の一つである「テスト」ですが、システムの品質を決定する最も重要な段階です。

    本記事では、4つの主要なテストと私のシステム開発での実体験をまとめます。

    2.テストの種類

     まず、テストの種類は主に4つに分かれます。

    段階を踏んでテストを進めていくことで、不具合を極力なくすことができるようになります。

    また、不具合が出た場合にも原因の特定が容易になることもあります。

    下記図がそれぞれの概要になります。

    一つずつテストの種類について説明をしていきます。

     ①単体テスト(UT)

      システム内の最小単位である関数やモジュールを対象としたテストです。

      開発の初期段階で行うテストで、各部品が設計通りに動作するか、バグが発生しないかを確認します。

      単体テストの時点で不具合を修正することで、後の工程での不具合を最小限にとどめられます。

     ②結合テスト(LT)

      複数のプログラムやモジュールを組み合わせた状態で動作を確認するテストです。

      単体テストをクリアした後に行うテストで、モジュール間のデータ連携やインタフェースに問題がないかを確認します。

      単体では問題なく動作するシステムが結合した際に起こるバグを検出することができます。

     ③システムテスト(ST)

      システム全体が要件通りに動作するかどうかを検証するテストです。

      総合テストとも呼び、選任のテスターが納品前の最終確認として行います。

      システムテスト仕様書をもとに、ユーザーの操作を想定した一連の機能・負荷への対応・セキュリティ・エラー発生時の処理などを検証します。

     ④受け入れテスト(UAT)

      クライアント側が実施する品質テストです。

      ユーザーテストとも呼び、システムテストを経て納品されたシステムが指定の要件やパフォーマンスを満たしているかどうかを総合的に判断します。

      システム開発の最終工程であり、実際の運用環境に近い条件で行われます。

    3.テストの際の留意点と実体験

     私がテストを実施するテスターとしての気を付けていた3つの留意点と実体験について記します。

    留意点①:テスト実施手順がわからない時は有識者に確認する

        ⇒テスト仕様書の記載でテストの条件や、実施方法が曖昧なことがありました。

    一年目の時には、テスト条件がよくわからないままテストを実施してしまったことがありました。(もちろん再テストになりました。)

    そこから自身で勝手に判断せずに、過去にそのテストケースを実施したことがある方などに積極的に確認することを意識するようになりました。

    結果としてテストをする前の準備というところで、スムーズに進めることができるようになりました。

    (例)ログイン画面→トップメニュー画面→ユーザー情報変更画面の順に画面遷移し、
    正常終了することを確認する。
       【確認したいこと】
        ・ログインするユーザーに制限はあるのか。
        ・ユーザー情報変更画面では何か入力を行うのか。
        など

    留意点②:テストした結果は必ず自身で見返す

        ⇒テストのエビデンスで不備に気づけないことがありました。

    作成したエビデンスを見返す習慣がなかった時には、そもそもエビデンスの整形ミスやエビデンス不足になっていることがありました。

    テスト後のエビデンスを確認するようになってからは余計なミスは少なくなり、打鍵者(私)とレビュー者の時間の短縮につながりました。

    留意点③:些細な不具合でも報告する

        ⇒不具合と書くと大げさですが、気になったところは有識者の方などに都度聞くようになりました。

    実体験としては、テスト実施中にテスト観点ではないところで不具合を見つけ、その報告をした際に感謝されたということがありました。

    そこからテストの中で気になる箇所はその度に確認をするようになりました。

    4.最後に

     記事の冒頭にも記載しましたが、システム開発における「テスト」とはシステムの品質を決定する最も重要な段階です。

    ただの作業としてテストを実施するのではなく、それぞれのテストケースの意味を考えながら行うことでよりシステムの品質を高くすることができるかと思います。

    私自身システム開発のテスト実施を行ってきましたが、テストケースの意味などに注目するようになってから、テストの結果に対して正当な見返しができるようになったと思います。

    皆さんもテスト実施の前に、テストの意味について振り返ってみてもらえればと思います。

    6.参考文献

    ・システム開発のテスト工程とは?種類や手法 流れをわかりやすく解説

    ・QAエンジニアが教えちゃいます!テスト見積のコツ | Sqripts

  • Raspberry Pi初心者がリモート接続できるまでの記録

    今回は、これまで私が取り組んできたRaspberry Piについて、
    学んだことや実践内容をまとめて紹介します。

    これからRaspberry Piを触ってみたい人や、
    IoTに興味がある人の参考になれば嬉しいです。

    ◆Raspberry Piとは?

    Raspberry Pi(ラズベリーパイ)は、
    イギリスのラズベリーパイ財団が提供している低コストで高性能な
    小型コンピュータ です。
    教育や電子工作、IoT開発を目的として作られており、
    小さいながらも普通のPCのように扱えるのが特徴です。
    現在は Raspberry Pi Zero 〜 Raspberry Pi 5 までのモデルが存在します。
    筆者のモデルは「Raspberry Pi 4」です。

    ◆モデルごとによる違い

    上記で記載したモデルについてざっくりとまとめると以下の通りです。

    モデル主な用途特徴
    Raspberry Pi Zero小型 IoT
    組み込み
    超小型・低価格
    必要最低限の端子のみ
    Raspberry Pi 4 / 5デスクトップ利用
    学習
    電子工作
    サーバー用途など
    高性能CPU
    複数USB
    HDMI
    LANなどを搭載

    ◆Raspberry Piでできること

    Raspberry Piは用途が非常に幅広く、例えば次のようなことが可能です。
     小型PCとして利用
     多機能家電の制御
     温度・湿度計の作成
     音楽プレイヤー
     Webサーバ構築
     IoT機器の制御

    「小さなコンピュータ=何でも作れる土台」と考えると分かりやすいです。

    ◆Raspberry Piに興味を持ったきっかけ

    現場で知り合った方から教えてもらったことがきっかけでした。
    また、以前受講した Python & IoT研修 でも話題に上がっており、
    「実際に触ってみたい」と思ったのが始まりです。

    ◆リモートデスクトップ接続に挑戦

    Raspberry Pi を手に入れて、さっそく触ってみました。
    操作自体は特に難しくなく、
    スムーズに使い始められたのですが、
    ひとつだけ気になる点がありました。

    それは、起動するたびに
    普段使っているデスクトップPCのキーボードとマウスを
    Raspberry Pi に差し替えなければならないこと。

    この作業が思いのほか手間で、「なんとかならないかな…」と感じるように。

    そこで次のステップとして、
    Windows から Raspberry Pi をリモート操作できる環境づくりに
    挑戦することにしました。
    これができれば、周辺機器を抜き差しする必要もなく、
    もっと快適に Raspberry Pi を使えるはずです。

    実施内容を簡単にまとめると以下の通りです。

    ・Raspberry Pi側の作業
     1.xrdpをインストール
      ※これによりインターネットを経由せずにLAN内の
       機器同士だけでリモートデスクトップ接続できるようになります。
       ⇒方法を調べるとCUI操作での対応方法の記載が多く、
        OSのインストール時にGUIを選んでしまった私は、
        GUI操作でのインストール方法の調査に時間がかかってしまいました。
     2.RDPサーバを有効化
     3.サービス再起動

    ・Windows側の作業
     「mstsc(リモートデスクトップ)」を起動
     Raspberry PiのIPアドレスを入力

    上記の手順で別PCからGUI操作が可能になりました。
    モニターやキーボードなしでも操作できるようになり、
    運用性が大幅に向上しました。

    ◆今後の構想

    今後は以下のようなIoT開発を予定し、
    その成果は当ブログで発信したいと思います。

     1. SSH接続環境の構築
     2. Webサーバ作成
     3. 気温・室温・臭気検知システム
     4. 外出先からエアコン操作

    いわゆる「スマートホーム化」を目指した構成です。
    未だ構想段階ですが、一つ一つクリアしていこうと思います。

    ◆Raspberry Piを通して得た気づき

    Raspberry Piの学習は単なる電子工作ではなく、
     Linux操作
     ネットワーク知識
     ハードウェア理解
     トラブル対応力
    など、エンジニアとして幅広いスキルにつながると感じました。
    特に私自身はネットワーク関連の知識理解が足りない部分があるため、
    今後は書籍による知識の拡充と共に実際に手元で操作できるツールとして
    Raspberry Piを活用していきたいと思います。

    ◆まとめ

    改めて、下記の点で有用であるということを実感しました。
     ・Raspberry Piは低コストで学習効果が高い
      ⇒昨今そこそこのスペックのPCを買うとなると安くはすまないが
       それに比べ、Raspberry Piは安価で済みます
      ⇒またpython、Scratch、Java等多くの言語に対応しています。
     ・リモート接続により実用性が大きく向上
      ⇒上述の通り
     ・開発だけでなくPC知識も重要
      ⇒Raspberry Pi 4には一般的なPCに搭載されている機能が
       ほぼ備わっているため、VM(仮想マシン)とは異なり“
       実体のあるコンピュータ”として扱えます。
       その結果、PCの物理的な構成についても理解しやすくなります。   
     ・トラブルも学習の一部
      ⇒もし壊れてもSDカードにOSを入れておくだけで環境を作り直せる

    今後は上述したようにWebサーバ構築やIoT連携など、
    さらに発展させていく予定です。

  • 【AWS認定試験】駆け出し冒険者完全ガイド【資格選定/勉強法】

    【AWS認定試験】駆け出し冒険者完全ガイド【資格選定/勉強法】

    はじめに

    私はお仕事でAWSを触る機会が多く、資格を複数個取得しています。

    弊社では最近、AWS資格を取得する人が増えてきた(?)こともあり、「どうやって勉強したらいいんですか?」や「どの認定試験を取るべきですか?」などの質問をちょこちょこもらっていました。

    そんな中、社内の勉強会で「AWS資格について初心者向けにお話をしていただきたい!」という要望をもらったので、せっかくならということで、この記事を書いてみました。

    初心者向けということで、難しい単語を使わず、メタファーでお送りしたいと思い、RPG風の世界観に置き換えて、AWS認定試験の資格選定や勉強法についてお話します。

    ※イメージを掴んでもらうため、たくさんの画像がでてきますが、あくまで参考程度に!

    それでは、どうぞ!

    導入

    AWS(アマゾン ウェブ サービス)……それは、200を超える強力な魔法(サービス)と、刻一刻と形を変える地形(アップデート)が広がる、エンジニアにとっての広大な「魔境」です。

    資格を取ってみたいと思い立った皆さんは、コンソール画面や資格一覧を前に、「どこから手を付ければいいんだ……」と立ち尽くしているかもしれません。そんな皆さんのために、AWSギルドが発行している「冒険者ライセンス(AWS認定資格)」の歩き方を解説します。

    kaimaku!

    冒険者のランク(認定レベル)

    冒険者ライセンスの世界には、習熟度に応じた4つのランクが存在します。

    ※2026/2/1時点の情報です

    【初級:Foundational 認定】見習い冒険者

    まずは道具の名前を覚えるレベル。

    • AWS Certified Cloud Practitioner
      • 「火の魔法(EC2)は熱い」「聖水(S3)は腐らない」といった基本を理解します。
    • AWS Certified AI Practitioner
      • 「使い魔(AI)」の初歩的な扱い方を学ぶ入門コースです。

    【中級:Associate 認定】一人前の冒険者 ★今回の本題★

    複数の道具を組み合わせ、パーティの主力として戦える証です。

    詳細は後述します。

    【上級:Professional 認定】伝説の勇者

    国全体の防衛や、数千人規模の遠征(大規模移行)を指揮できる、ギルド長レベル。

    • AWS Certified Solutions Architect – Professional
    • AWS Certified DevOps Engineer – Professional
    • AWS Certified Generative AI Developer – Professional

    【特級:Specialty 認定】特定の道を極めし者

    一分野を極めたマスター。特定の属性にて、めっぽう強い。

    • AWS Certified Machine Learning – Specialty
    • AWS Certified Advanced Networking – Specialty
    • AWS Certified Security – Specialty

    Associate 認定:5つの「ジョブ(職業)」を徹底解説

    駆け出しエンジニアの皆さんが最初に目指すべき、「中級・Associate 認定」。

    ここには5つのジョブが存在します。自分の好みのプレイスタイルを選んでみましょう。

    ① AWS Certified Solutions Architect – Associate

    【ジョブ:パーティの要 / 城塞設計士】

    • 得意技:高可用性の魔法・コスト最適化の盾
    • 仕事内容: 「モンスター(急なアクセス増)に襲われても壊れない城(システム)を、いかに安く、頑丈に建てるか」という設計図を書く役割です。
    • こんな人に:「まずは王道から!」「全体を把握したい!」という方。
    SAA

    ② AWS Certified Developer – Associate

    【ジョブ:魔道士 / 錬金術師】

    • 得意技:サーバーレスの呪文・SDKの杖
    • 仕事内容:「サーバー(重い装備)を管理するのは面倒だから、呪文(プログラム)を唱えた時だけ発動する仕組み」を作るのが得意。
    • こんな人に:普段コードを書いていて、開発の効率を極めたい方。
    Developer

    ③ AWS Certified CloudOps Engineer – Associate

    【ジョブ:城塞の守護聖騎士(パラディン)】

    • 得意技:継続的監視・自動修復
    • 仕事内容:「城が燃えていないか?」を常に監視し、万が一HPが減っても自動で回復(オートスケーリング)するよう設定する、守りのプロ。
    • こんな人に:「止まらないシステムこそが正義」と考える、インフラの守護神を目指す方。
    CloudOps

    ④ AWS Certified Data Engineer – Associate

    【ジョブ:王宮の図書館長】

    • 得意技:情報収集のパイプライン・大容量倉庫の管理
    • 仕事内容:大陸中に散らばった膨大な情報を集め、誰でも分析しやすいように整理整頓して保管する仕事です。
    • こんな人に:「データこそが世界を変える」と信じる、整理整頓好きのエンジニア。
    Data Engineer

    ⑤ AWS Certified Machine Learning Engineer – Associate

    【ジョブ:魔物調教師(テイマー)】

    • 得意技:AIモデルの育成・構築
    • 仕事内容:データを餌として与え、AIという「賢い使い魔」を実働できるように訓練し、戦場(本番環境)へと送り出す役割です。
    • こんな人に: 最新のAI技術を、「実戦兵器」として使いたい方。

    最初のクエスト:どれから受けるべき?

    推奨ルートは、圧倒的に 「AWS Certified Solutions Architect – Associate」です。

    なぜなら、どのジョブに就くとしても、「どんな地形(ネットワーク)があり、どんな装備(データベース)があるか」を知らなければ、戦うことすらできないからです。

    ただし、あくまで推奨です。やりたいジョブ(資格)があればそちらを優先することをおすすめします。「興味」はジョブを学ぶ上で、一番重要です。

    効率的なレベリングの極意:最短でライセンスを掴む方法

    「ジョブ(資格)の勉強って、分厚い攻略本(参考書)を最初から最後まで読まないといけないんでしょ?」

    いえ、そんなことはありません。効率的な冒険者は、「最短ルート」でレベルを上げます。

    以下は駆け出しの皆さんに送る、挫折しないための3つの鉄則です。

    ① 「攻略本」を読み込むより、まずは「戦場(過去問)」へ

    多くの人が「まずは本を読んで理解してから問題を解こう」と考えますが、これは罠です。

    いきなり過去問(問題演習)から始めてください。

    最初の10問は全滅しても構いません。「何が問われるのか」を肌で感じてください。

    書籍を丁寧に読むのは、問題でボコボコにされてからでも遅くありません。

    ② 「解説」こそが最強の魔導書

    問題を解き、その「解説」を熟読すること。これが一番の修行になります。

    問題を解く → 解説を読む → 「へぇ〜、この魔法(サービス)はこう使うんだ」と納得する。

    これを繰り返すだけで、試験合格に必要な知識は自然と溜まっていきます。

    ③ 「8割の理解」で突き進め

    Associate試験は、その分野の「博士」になるための試験ではありません。

    「なんとなく、こんなものがあるんだなー」という、ざっくりとした理解で十分です。

    実務で必ず使うとは限らないマニアックな知識も含まれています。

    そこに時間を溶かして「資格勉強、苦しい……」と燃え尽きてしまうのが一番の損失です。

    攻略本 < 実践

    最後に:ライセンスは「スタート地点」

    効率よくジョブを習得するべき最大の理由は、「本当の冒険(仕事)はライセンスを取った後に始まるから」です。

    全部を丁寧に理解しようとして3ヶ月かけるより、効率重視で1ヶ月で合格する。

    そして、浮いた2ヶ月間で、手を動かして「自分で何かを作ってみる」。

    これができれば、まさに一流の冒険者(エンジニア)への第一歩です(私も日々、実践中です)。

    おわりに

    AWSの世界は、半年も経てば新しい大陸が出現し、魔法の効果が変わります。

    合格証書は、あなたが「最低限、この大陸で生きていける」と認められた証。そこから先の深い知識は、実戦のなかで身につければいいのです!

    まずは、少しでも興味の引っかかる部分を作り、行動に繋げてもらえると幸いです。

    参考

  • 仕様駆動で進めるチーム開発

    仕様駆動で進めるチーム開発

    LLMを活用した開発ツールの普及により、自然言語の指示から即座にコードを生成する「Vibeコーディング」が一般的になりました。個人の実装速度を劇的に高める一方で、チーム開発やプロジェクトが一定の規模を超えたあたりで、このスタイル特有の難しさに直面することがあります。

    本記事では、Vibeコーディングで突き当たりやすい課題を整理した上で、一つの解決策として「仕様駆動開発(SDD)」を今の開発フローに合わせて取り入れる流れについて考えてみます。


    1. Vibeコーディングの課題

    注意マーク

    設計をあえて作り込まずに進めるVibeコーディングには、中長期的な運用においていくつか懸念されるポイントがあります。

    ・インターフェースの不整合

    明確なデータ定義がないまま進めると、フロントエンドとバックエンドの接続部分で認識のズレが発生しやすくなります。型や命名の些細な食い違いが、開発終盤での手戻りに繋がることも少なくありません。

    ・ハルシネーションの制御

    制約となる具体的なルールがない場合、生成AIは前後のコードから推測して存在しないデータ構造などを勝手に作り出してしまうことがあります。一見きれいに書かれている分、原因の特定に時間がかかる場合があります。

    ・ドキュメントの不足による属人化

    その場のプロンプトで生成されたコードは、設計意図が残りにくい側面があります。後から参加したメンバーにとって、コードそのものから仕様を読み解くのは負担が大きく、結果として特定の人にしか全貌がわからない状態を招きがちです。


    2. 仕様駆動開発(SDD)とは

    レクチャーする男性

    仕様駆動開発(Specification-Driven Development: SDD)とは、実装に入る前に、システムの振る舞いやデータの構造を共通の形式(OpenAPIなど)で定義し、それを実装の中心に据える手法です。

    この仕様ファイルは「チームとツールがいつでも立ち返ることができる共通の判断基準」として機能します。指示を丸投げするのではなく、作成した仕様をベースに実装を進めることで、意図しないコードの生成を抑え込み、一貫性のある出力を得やすくなります。


    3. 仕様駆動開発の具体的な流れ

    設計を行う際は、人間が手作業ですべてを書くのではなく、チャット形式のツールを設計のパートナーとして活用しながら進めるのが現実的だと考えています。

    ステップ1:対話を通じて仕様を固める

    まずはツールに対し、「どんな機能を作りたいか」を自然言語で伝えます。この際、「なぜその機能が必要か(Why)」まで伝えると、より文脈に沿ったエンドポイントやデータ項目が提案されやすくなります。

    ステップ2:仕様書の出力とチームによる確認

    対話で固まった内容をもとに、OpenAPI形式などで仕様書を出力させます。ここで欠かせないのが、人間によるレビューと合意です。

    提示された内容がビジネス要件に合っているか、チーム全員で確認します。このプロセスを通すことで、仕様がチームの総意となり、後の実装のブレを防ぐことができます。

    ステップ3:仕様を基にした技術設計

    仕様が決まれば、それをコンテキストとして読み込ませ、具体的なDB構成やシーケンス図などを作成させます。ベースとなる仕様が固まっているため、出力される設計情報の精度も高まります。

    ステップ4:仕様に基づいた実装をさせる

    確定した仕様ファイルをツールに読み込ませ、具体的なコードを実装させます。ここでのメリットは、単にコードが早く書けることだけではありません。

    共通の仕様ファイルをツールに読み込ませておくことで、フロントエンド側ではAPIから返ってくるデータ構造を正しく理解した状態でUIの実装が進み、バックエンド側では実装すべきエンドポイントの正解を把握した状態でロジックが生成されます。

    このように、共通の仕様が実装のガイドラインとなるため、フロントとバックを個別に実装させても、最後に双方を組み合わせた際に「型が合わない」「データが足りない」といった事故を減らすことができます。


    4. AIツールと連携して仕様の精度を高めるコツ

    虫眼鏡を使う男性

    仕様書をベースに実装を進めていく中で学んだ、いくつかのコツがあります。

    ・要求と制約をセットで伝える

    ツールへの指示では「何を実現したいか(要求)」だけでなく、「どのように実現してほしいか(制約)」をセットで伝えることが重要です。

    例えば「ユーザー投稿機能を作って」という要求に加えて、「バリデーションはこのライブラリを使い、レスポンスはこの形式に従って」といった具体的なルールを明示します。

    これにより、ツールの自由すぎる提案を抑え、プロジェクトの規律に沿った仕様に導くことができます。

    ・やらないことも定義する

    仕様を固める段階で「今回は検索機能は含めない」といった制約も共有しておくと、余計なデータ構造が混じり込むリスクを減らせます。

    ・徐々に詳細化する

    最初から完璧な定義ファイルを出力させようとせず、まずは自然言語の箇条書きで合意し、その後にコード形式へ変換させるという段階的なステップを踏むのがスムーズです。


    5. 運用上の課題

    悩む男性

    メリットの多い仕様駆動開発ですが、実務で導入する際にはいくつか気をつけるべき点もあります。

    ・仕様と実装の乖離

    実装フェーズにて、実装スピードを優先して、仕様ファイルを更新せずにコードだけ直してしまうと、仕様書が形骸化してしまいます。CIなどで不整合を検知する仕組みを導入し、機械的にチェックできるようにするのが理想的です。

    ・複雑化した既存プロジェクトへの適用

    既存プロジェクトのすべてを一気に変えるのは現実的ではないように思います。まずは新しく追加する機能や修正頻度の高いAPIから限定して導入してみるのがおすすめです。

    また、既存のコードから現在の挙動をベースにした仕様書を逆引きで生成させて現状を可視化するなど、小さな範囲から少しずつ広げていくとスムーズに作業が進むと考えています。

    ・初期設計への抵抗感

    最初に仕様を固める時間が、スピード感を削いでいるように感じられるかもしれません。まずは主要な機能だけに絞って定義し、少しずつ仕様を定めていくスモールスタートにするのも一つの手です。


    6. 最後に

    最初に正解を定義しておくことは、決して開発を停滞させるものではありません。むしろ、後半に発生しがちな混乱や手戻りを未然に防ぎ、プロジェクトをスムーズに完走させるための大切な先行準備といえます。

    ツールを用いて実装スピードを向上させつつ、仕様書というガイドラインでうまく導いてあげる。このバランスを意識することが、実装の勢いを止めることなく、チーム全員が安心して使い続けられるプロダクトを作るための、実用的な選択肢になると考えています。

  • Dockerの概要をやさしく解説

    Dockerの概要をやさしく解説

    はじめに

    皆さんは「Docker」について聞いたことはあるでしょうか。
    本記事では、Docker初学者向けに概要を解説します。

    概要

    Dockerとは、Docker社が提供するコンテナ型仮想環境用プラットフォーム です。アプリケーションを必要な環境ごとにコンテナという小さな箱にまとめて実行できます。
    コンテナにはアプリを動かすためのライブラリや設定など、必要な環境が一式含まれています。

    Dockerはコンテナ技術(仮想化技術の一種)を使っており、コンテナとは 軽量で隔離された実行環境 です。
    仮想マシンよりも軽く、起動も速いのが特徴です。

    なお、DockerはLinuxカーネル機能を使います。
    macOSやWindowsを使っている方は「Docker Desktop 」といったDockerを使うために必要なツールをインストールする必要があります。

    本記事について理解しやすくするため、用語の概要を一部ご紹介します。

    • Dockerイメージ
      コンテナのひな形にあたる動作環境用テンプレートであり、これを使ってコンテナを作成します。
    • Dockerfile
      いわばDockerイメージを作るための設計図です。
      このテキストファイルにインフラ構成情報を記載し、それをもとにDockerイメージが作られます。
    • Docker Compose
      複数のコンテナをまとめて管理するツールです。
      docker-compose.ymlというファイルにコンテナの構成情報を定義し、コンテナの起動・停止といった管理が一括で行えます。

    Dockerを使うメリット

    Dockerを使ってみて、実際に感じたメリットについて触れていきます。

    ①高い可搬性

    個人的に最も魅力を感じた点は、可搬性(どの環境でも同じように動くこと)です。

    皆さんは現場で作業する際、ローカル環境構築に手間取った経験はあるでしょうか。
    Docker イメージや docker-compose.yml を用意すれば、コマンド一つで同じ環境を再現できます。

    個人用AWSアカウントでEC2にDockerをインストール後、
    Dockerfileやdocker-compose.ymlを用いてローカルと同じ環境をクラウド上に簡単に再現できたため「これは便利だ」と感じました。

    また経験上、複数のコンテナを起動する場合はdocker-compose.ymlを使って一括で実行することが多かったです。
    コンテナが複数あると一つずつ立ち上げるのは手間なので、一括で実行できるのは楽です。

    ②柔軟な分離性

    各コンテナは独立して起動されるため例えば

    • コンテナAはPython3.10
    • コンテナBはPython3.12

    のように「プログラミング言語の別バージョン」をそれぞれ作成できます。

    ローカル環境で同じことをすると、バージョン切り替えやインストールが必要になりますがそういった手間を省けます。

    ローカル環境に多くのソフトをインストールすると、別のシステムを動かす際に「自分の環境だけ動かない」といったトラブルが起きがちです。
    そういったリスクを減らせるのは、「環境構築の安定性」の観点で利点といえます。

    ③優れた軽量性

    コンテナ以外にも仮想化技術があり、図にすると下記となります。


    コンテナ以外の仮想化技術だと各仮想化環境ごとにゲストOSを動かすためにオーバーヘッド(※)が大きくなり、処理が遅い傾向があります。
    ※仮想化を行うことで発生する余分な処理負荷や時間

    一方で、コンテナ仮想化はホストOSを共有する形で実行されるため、ホスト型やハイパーバイザー型より軽量で動くという仕組みです。

    Dockerを使うデメリット

    ではデメリットはどういったものがあるでしょうか。

    ①学習コストがかかる

    Dockerに限った話ではないですが、学習コストがかかります。
    例えば

    • Dockerコマンド
    • Docker Composeの書き方
    • Dockerfileの構成

    といった知識がないとDockerを有効活用できません。
    仮想化技術に触れたことは無い方は、まずは仮想化について把握しないとイメージしづらい部分が多いでしょう。

    ②コンテナはホストOSのカーネルを利用する

    Docker Desktopを使って他の作業者と同じ設定に揃えようとした際、うまくいかずに苦労しました。
    調べてみると原因は自分だけWindows 10 Homeを使っていたためで、Windows 10 Proを使う他のメンバーと同じ動作になりませんでした。
    Hyper-Vが有効化されず、調べたのですが解決策が見つからず最終的にはWindows 10 Proへ切り替えることになりました。

    コンテナはホストOSのカーネルを利用する形で起動するため、OSが異なると設定や挙動などに差異が出る可能性があるので要注意です。

    ③Dockerを利用した運用設計の検討

    Dockerを導入するなら「どう運用していくか」の検討も行う必要があります。

    AWSにサーバ構築するケースを考えてみます。
    例えば

    • EC2上にDocker構築
    • ECS(コンテナの起動タイプはFargate、ECS on EC2、ECS Anywhereの3つ)

    といった選択肢が考えられますが、料金体系・可用性・カスタイマイズ性といった要素を考慮して「どのサービス構成にするのがベストか」の検討が必要です。

    おわりに

    いかがでしたでしょうか。
    本記事が皆さんがコンテナや Docker に触れる際の参考になれば幸いです。

    興味がありましたら、実際にDockerを使ってアプリを動かしてみてください。

    参考資料