☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
專案實戰 初學

專案規劃與需求分析

為什麼需要規劃?

💡 比喻:蓋房子先畫藍圖 你不會叫工人直接搬磚頭開始蓋房子吧? 一定是先找建築師畫好藍圖,確認幾間房間、幾間廁所、電線怎麼走。 寫程式也一樣——先規劃好,才不會蓋到一半才發現要拆牆重來。

沒有規劃的專案會怎樣?

沒有規劃的專案:
第 1 週:興致勃勃開始寫 code ✨
第 2 週:發現資料庫設計不對,砍掉重來 💣
第 3 週:客戶說「我要的不是這個」 😱
第 4 週:放棄 💀

有規劃的專案:
第 1 週:寫需求文件 + 畫流程圖 📐
第 2 週:確認規格 + 設計 Schema 📋
第 3 週:開始寫 code(方向清楚) 💻
第 4 週:第一版完成 + Demo 🎉

從想法到規格書

第一步:把想法寫下來

// 定義專案想法的類別 // Define project idea class
public class ProjectIdea // 專案想法類別
{
    public string Name { get; set; } = ""; // 專案名稱
    public string Description { get; set; } = ""; // 專案描述
    public string TargetAudience { get; set; } = ""; // 目標使用者
    public string ProblemToSolve { get; set; } = ""; // 要解決的問題
    public List<string> CoreFeatures { get; set; } = new(); // 核心功能清單
}

// 範例:電商網站的專案想法 // Example: e-commerce project idea
var idea = new ProjectIdea // 建立電商專案想法
{
    Name = "小農直售平台", // 設定專案名稱
    Description = "讓小農可以直接賣農產品給消費者", // 設定專案描述
    TargetAudience = "小農 + 注重食安的消費者", // 設定目標族群
    ProblemToSolve = "中間商抽太多,小農沒賺到錢", // 設定要解決的問題
    CoreFeatures = new List<string> // 列出核心功能
    {
        "商品上架管理", // 功能一:商品管理
        "購物車與結帳", // 功能二:購物流程
        "訂單追蹤", // 功能三:訂單管理
        "會員系統" // 功能四:會員功能
    }
};

User Story 撰寫法

💡 比喻:點菜單 User Story 就像餐廳的菜單——寫清楚「誰要吃什麼」以及「為什麼想吃」。 格式固定:身為(角色),我想要(功能),以便(目的)

User Story 範本

// 定義 User Story 類別 // Define User Story class
public class UserStory // 使用者故事類別
{
    public string Role { get; set; } = ""; // 角色(誰在用)
    public string Want { get; set; } = ""; // 想要什麼功能
    public string SoThat { get; set; } = ""; // 目的是什麼
    public string Priority { get; set; } = ""; // 優先順序
    public List<string> AcceptanceCriteria { get; set; } = new(); // 驗收標準
}

// 撰寫 User Story 範例 // Write User Story examples
var stories = new List<UserStory> // 建立使用者故事清單
{
    new UserStory // 第一個故事:商品瀏覽
    {
        Role = "消費者", // 角色是消費者
        Want = "瀏覽商品清單並篩選分類", // 想要瀏覽和篩選商品
        SoThat = "快速找到想買的農產品", // 目的是快速找到商品
        Priority = "Must", // 優先順序:必須有
        AcceptanceCriteria = new List<string> // 驗收標準清單
        {
            "能顯示所有商品的卡片式列表", // 標準一:卡片式顯示
            "能按分類篩選(蔬菜、水果、米糧)", // 標準二:分類篩選
            "能按價格排序(高到低、低到高)", // 標準三:價格排序
            "每頁顯示 12 筆,有分頁功能" // 標準四:分頁功能
        }
    },
    new UserStory // 第二個故事:購物車
    {
        Role = "消費者", // 角色是消費者
        Want = "將商品加入購物車並調整數量", // 想要管理購物車
        SoThat = "一次購買多樣商品", // 目的是批量購買
        Priority = "Must", // 優先順序:必須有
        AcceptanceCriteria = new List<string> // 驗收標準清單
        {
            "點擊加入購物車後顯示成功提示", // 標準一:加入回饋
            "購物車頁面可修改數量", // 標準二:修改數量
            "能顯示小計與總計金額", // 標準三:金額計算
            "能刪除購物車中的商品" // 標準四:刪除功能
        }
    }
};

