基礎から学ぶC#入門 90日コース | アプリを作りながら学ぶ - Day 71:要件定義

Web APP 90日で身につけるC#
スポンサーリンク
スポンサーリンク

Day 71 のゴールと全体像

第8章では、いよいよ「アプリを作りながら学ぶ」フェーズに入っていきます。 Day 71 は、その最初の一歩――タスク管理アプリの要件定義の日です。

今日はまだ「ガリガリ実装する日」ではなく、

  • どんな機能を持ったアプリにするのか
  • そのために、どんなデータ構造が必要になりそうか
  • 画面(今回はコンソール)でどう操作できると気持ちいいか

を、ゆっくり言葉にしていく時間です。

扱うキーワードは次のとおりです。

  • タスク追加
  • タスク一覧
  • タスク検索
  • タスク編集
  • タスク削除
  • 完了管理
  • 優先度
  • 期限

これらを、ひとつひとつ「どういう動きがあると嬉しいか」をイメージしながら、 最終的に 「タスク管理アプリの基本設計」 まで持っていきます。

タスク管理アプリの全体イメージ

どんなアプリにしたいかをざっくり描く

まずは、アプリのざっくりしたイメージを言葉にしてみます。

  • コンソールベースのタスク管理アプリ
  • メニューから操作できる
  • タスクを追加して、一覧で確認できる
  • タスクを検索したり、編集・削除したりできる
  • 「完了したかどうか」「優先度」「期限」を管理できる

たとえば、こんな画面をイメージしてみてください。

=== タスク管理アプリ ===
1: タスク追加
2: タスク一覧
3: タスク検索
4: タスク編集
5: タスク削除
6: 完了状態の切り替え
7: 優先度で並び替え
8: 期限が近いタスク表示
0: 終了
選択してください:

この「メニューの顔」が、アプリの性格を決めていきます。

タスクという「データの形」を決める

タスクに必要な項目を洗い出す

機能を考える前に、 まずは「タスクって、どんな情報を持っているべきか?」を整理します。

今回の要件から、タスクに必要そうな項目は次のとおりです。

  • タスクID(識別子)
  • タスク名(タイトル)
  • 詳細(メモ・説明)
  • 完了フラグ(完了したかどうか)
  • 優先度(高・中・低など)
  • 期限(締め切りの日付)

これを C# のクラスにすると、こんなイメージになります。

// タスクを表すクラス
class TaskItem
{
    public int Id { get; set; }              // 一意なID
    public string Title { get; set; }        // タスク名
    public string Description { get; set; }  // 詳細・メモ
    public bool IsCompleted { get; set; }    // 完了しているかどうか
    public int Priority { get; set; }        // 優先度(数値で管理:1=高, 2=中, 3=低 など)
    public DateTime? DueDate { get; set; }   // 期限(ない場合もあるので ? にしておく)
}
C#

コメントを付けておくことで、 「このプロパティは何を意味しているのか」が読みやすくなります。

Day 71 の時点では、 「タスクの形をこうしておこう」というレベルで十分です。 実際のロジックは、Day 72 以降で育てていきます。

機能1:タスク追加

どんな動きにしたいか

タスク追加は、このアプリのいちばん基本的な機能です。

イメージとしては、

  1. タスク名を入力する
  2. 詳細(メモ)を入力する
  3. 優先度を選ぶ(1: 高, 2: 中, 3: 低)
  4. 期限を入力する(任意)
  5. タスク一覧に追加される

という流れです。

コードのイメージ

// タスク一覧を管理するリスト
List<TaskItem> tasks = new List<TaskItem>();
int nextId = 1; // IDを連番で振るためのカウンタ

