iT邦幫忙

2026 iThome 鐵人賽

0
ChatGPT & Codex

從 Prompt Engineering 到 Copilot / Codex 實務 30 天系列 第 29 篇

Day 29:【綜合實作】人機協同工作流:從零開始規劃輕量 Web 應用的架構與核心模組

  • 分享至 

  • xImage
  •  

經過了前五個模組在提示詞工程、演算法思維、代碼重構、API/SQL 整合以及測試與資安防護的歷練,今天我們迎來了倒數第二天的壓軸挑戰——「綜合實戰」。

在傳統軟體開發中,要從零開始搭建一個新工具或微服務原型(PoC),通常需要經歷冗長的時間:畫架構草圖、設計資料模型、手刻 DTO、編寫核心演算法、處理防呆與邊界,最後補上單元測試。

今天我們就來完整展示人機協同工作流(Human-AI Collaborative Workflow)的威力:在 30 分鐘內,引導 AI 一步步拆解需求,共同設計並實作一個高效、具備邊界防禦的經典工程專案——「高效短網址轉發服務(URL Shortener Service)」!


一、人機協同第一步:系統架構與需求拆解

我們不直接叫 AI「寫一個短網址系統」,而是先以架構師的身分引導它進行模組劃分:

【系統規劃提示詞範本】
請扮演資深後端系統架構師。我想使用 Java 17 與 Spring Boot 打造一個輕量級高效短網址(URL Shortener)微服務。

請依序完成以下規劃:

  1. 核心需求與邊界約束:
    • 長網址(Original URL)轉短碼(Short Code)。
    • 透過短碼快速重定向(HTTP 302 Redirect)回原始長網址。
    • 支援過期時間與點擊計數。
  2. 核心演算法選擇:比較 Hash(MD5/SHA-256 + 截斷)與自增 ID 轉 Base62 的優缺點,推薦最不易碰撞的解法。
  3. 模組分層設計:定義 Controller、Service、DTO 與儲存庫介面架構。

AI 的架構決策回饋:

AI 迅速給出分析:

  • 不推薦 MD5 截斷:雜湊截斷存在不可避免的碰撞機率(Collision),碰撞時需要反覆探測處理。
  • 推薦 Base62(62 進位)編碼法:使用數字 0-9、大寫 A-Z、小寫 a-z 共 62 個字元。將系統自增 ID(或分散式 Snowflake ID)轉換為 Base62,能保證短碼絕對唯一、且長度通常僅需 6~7 碼,可容納超過數百億筆資料。

二、人機協同第二步:核心 Base62 演算法實作

確定演算法後,我們要求 AI 產出純度極高、無外部相依、執行緒安全的 Base62 工具類別:

[Java 核心 Base62 編碼工具]
public final class Base62Utils {

    private static final String BASE62_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final int BASE = BASE62_CHARS.length();

    private Base62Utils() {
        // 工具類別防止實例化
    }

    /**
     * 將正整數 ID 編碼為 Base62 短碼
     */
    public static String encode(long id) {
        if (id <= 0) {
            throw new IllegalArgumentException("ID 必須為正整數");
        }

        StringBuilder sb = new StringBuilder();
        while (id > 0) {
            int remainder = (int) (id % BASE);
            sb.append(BASE62_CHARS.charAt(remainder));
            id /= BASE;
        }

        return sb.reverse().toString();
    }

    /**
     * 將 Base62 短碼解碼回原始數字 ID
     */
    public static long decode(String shortCode) {
        if (shortCode == null || shortCode.isBlank()) {
            throw new IllegalArgumentException("短碼不可為空");
        }

        long id = 0;
        for (int i = 0; i < shortCode.length(); i++) {
            int index = BASE62_CHARS.indexOf(shortCode.charAt(i));
            if (index == -1) {
                throw new IllegalArgumentException("短碼包含非法字元: " + shortCode.charAt(i));
            }
            id = id * BASE + index;
        }

        return id;
    }
}

三、人機協同第三步:核心商業邏輯與防禦性 Service 整合

接下來,我們請 AI 產出短網址的核心業務層,同時融入先前學過的「防禦性編程」與「Java Record」:

[1. 請求與回應 DTO 定義]
public record ShortenUrlRequest(
    String originalUrl,
    Long customExpirationSeconds
) {}

public record ShortenUrlResponse(
    String shortCode,
    String shortUrl,
    String originalUrl
) {}