// 輸出 User Story 格式 // Output formatted User Story
foreach (var story in stories) // 逐一輸出每個故事
{
    var output = $"身為 {story.Role}," + // 組合角色部分
                 $"我想要 {story.Want}," + // 組合功能部分
                 $"以便 {story.SoThat}"; // 組合目的部分
    Console.WriteLine(output); // 印出完整的 User Story
    Console.WriteLine($"優先順序:{story.Priority}"); // 印出優先順序
}

功能拆解與優先排序 (MoSCoW)

💡 比喻:搬家打包 搬家時你會分類:一定要帶的(身分證、錢包)、應該帶的(換洗衣物)、 可以帶的(書本)、不帶的(舊雜誌)。 MoSCoW 就是幫功能做一樣的分類。

// 定義 MoSCoW 優先順序列舉 // Define MoSCoW priority enum
public enum MoSCoWPriority // MoSCoW 優先順序
{
    Must,   // 必須有:沒有這個系統不能用 // Must have
    Should, // 應該有:很重要但可以晚一點做 // Should have
    Could,  // 可以有:有的話更好 // Could have
    Wont    // 不做:這次不做,未來再說 // Won't have
}

// 定義功能項目類別 // Define feature item class
public class FeatureItem // 功能項目類別
{
    public string Name { get; set; } = ""; // 功能名稱
    public MoSCoWPriority Priority { get; set; } // MoSCoW 優先等級
    public int EstimatedDays { get; set; } // 預估天數
    public string Note { get; set; } = ""; // 備註說明
}

// 電商網站的功能拆解 // Feature breakdown for e-commerce
var features = new List<FeatureItem> // 建立功能清單
{
    // Must(必須有) // 沒這些就不能上線
    new() { Name="會員註冊登入", Priority=MoSCoWPriority.Must, EstimatedDays=3, Note="用 Identity Framework" }, // 會員系統
    new() { Name="商品 CRUD", Priority=MoSCoWPriority.Must, EstimatedDays=4, Note="含圖片上傳" }, // 商品管理
    new() { Name="購物車", Priority=MoSCoWPriority.Must, EstimatedDays=3, Note="Session + DB 雙軌" }, // 購物車功能
    new() { Name="訂單建立", Priority=MoSCoWPriority.Must, EstimatedDays=3, Note="含庫存扣減" }, // 訂單功能

    // Should(應該有) // 第一版之後盡快做
    new() { Name="商品搜尋", Priority=MoSCoWPriority.Should, EstimatedDays=2, Note="關鍵字 + 分類" }, // 搜尋功能
    new() { Name="Email 通知", Priority=MoSCoWPriority.Should, EstimatedDays=2, Note="訂單確認信" }, // 通知功能
    new() { Name="訂單狀態追蹤", Priority=MoSCoWPriority.Should, EstimatedDays=2, Note="狀態機設計" }, // 追蹤功能

    // Could(可以有) // 有時間再做
    new() { Name="商品評價", Priority=MoSCoWPriority.Could, EstimatedDays=3, Note="星等 + 文字評論" }, // 評價功能
    new() { Name="推薦系統", Priority=MoSCoWPriority.Could, EstimatedDays=5, Note="基於購買紀錄" }, // 推薦功能

    // Won't(不做) // 這次不做
    new() { Name="即時聊天", Priority=MoSCoWPriority.Wont, EstimatedDays=7, Note="改用 LINE 客服" }, // 聊天功能
};

// 統計各優先級的工作天數 // Calculate total days per priority
var summary = features // 從功能清單開始
    .GroupBy(f => f.Priority) // 依優先順序分組
    .Select(g => new // 建立統計物件
    {
        Priority = g.Key, // 優先等級
        Count = g.Count(), // 功能數量
        TotalDays = g.Sum(f => f.EstimatedDays) // 總天數
    })
    .OrderBy(s => s.Priority); // 依優先順序排序

