カテゴリー: アジャイル開発

  • 2日目:Go言語プロジェクトの初期設計とGoogle Books APIで直面した問題

    2日目:Go言語プロジェクトの初期設計とGoogle Books APIで直面した問題

    はじめに

    昨日行った作業を振り返り、進捗と発見した課題について整理しました。本記事では、Google Books APIを活用して書籍情報を取得するアプリケーションをGo言語で構築する中での進捗、問題点、および解決策の概要を報告します。また、次回以降に取り組むべき課題についても触れています。

    昨日の進捗

    以下の内容を完了しました:

    1. プロジェクトの初期設定
      • Go言語でのプロジェクト構造を作成。
      • 必要なディレクトリやファイルを整理し、基本的な構成を決定。
    2. Google Books APIs の連携
      • 書籍情報(タイトル、著者、出版社、カテゴリーなど)を取得するプログラムを実装。
    3. 動作確認
      • テストデータを用いてAPIのレスポンスを確認し、基本的な情報取得が機能することを確認。

    プロジェクトのディレクトリ構成

    以下のようなディレクトリ構造でプロジェクトを構築しました。この構成により、コードの可読性と保守性を向上させています。

    BookReview/
      ├── cmd/
      │    └── main.go        // エントリーポイント
      ├── internal/
      │    ├── models/       // 書籍情報のデータモデル
      │    ├── services/     // ISBN検索API呼び出しロジック
      │    └── handlers/     // HTTPハンドラー
      ├── templates/         // HTMLテンプレート
      ├── static/            // 静的ファイル
      └── config/            // 環境設定ファイル

    ISBN番号、Google Books APIs 、 Go言語を使った表示例

    Google Books APIs を使った最小限のロジック

    以下に、GoでGoogle Books APIを使用して書籍情報を取得する最小限のサンプルコードを示します。この例では、特定のISBN番号に基づいて書籍情報を取得します。

    ここに示す例は今回実装したコードではありません。

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"net/http"
    )
    
    func main() {
    	// Google Books API エンドポイント
    	apiURL := "https://www.googleapis.com/books/v1/volumes?q=isbn:9781449331818"
    
    	// HTTPリクエストを送信
    	resp, err := http.Get(apiURL)
    	if err != nil {
    		fmt.Println("Error:", err)
    		return
    	}
    	defer resp.Body.Close()
    
    	// レスポンスのデコード
    	var result map[string]interface{}
    	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
    		fmt.Println("Error decoding JSON:", err)
    		return
    	}
    
    	// 必要な情報を表示(最初の結果のみ)
    	if items, ok := result["items"].([]interface{}); ok && len(items) > 0 {
    		volumeInfo := items[0].(map[string]interface{})["volumeInfo"].(map[string]interface{})
    		fmt.Println("Title:", volumeInfo["title"])
    		fmt.Println("Authors:", volumeInfo["authors"])
    	} else {
    		fmt.Println("No results found.")
    	}
    }

    実行手順

    1. このコードをローカル環境に保存します(例: main.go)。
    2. 必要に応じてGoをインストールして環境を設定します。
    3. ターミナルでコードをコンパイル&実行します:go run main.go

    ポイント

    • ISBN指定: URLパラメータ q=isbn:ISBN番号 を使っています。
    • 最小限のロジック: エラー処理や高度な解析は省き、基本的な取得と表示に焦点を当てています。

    Google Books APIs の基本仕様

    Google Books API: ISBNで書籍情報を取得する仕様

    Google Books API は、特定のISBN番号をクエリパラメータとして指定することで書籍情報を取得できます。

    基本URL

    https://www.googleapis.com/books/v1/volumes

    リクエストパラメータ

    • q: 検索クエリ。ISBN番号を指定する際は isbn:ISBN番号 の形式で指定します。
      • 例: q=isbn:9781449331818

    サンプルリクエストURL

    https://www.googleapis.com/books/v1/volumes?q=isbn:9781449331818

    レスポンス例

    レスポンスはJSON形式で返されます。一部抜粋したサンプルレスポンスは以下の通りです。

    {
      "kind": "books#volumes",
      "totalItems": 1,
      "items": [
        {
          "volumeInfo": {
            "title": "Learning JavaScript Design Patterns",
            "authors": ["Addy Osmani"],
            "publisher": "O'Reilly Media",
            "publishedDate": "2012-08-30",
            "description": "A book description.",
            "industryIdentifiers": [
              {
                "type": "ISBN_10",
                "identifier": "1449331815"
              },
              {
                "type": "ISBN_13",
                "identifier": "9781449331818"
              }
            ],
            "pageCount": 254,
            "language": "en",
            "previewLink": "http://books.google.com/..."
          }
        }
      ]
    }

    必要な情報の取り出し

    レスポンスJSONから以下の情報を取り出すには、対応するキーを下記のように利用します。

    • タイトル: items[0].volumeInfo.title
    • 著者名: items[0].volumeInfo.authors
    • 出版社名:items[0].volumeInfo.publisher
    • 出版日: items[0].volumeInfo.publishedDate

    制限事項と注意点

    1. APIキー: 一部のリクエストにはGoogle Cloud Consoleで取得できるAPIキーが必要になる場合があります。
    2. エラー処理: 不正なISBNやネットワークエラーへの対応が必要です。
    3. 利用制限: APIには日単位の利用制限があります。

    進行中の課題と仮説

    問題1: Google Books API のレスポンスにおける「publisher」フィールドの欠落

    • 現象: テストした6冊のデータのうち、すべての書籍で「出版社名」が取得できませんでした。

      「15冊分のISBN番号でテストした結果、出版社情報も正しく表示されることを確認しました。一方で、Google Books APIでは出版社名やカテゴリー情報が少ない傾向があることが分かりました。
    • 仮説: APIレスポンスに publisher フィールドが含まれない書籍が多い可能性。
    • 対策案:
      1. 他の書籍で再テストを行い、再現性を確認。
      2. デフォルト値を設け、ユーザーが手動で補完できる仕組みを検討。
      3. 複数のAPIを併用する

    問題2: 詳細なエラーハンドリングの不足

    • 現象: APIリクエストの失敗や不完全なレスポンスに対する処理が未実装。
    • 対策案:
      • 各種エラーパターンに対応したハンドリングを追加。
      • ログ出力を強化してデバッグを容易にする。

    感想と成功点

    • 成功点:
      • プロジェクト構造を整理し、後の拡張を考慮した設計を実現。
      • Google Books APIの基本的な利用方法を習得し、データ取得が可能になった。
    • 課題:
      • レスポンスに欠落データが多い場合の対策が必要。
      • ISBNコードの読み取り機能や詳細エラー処理の実装がまだ不足している。

    今後の予定

    1. Google Books API のレスポンス解析:
      • 欠落データの原因を特定し、対応策を検討する。
      • 「出版社名」取得の代替案を考える。
    2. エラーハンドリングの改善:
      • リクエストエラーや不完全なレスポンスに対応するロジックを追加。
    3. 次のステップ:
      • カメラでISBNコードを読み取る機能のプロトタイプ作成。
      • 書籍情報をローカルデータベースに保存する仕組みの構築。
      • 書影画像がない場合にデフォルト画像を表示する処理の改善。

    おわりに

    今回はプロジェクトの進捗を中心に振り返りました。課題がいくつか見つかりましたが、これらを解決しながら、Go言語とアジャイル開発の学びを深めていきたいと思います。次回以降、より詳細な実装例や学びのポイントを共有していきますので、ご期待ください!

  • 【初日】「読んだ本のレビューアプリ」開発スタート! ~Go言語×アジャイル×ChatGPT & Copilot~

    【初日】「読んだ本のレビューアプリ」開発スタート! ~Go言語×アジャイル×ChatGPT & Copilot~

    はじめに

    今日から、新しいチャレンジを始めます。それは「読んだ本のレビューを残すアプリ」をGo言語でアジャイル開発し、学びながら進めること。さらに、開発の過程でChatGPTやGitHub CopilotといったAIアシスタントを「仮想ペアプロ」として活用します。

    なぜこんなことをやろうと思ったのか?

    • Go言語を実践的に学びたい
      APIサーバやDB操作、テンプレート処理を通して学ぶ。
    • 読書記録アプリを作りたい
      ISBNで書籍情報を取得し、そこにレビューやメモを残せるプラットフォーム。
    • アジャイル開発で柔軟に
      段階的に機能を増やし、完成度を上げていく。
    • ChatGPT & Copilot活用
      詰まったらChatGPTに相談し、コード補完はCopilotに任せる。
    • 最終的にはカメラでバーコード読み取り
      QuaggaJSやZXingなどのJSライブラリを使い、スマホやPCのカメラでISBNをスキャン→自動的に書籍情報取得する流れを目指す。

    目標とロードマップ

    最終形をざっくりイメージすると、

    1. ISBN検索機能(外部API連携) → 書籍基本情報を取得
    2. レビュー機能 → 書籍情報に対してメモやコメントを保存
    3. バーコード読み取り機能(フロント側) → スマホやPCのカメラでISBNをスキャン、手入力不要
    4. メモ管理(編集・削除・一覧表示) → 本格的なレビューデータベース

    これらをアジャイル的な小さなスプリントで区切って進めます。

    スプリント例

    • スプリント1: ISBN検索API(Goで外部API連携)
    • スプリント2: フロントエンドでISBN入力→検索結果表示
    • スプリント3: DB導入・レビュー記録機能追加
    • スプリント4: レビュー編集・削除、一覧表示
    • スプリント5: QuaggaJSやZXingを使ったバーコード読み取り機能実装
    • スプリント6: デプロイ、UI改善、総仕上げ

    ※ スプリント数や内容は柔軟に変更する可能性あり


    今日(Day 1)の活動結果

    • プロジェクトのディレクトリ作成:
      BookReviewを作成
    (base) ******\projects\go\mkdir BookReview
    (base) ******\projects\go\cd BookReview
    • Gitの初期化:
      git int でディレクトリのディレクトリを作成
    (base) ******\projects\go\BookReview> git init
    • Goの初期化:
      Go言語のプロジェクトフォルダなので go の初期化も設定。

    Go言語プロジェクトでモジュール管理を行う場合、go mod コマンドによる初期化が必要になることがあります。特に、外部パッケージを利用する際や、プロジェクトをより構造的に管理したい場合は以下のステップを踏むことが一般的です。

    コマンド例:

    (base) ******\projects\go\BookReview> go mod init bookreview

    実行結果:

    go: creating new go.mod: module bookreview
    • GitHubリポジトリ作成my-book-review-app のようなプロジェクト名でリポジトリ作成。
    GitHub repositoly
    • HTTPサーバ起動テスト
      簡単なGo HTTPサーバを作り、「Hello, Book Review World!」が表示されるか確認。
    package main
    
    import (
    	"fmt"
    	"net/http"
    )
    
    func handler(w http.ResponseWriter, r *http.Request) {
    	fmt.Fprintln(w, "Hello, Book Review World!")
    }
    
    func main() {
    	http.HandleFunc("/", handler)
    	fmt.Println("サーバーがポート8080で起動しています...")
    	http.ListenAndServe(":8080", nil)
    }
    // ビルドと実行
    (base) ****** \projects\go\BookReview> go build
    (base) ****** \projects\go\BookReview> ./BookReview
    サーバーがポート8080で起動しています...
    // 実行のみ
    (base) ****** \projects\go\BookReview> go run .\main.go
    サーバーがポート8080で起動しています...
    種類の実行方法
    Hello, Book Review World! の表示例
    実行結果です
    • ChatGPT活用:PATH設定でちょっと悩んだが、ChatGPTに質問→すぐ解決できました。
    • GitHub Copilot活用テスト:ハンドラー関数を書く際にCopilotが補完してくれ、今後が楽しみ。

    HTTPサーバ起動テスト用コードの内容確認

    上記で表した Go 言語を使った基本的な Web サーバーを実装したコードについてまとめました。


    1. package main

    • Go プログラムのエントリポイントを示します。main パッケージは実行可能なプログラムを構成する特別なパッケージです。

    2. import 文

    import (
    	"fmt"
    	"net/http"
    )
    
    • 必要なライブラリをインポートしています。
      • fmt: フォーマットされた I/O 関数(例: Println)を提供します。
      • net/http: HTTP サーバーやクライアントを扱うための機能を提供します。

    3. func handler(w http.ResponseWriter, r *http.Request)

    • これは HTTP リクエストを処理するハンドラー関数です。
      • w http.ResponseWriter: HTTP レスポンスを書き込むためのインターフェース。
      • r *http.Request: クライアントから送信された HTTP リクエストを表します。
    • この関数では、fmt.Fprintln を使ってレスポンスに「Hello, Book Review World!」という文字列を書き込んでいます。

    ハンドラー関数とは

    HTTP リクエストを処理するハンドラー関数とは、Webサーバーに来たリクエスト(アクセス)を受け取って、それに対する処理を行う関数のことです。

    この関数は2つの重要な要素を受け取ります。

    • レスポンスライター(w):クライアントへの返信を書き込むためのツール
    • リクエスト(r):クライアントから送られてきた情報

    具体的には、このコードではクライアントがアクセスしてきた時に「Hello, Book Review World!」というメッセージを返す処理を行っています。


    4. func main()

    • プログラムのエントリポイントです。以下の処理を行います。

    エントリーポイントとは?

    エントリーポイントとは、プログラムの実行が開始される場所を指します。

    Go言語では、mainパッケージ内のmain関数がエントリーポイントとなり、プログラムはここから実行が始まります。

    このプログラムの場合、main関数の中で

    • HTTPハンドラーの設定
    • サーバーの起動
    • ポート8080でのリッスン開始

    という一連の処理が実行されます。

    (1) http.HandleFunc("/", handler)

    • ルート URL("/")にアクセスしたときに実行されるハンドラー関数を登録します。
      • ここでは handler 関数が登録されています。
      はい、その通りです。このコードの流れは以下のようになっています:
      1. main関数内でhttp.HandleFunc("/", handler)を使って、ルートURL(”/”)へのアクセスがあった時に実行される関数としてhandlerを登録します。
      2. クライアントがWebサーバーのルートURLにアクセスすると、登録されたhandler関数が呼び出され、「Hello, Book Review World!」というメッセージを返します。
      これは、Webサーバーでよく使われる「ルーティング」と呼ばれる仕組みの基本的な例です。特定のURLパターンに対して、それを処理する関数を関連付けているのです。

    (2) fmt.Println("サーバーがポート8080で起動しています...")

    • コンソールにサーバーが起動中であることを表示します。

    (3) http.ListenAndServe(":8080", nil)

    • ポート 8080 で HTTP サーバーを起動します。
      • ":8080": サーバーがリッスンするポート番号。
      • nil: デフォルトのマルチプレクサを使用することを指定しています。

    実行結果

    1. プログラムを起動すると、ターミナルに以下が表示されます。 コードをコピーする サーバーがポート8080で起動しています...
    2. ブラウザで http://localhost:8080/ にアクセスすると、以下のレスポンスが表示されます。 コードをコピーする Hello, Book Review World!

    学べるポイント

    1. HTTP サーバーの起動方法
      • Go では net/http パッケージを使って簡単に Web サーバーを構築できます。
    2. ハンドラー関数の作成
      • HTTP リクエストを処理するカスタムロジックを実装できます。
    3. ポートの指定
      • ポート番号を指定することで、どのポートでサーバーを動作させるかを制御します。
    4. シンプルな構成
      • Go の標準ライブラリだけで基本的な Web アプリケーションを構築可能です。

    このコードをベースに、さらに機能を追加してアプリケーションを拡張していくことができます!

    明日以降にやること

    • Day 2: Google Books APIなどを叩いて、ISBN指定でタイトル取得のプロトタイプを作る。
    • 中盤: DB導入し、書籍レビューを保存できるようにする。
    • 後半: QuaggaJSやZXingでカメラアクセス実装→バーコード読み取り→ISBN取得→書籍情報表示の流れを完成!

    なぜバーコード読み取り?

    入力を極力簡略化したいからです。

    • 手でISBNを入力する手間を省く
    • スマホのカメラで本のバーコード(ISBN)をスキャン→即座に書籍情報表示→レビュー記入、というスムーズなUXを提供したい

    まとめ

    今日は地ならし。Go言語でHello World的なHTTPサーバが起動できました。明日から、いよいよISBN検索APIの実装に入っていきます。最終的にはカメラでバーコード読み取りも実現し、より便利な読書記録ツールに育てていく予定。ChatGPT & Copilotと二人三脚で、試行錯誤しながら前進していきます!