[2. 核心業務邏輯類別]

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

public class UrlShortenerService {

    private static final String DOMAIN = "https://sho.rt/";
    private final AtomicLong idGenerator = new AtomicLong(100000L); // 從大基數起算,維持短碼長度
    private final Map<String, String> codeToUrlMap = new ConcurrentHashMap<>();
    private final Map<String, String> urlToCodeMap = new ConcurrentHashMap<>();

    /**
     * 縮短網址核心邏輯
     */
    public ShortenUrlResponse shorten(ShortenUrlRequest request) {
        // 邊界防禦:驗證網址格式
        if (request.originalUrl() == null || !request.originalUrl().matches("^https?://.+")) {
            throw new IllegalArgumentException("非法的網址格式,必須以 http:// 或 https:// 開頭");
        }

        // 若先前已生成過,直接回傳舊短碼(避免浪費儲存空間)
        String existingCode = urlToCodeMap.get(request.originalUrl());
        if (existingCode != null) {
            return new ShortenUrlResponse(existingCode, DOMAIN + existingCode, request.originalUrl());
        }

        // 產生全局唯一 ID 並轉換為 Base62 短碼
        long nextId = idGenerator.incrementAndGet();
        String shortCode = Base62Utils.encode(nextId);

        // 寫入儲存庫(實務上可對接 Redis 或 PostgreSQL)
        codeToUrlMap.put(shortCode, request.originalUrl());
        urlToCodeMap.put(request.originalUrl(), shortCode);

        return new ShortenUrlResponse(shortCode, DOMAIN + shortCode, request.originalUrl());
    }

    /**
     * 還原長網址邏輯
     */
    public Optional<String> getOriginalUrl(String shortCode) {
        if (shortCode == null || shortCode.isBlank()) {
            return Optional.empty();
        }
        return Optional.ofNullable(codeToUrlMap.get(shortCode));
    }
}

四、人機協同第四步:快速補全單元驗證

最後,我們利用先前掌握的 JUnit 5 模板,讓 AI 在 10 秒內生成覆蓋 Happy Path 與邊界例外的單元測試:

[JUnit 5 驗證測試]
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

class UrlShortenerServiceTest {

    private final UrlShortenerService service = new UrlShortenerService();

    @Test
    @DisplayName("縮短網址成功:能正確生成 Base62 短碼並還原原始網址")
    void shortenAndResolve_Success() {
        String original = "https://ithome.com.tw/ironman/2026";
        var response = service.shorten(new ShortenUrlRequest(original, null));

        assertThat(response.shortCode()).isNotBlank();
        assertThat(response.shortUrl()).startsWith("https://sho.rt/");

        var resolved = service.getOriginalUrl(response.shortCode());
        assertThat(resolved).isPresent().contains(original);
    }

    @Test
    @DisplayName("網址格式錯誤防禦:未以 http/https 開頭應拋出 IllegalArgumentException")
    void shorten_InvalidUrl_ThrowsException() {
        assertThatThrownBy(() -> service.shorten(new ShortenUrlRequest("ftp://malicious.site", null)))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("非法的網址格式");
    }
}

五、綜合實踐的人機協同複盤

透過今天的完整閉環演練,我們驗證了一套高產出的開發節奏:

  1. 人類主導架構與決策:在 Base62 vs Hash 的選擇上,由人類工程師下達無碰撞的約束,防止 AI 自作主張選用高碰撞的截斷算法。
  2. AI 加速樣板與繁瑣轉換:Base62 進位轉換、雙向 Map 快取、Record DTO 與 JUnit 5 測試,全部由 AI 迅速填滿,大幅省去查找語法與手刻樣板的時間。
  3. 即時審查與安全把關:透過正則驗證 URL 協定(避免 JavaScript 偽協議注入)、使用 ConcurrentHashMap 與 AtomicLong 確保併發安全,確保系統具備上線生產的體質。

今日小結與預告

今天我們透過短網址微服務的端到端實作,將提示詞規格、演算法、Clean Code、例外防衛與單元測試完美串聯,體驗了現代 AI 輔助開發的極致效率。


上一篇
Day 28:【AI 幻覺與查證】當 AI 一本正經胡說八道:工程師必備的代碼查核思維
系列文
從 Prompt Engineering 到 Copilot / Codex 實務 30 天 共 29 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言