foreach (var item in summary) // 逐一輸出統計結果
{
    Console.WriteLine($"{item.Priority}: {item.Count} 個功能,共 {item.TotalDays} 天"); // 印出統計
}

資料庫 Schema 設計流程

💡 比喻:收納箱貼標籤 設計 Schema 就像整理房間——先決定要幾個收納箱(Table), 每個箱子貼上標籤(Column),箱子之間用線連起來(Relationship)。

// 設計電商網站的核心 Entity // Design core entities for e-commerce
// 第一步:識別核心實體 // Step 1: Identify core entities

public class Product // 商品實體
{
    public int Id { get; set; } // 主鍵
    public string Name { get; set; } = ""; // 商品名稱
    public string Description { get; set; } = ""; // 商品描述
    public decimal Price { get; set; } // 售價
    public int Stock { get; set; } // 庫存數量
    public int CategoryId { get; set; } // 外鍵:分類 ID
    public Category Category { get; set; } = null!; // 導覽屬性:分類
    public DateTime CreatedAt { get; set; } // 建立時間
    public bool IsActive { get; set; } = true; // 是否上架
}

public class Category // 分類實體
{
    public int Id { get; set; } // 主鍵
    public string Name { get; set; } = ""; // 分類名稱
    public string Slug { get; set; } = ""; // 網址用的代稱
    public List<Product> Products { get; set; } = new(); // 導覽屬性:此分類的商品
}

public class Order // 訂單實體
{
    public int Id { get; set; } // 主鍵
    public string UserId { get; set; } = ""; // 會員 ID
    public DateTime OrderDate { get; set; } // 訂單日期
    public decimal TotalAmount { get; set; } // 訂單總金額
    public string Status { get; set; } = "Pending"; // 訂單狀態
    public List<OrderItem> Items { get; set; } = new(); // 導覽屬性:訂單明細
}

public class OrderItem // 訂單明細實體
{
    public int Id { get; set; } // 主鍵
    public int OrderId { get; set; } // 外鍵:訂單 ID
    public int ProductId { get; set; } // 外鍵:商品 ID
    public int Quantity { get; set; } // 購買數量
    public decimal UnitPrice { get; set; } // 當時單價(記錄歷史價格)
    public Order Order { get; set; } = null!; // 導覽屬性:所屬訂單
    public Product Product { get; set; } = null!; // 導覽屬性:商品資訊
}

Entity Relationship 關係圖

┌─────────────┐     ┌──────────────┐     ┌──────────────┐
│  Category   │────<│   Product    │>────│  OrderItem   │
│             │ 1:N │              │ 1:N │              │
│ Id          │     │ Id           │     │ Id           │
│ Name        │     │ Name         │     │ OrderId (FK) │
│ Slug        │     │ Price        │     │ ProductId(FK)│
└─────────────┘     │ CategoryId   │     │ Quantity     │
                    │ Stock        │     │ UnitPrice    │
                    └──────────────┘     └──────┬───────┘
                                                │ N:1
                                         ┌──────┴───────┐
                                         │    Order     │
                                         │ Id           │
                                         │ UserId       │
                                         │ TotalAmount  │
                                         │ Status       │
                                         └──────────────┘

API 端點規劃 (RESTful)

// RESTful API 端點規劃表 // RESTful API endpoint planning
// 規則:用名詞不用動詞,用 HTTP Method 區分操作 // Use nouns, not verbs

public class ApiEndpoint // API 端點類別
{
    public string Method { get; set; } = ""; // HTTP 方法
    public string Path { get; set; } = ""; // 路徑
    public string Description { get; set; } = ""; // 說明
    public string Auth { get; set; } = ""; // 驗證需求
}