void AddTask()
{
    Console.Write("タスク名を入力してください: ");
    string title = Console.ReadLine();

    Console.Write("詳細(メモ)を入力してください: ");
    string description = Console.ReadLine();

    Console.Write("優先度を入力してください (1: 高, 2: 中, 3: 低): ");
    int priority = int.Parse(Console.ReadLine());

    Console.Write("期限を入力してください (yyyy-MM-dd、未入力ならスキップ): ");
    string dueText = Console.ReadLine();
    DateTime? dueDate = null;
    if (!string.IsNullOrWhiteSpace(dueText))
    {
        // 期限が入力されている場合だけ DateTime に変換
        dueDate = DateTime.Parse(dueText);
    }

    var task = new TaskItem
    {
        Id = nextId++,
        Title = title,
        Description = description,
        Priority = priority,
        DueDate = dueDate,
        IsCompleted = false // 追加時点では未完了
    };

    tasks.Add(task);

    Console.WriteLine("タスクを追加しました。");
}
C#

ここでは、

  • nextId でタスクIDを連番で振る
  • 期限は任意入力なので、空なら null にしておく
  • 追加時点では IsCompleted = false にしておく

という要件を、コードに落とし込んでいます。

機能2:タスク一覧

どんな表示が気持ちいいか

タスク一覧は、アプリの「顔」ともいえる機能です。

  • ID
  • 完了状態
  • 優先度
  • 期限
  • タイトル

あたりを、コンパクトに表示できると気持ちいいですね。

コードのイメージ

void ShowTasks()
{
    Console.WriteLine("=== タスク一覧 ===");

    if (tasks.Count == 0)
    {
        Console.WriteLine("タスクが登録されていません。");
        return;
    }

    foreach (var t in tasks)
    {
        string status = t.IsCompleted ? "[完了]" : "[未完了]";
        string priorityText = t.Priority switch
        {
            1 => "高",
            2 => "中",
            3 => "低",
            _ => "不明"
        };

        string dueText = t.DueDate.HasValue
            ? t.DueDate.Value.ToString("yyyy-MM-dd")
            : "期限なし";

        Console.WriteLine($"ID: {t.Id} {status} 優先度: {priorityText} 期限: {dueText} タイトル: {t.Title}");
    }
}
C#

ここでは、

  • 完了状態を [完了] / [未完了] で表示
  • 優先度を数値から「高・中・低」に変換
  • 期限がない場合は「期限なし」と表示

という、人間にとって読みやすい表示を意識しています。

機能3:タスク検索

どんな検索があると便利か

検索機能は、

  • タイトルに含まれるキーワードで検索
  • 完了状態で絞り込み
  • 優先度で絞り込み

など、いろいろ考えられますが、 Day 71 の段階では、まず 「タイトルの部分一致検索」 を要件として決めておくとよいです。

コードのイメージ

void SearchTasks()
{
    Console.Write("検索キーワードを入力してください(タイトルに対して検索します): ");
    string keyword = Console.ReadLine();

    var results = tasks.FindAll(t =>
        !string.IsNullOrEmpty(t.Title) &&
        t.Title.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0);

    Console.WriteLine("=== 検索結果 ===");

    if (results.Count == 0)
    {
        Console.WriteLine("該当するタスクがありませんでした。");
        return;
    }

    foreach (var t in results)
    {
        string status = t.IsCompleted ? "[完了]" : "[未完了]";
        Console.WriteLine($"ID: {t.Id} {status} タイトル: {t.Title}");
    }
}
C#

ここでは、

  • タイトルにキーワードが含まれているかどうかで検索
  • 大文字・小文字を区別しない検索にしている

という要件を、コードに反映しています。

機能4:タスク編集

どんな編集ができると嬉しいか

タスク編集では、

  • タイトル
  • 詳細
  • 優先度
  • 期限

などを変更できるようにしたいところです。

編集の流れとしては、

  1. 編集したいタスクの ID を入力する
  2. 該当タスクを表示する
  3. 各項目について「変更するかどうか」を聞く
  4. 入力があれば更新する

という形が分かりやすいです。

コードのイメージ

