📑

Gemini CLIを先生として使う

に公開

バイブコーディングしていますか?
例えば五目並べであったり、簡単なパズルゲームのように要件と仕様が明確になっているものは比較的しっかりと作成してくれるように思いますが、そうではない仕様が曖昧なものは当然、曖昧な成果物しか生成してくれません。これは対人間でも同じだと思っていますが、人間の高い適応力で”いい感じ”にやっている事が多いのかなと思っています。
正しく仕様整理し、言語化することがしばらく人間に求められるスキルになるような気がします。
今回、Gemini CLIを学習のために使用してみました。
VSCodeからGemini CLIを使用するととても嬉しいです。

↓Gemini CLIに聞いた、Gemini CLIの説明

  1. Gemini CLIとは?
    Gemini CLIは、Googleが開発したオープンソースのコマンドラインAIアシスタントです。ターミナル(コマンドプロンプトやPowerShellなど)から直接、Googleの高性能AIモ
    デル「Gemini」と対話し、開発に関する様々なタスクを支援してもらうことができます。

  2. 主な機能・できること

  • コードに関する対話:
    • コード生成: 「〇〇する関数を作って」といった指示でコードを生成します。
    • リファクタリング: 「このコードをより効率的にして」と頼むと、改善案を提示します。
    • コード解説: 複雑なコードや他人が書いたコードについて「この処理は何をしているの?」と質問すれば、自然言語で解説してくれます。
    • バグ修正: エラーメッセージを貼り付けて「このエラーの原因は?」と聞けば、解決策を探ってくれます。
  • ファイル操作とコンテキスト理解:
    • カレントディレクトリや指定したファイルの内容を理解し、プロジェクト全体の文脈を踏まえた回答を生成します。
    • 「authに関連するファイルを探して」といった指示で、プロジェクト内を検索できます。
  • コマンドの実行とテスト:
    • 「このプロジェクトのテストを実行して」といった指示で、テストコマンドを提案・実行します。
    • 安全のため、実行前に必ずユーザーに確認を求めます。
  • 汎用的な質問応答:
    • プログラミング言語の仕様や、新しいライブラリの使い方など、開発に関する一般的な質問にも答えます。
  1. インストールとセットアップ
    Gemini CLIはNode.jsのパッケージとして提供されています。インストールは非常に簡単です。
  2. Node.jsのインストール:
    • まだインストールしていない場合は、Node.js公式サイト (https://nodejs.org/)からLTS版をダウンロードしてインストールしてください。
  3. Gemini CLIのインストール:
    • ターミナルを開き、以下のコマンドを実行します。
npm install -g @google/gemini-cli
  1. 認証:
    • インストール後、geminiコマンドを初めて実行すると、Googleアカウントでの認証が求められます。ブラウザが開き、認証プロセスを進めることになります。
gemini auth login
  1. 具体的な使い方(コマンド例)
    基本的には gemini [やりたいこと] の形式で使います。
  • カレントディレクトリのファイルを要約してもらう:
gemini "Summarize the files in the current directory."
  • 特定のファイルについて質問する:
gemini "Explain the main function in src/index.js"
  • コードを生成してもらう:
list with all strings in uppercase."
  • Gitコマンドを教えてもらう:
gemini "How do I revert the last commit?"
  1. 他のAIツールとの違い
  • GitHub Copilot CLIとの比較:
    • モデル: CopilotがOpenAIのモデル(GPTシリーズ)をベースにしているのに対し、Gemini CLIはGoogleのGeminiモデル(無料枠ではGemini 1.5
      Flash)を使用します。
    • エコシステム: Gemini CLIはGoogle CloudやGemini Code Assist(IDE拡張機能)との連携がスムーズです。
    • オープンソース: Gemini CLIはオープンソースであり、誰でも開発に参加できる点が大きな特徴です。Copilotはクローズドソースです。
  • ChatGPTとの比較:
    • ChatGPTが汎用的な対話AIであるのに対し、Gemini CLIは開発者のワークフローに特化しており、ローカルのファイルシステムと直接連携できる点が強みです。

ロールの設定

まずは立場を明確にします。
Geminiが先生、自分が生徒であることを明示します。
そのうえで、Geminiが先生の振る舞いをするために必要な要素などを質問することもできるので、そのように学習したいかを前提条件としてしっかりと決めるのがよいです。

今回、HTML+javascriptの学習を行い、問題形式で出題してもらいました。
また、自分能力として他言語の経験から基本文法の理解があることを前提として、その上で実装目標と仕様、ヒントの提示をしてもらいます。

出題された課題

問題形式が全部で何問になるか確認していませんでしたが、結果的に7問の問題となりました。
記録として課題の概要を以降に残します。
記載したコードはGeminiでリファクタリングを実施後です。

課題1 クリックイベント

ボタンクリックしたことをpタグに表示する

     <h1>課題1</h1>
     <button id="button">クリック!</button>
     <p></p>
    const button = document.getElementById('button');
    const p = document.querySelector('p'); // 最初のpタグを取得
    button.addEventListener('click', () => {
        p.textContent = 'ボタンがクリックされました!';
    });

課題2 挨拶ジェネレーター

inputタグから入力値を取得し、pタグに表示する

    <h1>課題2</h1>
    <input type="text" id="name-input">
    <button id="greeting-button">挨拶する</button>
    <p id="output-area"></p>
    const nameInput = document.getElementById('name-input');
    const greetingButton = document.getElementById('greeting-button');
    const outputArea = document.getElementById('output-area');

    greetingButton.addEventListener('click', () => {
        const name = nameInput.value.trim();
        outputArea.textContent = name ? `こんにちは、${name}さん!` : '';
    });

課題3:ToDoリスト(要素の追加)

  目標:
  今度は、簡単なToDoリストを作成します。ユーザーが入力欄にタスクを書き込み、「追加」ボタンを押すと、そのタスクがリストにどんどん追加されていく機能を作ってみ
  ましょう。

  要件:
   1. HTMLの準備:
       * index.html を変更して、以下の要素を配置してください。
           * タスクを入力するためのテキスト入力欄 (<input type="text">)。IDを付けましょう (例: id="task-input")。
           * タスクを追加するためのボタン (<button>)。表示名は「追加」。IDを付けましょう (例: id="add-button")。
           * タスクのリストを表示するための、順序なしリスト (<ul>)。IDを付けましょう (例: id="todo-list")。

   2. JavaScriptのロジック:
       * <script> タグの中身を、以下のロジックを実装するように書き換えてください。
           * 入力欄、追加ボタン、リスト(<ul>)の3つの要素を、IDを使って取得します。
           * 追加ボタンがクリックされたら、以下の処理を実行します。
               1. 入力欄に入力されている値(value)を取得します。
               2. もし入力値が空でなければ, 以下の処理に進みます。(空の場合は何もしません)
               3. document.createElement('li') を使って、新しいリストアイテム要素 (<li>) を作成します。
               4. 作成した <li> 要素のテキスト内容 (textContent) に、入力欄から取得した値を設定します。
               5. <ul> 要素の子要素として、作成した <li> 要素を追加します。(appendChild というメソッドを使います)
               6. 【挑戦】タスクを追加した後、入力欄を空にしてみましょう。

  ヒント:
   * 新しいHTML要素をJavaScriptで作成するには document.createElement('タグ名') を使います。
   * ある要素の子要素として、別の要素を追加するには 親要素.appendChild(子要素) という構文を使います。

課題4:ToDoリスト(要素の削除)

  要件:
   1. JavaScriptのロジック変更:
       * 課題3で作成した、タスクを追加する処理の中に、以下の機能を追加します。
           1. <li> 要素を作成するのと同時に、削除ボタン (<button>) も document.createElement('button') で作成します。
           2. 作成した削除ボタンのテキスト (textContent) を「削除」に設定します。
           3. ここがポイントです: 作成した削除ボタンに、クリックされたときの処理 (addEventListener) を設定します。その処理内容は以下の通りです。
               * クリックされた削除ボタンの 親要素 である <li> 要素を、<ul> リストから削除する。
           4. <li> 要素に、タスクのテキストだけでなく、この削除ボタンも追加 (appendChild) します。

課題5:ToDoリスト(ローカルストレージへの保存と復元)

目標:
 現状のToDoリストは、ページをリロード(再読み込み)すると全てのタスクが消えてしまいます。これを、ブラウザを閉じてもタスクが消えないように、ローカルストレー
  ジ (Local Storage) という仕組みを使ってデータを保存・復元できるようにします。

 ローカルストレージとは?
 ウェブブラウザに備わっている、簡単なデータをキーと値のペアで保存しておける機能です。サーバーは不要で、ユーザーのコンピュータ内にデータが保存されます。

 要件:
  1. タスクの保存:
       * タスクが 追加 された時、または 削除
         された時に、現在のToDoリストの状態(全てのタスクのテキスト)を配列として取得し、ローカルストレージに保存します。

 2. タスクの復元:
       * ページが 読み込まれた時 に、ローカルストレージに保存されているデータがあるかどうかを確認します。
       * もしデータがあれば、そのデータを使ってToDoリストの <li> 要素を復元し、画面に表示します。
     <h1>課題3</h1>
     <input type="text" id="task-input">
     <button id="add-button">追加</button>
     <ul id="todo-list"></ul>
   // --- 定数 ---
    const STORAGE_KEY = 'todo-tasks'; // ローカルストレージのキー

    // --- DOM要素 ---
    const taskInput = document.getElementById('task-input');
    const addButton = document.getElementById('add-button');
    const todoList = document.getElementById('todo-list');

    // --- 関数 ---

    // タスク要素(li)を画面に追加する関数
    const addTaskToDOM = (taskText) => {
        const li = document.createElement('li');
        const span = document.createElement('span');
        const deleteButton = document.createElement('button');

        span.textContent = taskText;
        deleteButton.className = 'del-button';
        deleteButton.textContent = '削除';

        li.appendChild(span);
        li.appendChild(deleteButton);
        todoList.appendChild(li);
    };

    // 現在のタスクリストをストレージに保存する関数
    const saveTasks = () => {
        const listItems = todoList.querySelectorAll('li span');
        const tasks = Array.from(listItems).map(span => span.textContent);
        localStorage.setItem(STORAGE_KEY, JSON.stringify(tasks));
    };

    // ストレージからタスクを読み込んで画面に表示する関数
    const loadTasks = () => {
        const tasksJson = localStorage.getItem(STORAGE_KEY);
        if (!tasksJson) return; // データがなければ何もしない

        const tasks = JSON.parse(tasksJson);
        tasks.forEach(task => addTaskToDOM(task));
    };

   // --- イベントリスナー ---
    // [追加]ボタンのクリックイベント
    addButton.addEventListener('click', () => {
    const taskText = taskInput.value.trim();
    if (taskText) {
        addTaskToDOM(taskText);
        saveTasks();
        taskInput.value = '';
    }
    });
    
    // [削除]ボタンのクリックイベント(イベント移譲)
    todoList.addEventListener('click', (event) => {
    if (event.target.className === 'del-button') {
        const li = event.target.parentElement;
        todoList.removeChild(li);
        saveTasks();
    }
    });
    
    // --- 初期化処理 ---
    loadTasks(); // ページ読み込み時にタスクを復元

課題7: 天気予報

APIを利用した天気予報情報の取得

Discussion