var endpoints = new List<ApiEndpoint> // 建立端點清單
{
    // 商品相關 API // Product endpoints
    new() { Method="GET", Path="/api/products", Description="取得商品清單(支援分頁、篩選)", Auth="無" }, // 公開取得商品
    new() { Method="GET", Path="/api/products/{id}", Description="取得單一商品詳情", Auth="無" }, // 公開取得商品詳情
    new() { Method="POST", Path="/api/products", Description="新增商品", Auth="Admin" }, // 管理員新增商品
    new() { Method="PUT", Path="/api/products/{id}", Description="更新商品資訊", Auth="Admin" }, // 管理員更新商品
    new() { Method="DELETE", Path="/api/products/{id}", Description="刪除商品", Auth="Admin" }, // 管理員刪除商品

    // 購物車相關 API // Cart endpoints
    new() { Method="GET", Path="/api/cart", Description="取得購物車內容", Auth="User" }, // 會員取得購物車
    new() { Method="POST", Path="/api/cart/items", Description="加入商品到購物車", Auth="User" }, // 會員加入商品
    new() { Method="PUT", Path="/api/cart/items/{id}", Description="更新購物車商品數量", Auth="User" }, // 會員修改數量
    new() { Method="DELETE", Path="/api/cart/items/{id}", Description="移除購物車商品", Auth="User" }, // 會員移除商品

    // 訂單相關 API // Order endpoints
    new() { Method="POST", Path="/api/orders", Description="建立訂單(從購物車結帳)", Auth="User" }, // 會員下單
    new() { Method="GET", Path="/api/orders", Description="取得我的訂單列表", Auth="User" }, // 會員查詢訂單
    new() { Method="GET", Path="/api/orders/{id}", Description="取得訂單詳情", Auth="User" }, // 會員查詢訂單詳情
};

// 印出 API 規劃表 // Print API plan
foreach (var ep in endpoints) // 逐一輸出端點
{
    Console.WriteLine($"{ep.Method,-8} {ep.Path,-30} {ep.Description}"); // 格式化輸出
}

線框圖 (Wireframe) 工具推薦

// 線框圖工具比較 // Wireframe tool comparison
var tools = new Dictionary<string, string> // 建立工具字典
{
    ["Figma"] = "免費版功能強大,支援團隊協作,業界標準", // Figma:最推薦
    ["Excalidraw"] = "免費開源,手繪風格,適合快速草圖", // Excalidraw:快速草圖
    ["draw.io"] = "免費,適合畫流程圖和架構圖", // draw.io:流程圖
    ["Balsamiq"] = "付費,低保真度線框圖專用", // Balsamiq:專業線框圖
    ["紙和筆"] = "最快!先在紙上畫,確認後再用工具" // 紙筆:最快速
};

foreach (var tool in tools) // 逐一輸出工具資訊
{
    Console.WriteLine($"🔧 {tool.Key}: {tool.Value}"); // 印出工具名稱和說明
}

時程估算技巧

💡 比喻:做菜估時間 你覺得炒盤菜 10 分鐘,但你忘了算洗菜、切菜、洗鍋子的時間。 程式估時也一樣——寫 code 只佔 30%,測試、除錯、調整佔 70%。

// 時程估算工具類別 // Time estimation utility class
public class TaskEstimator // 任務估算器
{
    public string TaskName { get; set; } = ""; // 任務名稱
    public double OptimisticDays { get; set; } // 樂觀估計(天)
    public double PessimisticDays { get; set; } // 悲觀估計(天)
    public double MostLikelyDays { get; set; } // 最可能估計(天)

    // PERT 估算法:(樂觀 + 4*最可能 + 悲觀) / 6 // PERT estimation formula
    public double PertEstimate => // 計算 PERT 估計值
        (OptimisticDays + 4 * MostLikelyDays + PessimisticDays) / 6; // 加權平均公式
}

// 使用 PERT 估算法 // Apply PERT estimation
var tasks = new List<TaskEstimator> // 建立任務清單
{
    new() { TaskName="會員系統", OptimisticDays=2, MostLikelyDays=3, PessimisticDays=7 }, // 估算會員系統
    new() { TaskName="商品 CRUD", OptimisticDays=3, MostLikelyDays=4, PessimisticDays=8 }, // 估算商品功能
    new() { TaskName="購物車", OptimisticDays=2, MostLikelyDays=3, PessimisticDays=6 }, // 估算購物車
    new() { TaskName="訂單流程", OptimisticDays=3, MostLikelyDays=5, PessimisticDays=10 }, // 估算訂單功能
    new() { TaskName="前端頁面", OptimisticDays=5, MostLikelyDays=7, PessimisticDays=14 }, // 估算前端開發
    new() { TaskName="測試與修正", OptimisticDays=3, MostLikelyDays=5, PessimisticDays=10 }, // 估算測試時間
};