void EditTask()
{
    Console.Write("編集したいタスクのIDを入力してください: ");
    int id = int.Parse(Console.ReadLine());

    var task = tasks.Find(t => t.Id == id);
    if (task == null)
    {
        Console.WriteLine("指定されたIDのタスクが見つかりませんでした。");
        return;
    }

    Console.WriteLine($"現在のタイトル: {task.Title}");
    Console.Write("新しいタイトル(変更しない場合は空のまま): ");
    string newTitle = Console.ReadLine();
    if (!string.IsNullOrWhiteSpace(newTitle))
    {
        task.Title = newTitle;
    }

    Console.WriteLine($"現在の詳細: {task.Description}");
    Console.Write("新しい詳細(変更しない場合は空のまま): ");
    string newDesc = Console.ReadLine();
    if (!string.IsNullOrWhiteSpace(newDesc))
    {
        task.Description = newDesc;
    }

    Console.WriteLine($"現在の優先度: {task.Priority}");
    Console.Write("新しい優先度 (1: 高, 2: 中, 3: 低、変更しない場合は空のまま): ");
    string newPriorityText = Console.ReadLine();
    if (!string.IsNullOrWhiteSpace(newPriorityText))
    {
        task.Priority = int.Parse(newPriorityText);
    }

    Console.WriteLine($"現在の期限: {(task.DueDate.HasValue ? task.DueDate.Value.ToString("yyyy-MM-dd") : "期限なし")}");
    Console.Write("新しい期限 (yyyy-MM-dd、空なら期限なしに変更): ");
    string newDueText = Console.ReadLine();
    if (string.IsNullOrWhiteSpace(newDueText))
    {
        task.DueDate = null;
    }
    else
    {
        task.DueDate = DateTime.Parse(newDueText);
    }

    Console.WriteLine("タスクを更新しました。");
}
C#

編集機能は少し長くなりますが、 「現在の値を表示してから、変更するかどうかを聞く」 という流れにすると、ユーザーにとって親切な設計になります。

機能5:タスク削除

シンプルだけど慎重さが必要な機能

削除はシンプルですが、 「本当に消していいかどうか」を確認したくなる機能でもあります。

コードのイメージ

void DeleteTask()
{
    Console.Write("削除したいタスクのIDを入力してください: ");
    int id = int.Parse(Console.ReadLine());

    var task = tasks.Find(t => t.Id == id);
    if (task == null)
    {
        Console.WriteLine("指定されたIDのタスクが見つかりませんでした。");
        return;
    }

    Console.WriteLine($"削除対象: ID={task.Id}, タイトル={task.Title}");
    Console.Write("本当に削除しますか? (y/n): ");
    string confirm = Console.ReadLine();

    if (confirm?.ToLower() == "y")
    {
        tasks.Remove(task);
        Console.WriteLine("タスクを削除しました。");
    }
    else
    {
        Console.WriteLine("削除をキャンセルしました。");
    }
}
C#

ここでは、

  • 削除前に対象タスクを表示
  • y の確認があった場合のみ削除

という、安全寄りの設計を要件として決めています。

機能6:完了管理

完了状態を切り替える

完了管理は、

  • タスクを「完了」にする
  • 間違えて完了にしたものを「未完了」に戻す

という、トグル(切り替え)型の操作が分かりやすいです。

コードのイメージ

void ToggleComplete()
{
    Console.Write("完了状態を切り替えたいタスクのIDを入力してください: ");
    int id = int.Parse(Console.ReadLine());

    var task = tasks.Find(t => t.Id == id);
    if (task == null)
    {
        Console.WriteLine("指定されたIDのタスクが見つかりませんでした。");
        return;
    }

    task.IsCompleted = !task.IsCompleted; // true/false を反転

    Console.WriteLine($"タスクの完了状態を変更しました。現在の状態: {(task.IsCompleted ? "完了" : "未完了")}");
}
C#

このように、 「完了状態を反転させる」というシンプルな操作にしておくと、 ユーザーも直感的に扱いやすくなります。

機能7:優先度

優先度をどう扱うか

優先度は、

  • タスク追加時に設定する
  • 編集で変更できる
  • 一覧表示で「優先度順に並べる」機能を追加する

という形で扱うと、アプリとしての“便利さ”がぐっと増します。

並び替えのイメージ

void ShowTasksByPriority()
{
    Console.WriteLine("=== 優先度順タスク一覧 ===");

    var ordered = tasks
        .OrderBy(t => t.Priority)      // 1(高) → 2(中) → 3(低)
        .ThenBy(t => t.DueDate ?? DateTime.MaxValue); // 同じ優先度なら期限が早い順

    foreach (var t in ordered)
    {
        string priorityText = t.Priority switch
        {
            1 => "高",
            2 => "中",
            3 => "低",
            _ => "不明"
        };

        string dueText = t.DueDate.HasValue
            ? t.DueDate.Value.ToString("yyyy-MM-dd")
            : "期限なし";

        Console.WriteLine($"ID: {t.Id} 優先度: {priorityText} 期限: {dueText} タイトル: {t.Title}");
    }
}
C#

Day 71 の段階では、 「優先度は数値で管理して、表示時に文字に変換する」 という方針を決めておくだけでも十分です。

機能8:期限

期限をどう活かすか

期限は、

  • タスク追加・編集で設定できる
  • 一覧表示で見えるようにする
  • 「期限が近いタスクだけ表示する」機能を作る

といった形で活用できます。

期限が近いタスク表示のイメージ

void ShowUpcomingTasks()
{
    Console.Write("何日以内の期限のタスクを表示しますか?: ");
    int days = int.Parse(Console.ReadLine());

    DateTime now = DateTime.Now;
    DateTime limit = now.AddDays(days);

    var upcoming = tasks.FindAll(t =>
        t.DueDate.HasValue &&
        t.DueDate.Value >= now &&
        t.DueDate.Value <= limit);

    Console.WriteLine($"=== 期限が {days} 日以内のタスク ===");

    if (upcoming.Count == 0)
    {
        Console.WriteLine("該当するタスクがありませんでした。");
        return;
    }

    foreach (var t in upcoming)
    {
        Console.WriteLine($"ID: {t.Id} 期限: {t.DueDate.Value:yyyy-MM-dd} タイトル: {t.Title}");
    }
}
C#

Day 71 では、 「期限を DateTime? で持って、こういう使い方ができる」 というイメージを持っておくことが大切です。

Day 71 用ミニテンプレート:要件定義の骨組み

最後に、今日の内容を「要件定義の骨組み」としてまとめておきます。

タスクのデータ構造

class TaskItem
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public bool IsCompleted { get; set; }
    public int Priority { get; set; }      // 1: 高, 2: 中, 3: 低
    public DateTime? DueDate { get; set; } // 期限(任意)
}
C#

必要な機能一覧(コンソールメニュー想定)

  • タスク追加
  • タスク一覧
  • タスク検索(タイトル部分一致)
  • タスク編集
  • タスク削除
  • 完了状態の切り替え
  • 優先度順の一覧表示
  • 期限が近いタスクの表示

この「機能のリスト」と「タスクの形」が決まっていれば、 Day 72 以降で、実際の実装にスムーズに入っていけます。

Day 71 のまとめ

Day 71 では、

  • タスク管理アプリの全体イメージを描き
  • タスクという「データの形」をクラスとして定義し
  • タスク追加・一覧・検索・編集・削除・完了管理・優先度・期限 それぞれの機能について「どう動くと気持ちいいか」を言葉にし
  • それを簡単なコードイメージに落とし込んでいきました。

要件定義は、 「コードを書く前に、アプリの性格を決める時間」です。

ここでしっかりイメージを固めておくと、 次の日からの実装がぐっと楽になり、 迷いが少ない状態でコードを書いていけます。

ぜひ、

  • 自分ならどんなメニュー構成にしたいか
  • どんな表示があると嬉しいか
  • どこまで機能を絞るとちょうどよさそうか

といったことを、少し自分なりに考え直してみながら、 Day 72 以降の「タスク管理アプリ制作」に進んでいっていただければうれしいです。

タイトルとURLをコピーしました