double totalDays = 0; // 初始化總天數
foreach (var task in tasks) // 逐一計算每個任務
{
    var estimate = Math.Ceiling(task.PertEstimate); // 無條件進位取整數天
    totalDays += estimate; // 累加到總天數
    Console.WriteLine($"{task.TaskName}: 約 {estimate} 天"); // 印出估算結果
}

// 加上緩衝時間(建議加 20-30%) // Add buffer time (20-30% recommended)
var buffer = Math.Ceiling(totalDays * 0.25); // 加 25% 緩衝
Console.WriteLine($"預估總天數:{totalDays} 天 + 緩衝 {buffer} 天 = {totalDays + buffer} 天"); // 印出最終估計

黃金法則:初學者把你的估計乘以 2,中級乘以 1.5,資深乘以 1.2。


🤔 我這樣寫為什麼會錯?

❌ 錯誤 1:沒有寫驗收標準

// ❌ 錯誤:User Story 太模糊 // Mistake: vague User Story
var badStory = "使用者可以買東西"; // 這太模糊了,什麼叫買東西?

// ✅ 正確:要有明確的驗收標準 // Correct: include acceptance criteria
var goodStory = new UserStory // 建立清楚的使用者故事
{
    Role = "消費者", // 明確的角色
    Want = "用信用卡結帳購物車的商品", // 明確的功能
    SoThat = "快速完成購買流程", // 明確的目的
    AcceptanceCriteria = new List<string> // 列出可驗證的標準
    {
        "支援 Visa/MasterCard", // 驗收條件一
        "結帳失敗要顯示錯誤訊息", // 驗收條件二
        "成功後寄確認信" // 驗收條件三
    }
};

❌ 錯誤 2:所有功能都標 Must

// ❌ 錯誤:每個功能都是 Must // Mistake: everything is Must priority
var badPriority = new List<FeatureItem> // 全部都標 Must 等於沒排序
{
    new() { Name="AI 推薦", Priority=MoSCoWPriority.Must, EstimatedDays=10 }, // AI 推薦不是第一版必須
    new() { Name="多國語言", Priority=MoSCoWPriority.Must, EstimatedDays=5 }, // 多語言也不是第一版必須
    new() { Name="基本登入", Priority=MoSCoWPriority.Must, EstimatedDays=2 }, // 這才是真正的 Must
};
// 當所有功能都是 Must,就等於沒有優先排序 // If everything is Must, nothing is Must
// 問自己:「沒有這個功能,系統能不能上線?」 // Ask: can the system launch without this?

❌ 錯誤 3:忘記記錄歷史價格

// ❌ 錯誤:訂單明細只記商品 ID // Mistake: only storing product ID in order
public class BadOrderItem // 糟糕的訂單明細設計
{
    public int ProductId { get; set; } // 只存商品 ID
    public int Quantity { get; set; } // 只存數量
    // 問題:商品漲價後,舊訂單金額也跟著變! // Bug: old orders change when price updates!
}

// ✅ 正確:記錄當時的價格快照 // Correct: store price snapshot
public class GoodOrderItem // 正確的訂單明細設計
{
    public int ProductId { get; set; } // 商品 ID
    public int Quantity { get; set; } // 數量
    public decimal UnitPrice { get; set; } // 下單當時的單價(快照)
    public string ProductName { get; set; } = ""; // 下單當時的商品名稱(快照)
}

📋 本章重點

步驟 做什麼 產出物
1 寫下想法 專案企劃書
2 寫 User Story 使用者故事清單
3 MoSCoW 排序 功能優先排序表
4 設計 Schema ER 圖 + Migration
5 規劃 API API 端點文件
6 畫 Wireframe 線框圖
7 估算時程 甘特圖 / 時程表

🎯 下一步:拿著這份規劃書,我們開始實作電商網站!

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