聊聊微服務是什麼 – 服務通訊
這個 Tag 的第六個主題是「服務通訊」,講白話些就是「我要怎麼呼叫另一個服務的功能?」我們在第三個主題講了「服務通訊的大致邏輯」,以及在第四個和第五個主題花了很大的篇幅講了「服務怎麼 連線 到服務」,但好像從來都沒有真正說「服務怎麼和服務 互動」、「RPC 是什麼」,以及具體要怎麼通訊、有哪些通訊方法,以及有哪些通訊手段。這裡就要開始介紹了! 這篇是之前 SITCON 2025 的草稿,不是後面寫的,也還沒有做過 peer reviewing!如果有任何問題的話,也歡迎到 Threads 或 X 上標我指正。 「通訊」是什麼? 在單體服務的世界,你要呼叫一個方法,比如「選課」,你通常是用函式或 HTTP API 呼叫完成的。舉例來說: 你的前端往你的 API 發出了 POST /api/v1/course/:course/selection。我們會稱這個網址叫做端點 (endpoint)。 你的 API 有一個「選課」Controller,裡面有一個處理選課端點的「方法」(method),這裡叫做 SelectCourse 吧! 接著你的 SelectCourse 方法會透過呼叫 GetStudentInfo 方法來取得這個學生的資訊,以及透過 GetCourseContraints 方法取得課程的限修資訊 接著 SelectCourse 方法會根據這些資訊決定允不允許學生選這堂課,然後將選課結果插入資料庫當中。 📚 小提醒:在 MVCS 架構下,我們通常會叫這種功能性質的 class 為 Service。不過為了防止跟微服務的 Service 混淆(雖然其實概念是一樣的),這裡就不會用 Service 這個名詞。 如果你能理解上面這張圖,那我們把它換成微服務,你就很清楚我們要解決什麼「通訊」問題了: 上面這張圖的青色線段,就是我們這次要探討的問題了:這些服務都不在一起,我們要怎麼呼叫對方的方法——也就是「青色」這個線條,究竟怎麼實作? 🫨 選課服務是怎麼連線到使用者服務的?你可以往回看看「服務探索」這個章節!從這裡開始,我們都假定我們已經知道這些服務的 IP 和連線方式了,要處理的只是應用層的溝通問題。 用 HTTP 設計自己的 RPC 首先,最直覺的方法,就是你給每個服務開一個 HTTP 的 API,用 HTTP 的呼叫邏輯和其他服務溝通。因為這些 HTTP 方法只是內部使用的,你不用像 REST API 一樣,需要認真思考每個端點的命名,只需要讓每個服務看得懂就好。因此,你這樣設計你的微服務溝通方法: ...
聊聊微服務是什麼 – 擴縮與負載平衡
這個 Tag 的第五個主題是水平擴縮跟負載平衡。還記得我們昨天提到的「服務探索」嗎?到目前來講,我們只「探索」了一個服務,但是微服務的其中一個目標,就是在不擴展機器的情況下,盡可能把請求負載分擔到各個服務上。我們要怎麼做到這個「分擔」呢? 這篇是之前 SITCON 2025 的草稿,不是後面寫的,也還沒有做過 peer reviewing!如果有任何問題的話,也歡迎到 Threads 或 X 上標我指正。 什麼是擴縮和負載平衡? 答案意外得簡單:我們不就多開幾個服務,然後按一套規則平均把請求分擔到這些服務就好了嗎?恭喜你發明了水平擴縮 (horizontal scaling) 跟負載平衡 (load balancing) 了!這兩件事情的邏輯很簡單:「我們要在不動單一個節點的情況下,盡量把服務『擴縮』到各個地方,並且平均地『分配』請求到這些服務上?」 只是在實務上會更複雜,舉例來說,你會有 N 個 Gateway,連線到 M 個選課服務,這 M 個選課服務還會分別連線到 X 個課程服務,以及 Y 個使用者服務。我們接下來要解決的議題,就是如何在更複雜的場景,可以將連線分配到服務上、如何在單一服務下線時讓其他服務繼續工作,以及 HTTP 的世界,負載平衡通常該怎麼做。 要怎麼擴縮服務? 首先,我們先從比較簡單的問題開始:「怎麼擴縮?」它本質上就是多開幾個服務,你在好幾個終端機視窗,重複啟動你的服務,其實就是一種「擴展」(scaling up);你把過剩的服務用 Ctrl-C 殺掉,其實就是一種「縮減」(scaling down)。不過你假如真的這樣做,會發現到「重複用相同的參數啟動服務會遇到 port 衝突的問題」(比如說不能有兩個服務開在 3000 port 上),所以你就需要將另一個服務開在不同的 port 上(比如說,3001 port),這樣一來,你就起了有兩個 replicas 的服務了! 📚 「Replicas」是什麼?其實就是「重複的實例」,比如說上圖中的 course-service(課程服務),我們可以稱他有 6 個 Replicas。 要怎麼分配請求(負載平衡)? 下一個問題,就是「怎麼分配請求?」這個問題跟「服務探索」一樣,可以從用戶端和伺服器端下手。就以上面的圖來說: 用戶端解法:Gateway 在知道 6 個課程服務的位址之後,用分配演算法(隨機挑選、循環調度 (round robin),或者是比較複雜的根據負載分配)來決定要連線到哪台機器。 伺服器端解法:我們可以在前面掛一個代理伺服器(用 NGINX、Caddy),由代理伺服器透過分配演算法來決定要代理到哪台機器,而 Gateway 直接連線到這個代理伺服器就好。 其中,「伺服器端解法」中那個「代理伺服器」的別稱就是「負載分配器」(Load Balancer)。你應該在 AWS、GCP、Cloudflare 等 IaaS 上看過這個名詞,實際上他的原理就是透過一套演算法,將請求分配、代理到指定的服務。 ...
聊聊微服務是什麼 – 服務探索
今年我 SITCON 有投一篇微服務的議程:「選課卡成狗?微服務架構帶你翻轉校園系統」。在 SITCON 之前,我打算每天在 Blog 上寫一篇和 Cloud Native 相關的短文,來當作議程的前導內容。當然針對每一篇短文的意見回饋(看不懂也是一種意見反饋 🥺),最終都有助於我產出更好的議程內容~ 這個 Tag 的第四個主題是「服務探索」。從這個主題開始,我們要開始探討前三章說的微服務架構會有什麼問題,以及可以怎麼克服了。 考慮到 Blog 本身不是一個很好的互動平台,我在每篇文章的底下都會留「💬 互動區塊」,連結到和這篇文章相關的社交媒體上。你可以在社交媒體上和這篇文章互動~ 同台機器上,服務如何互相連線? 前文的結尾我有留一個問題:「如何讓服務之間可以互相連線?」你或許會覺得這問題非常基本,因此我們不妨拿之前的微服務架構模擬看看。假如你在本機端而且不想配置網路的話,最直接的做法可能是每個服務都開不同的 port,讓 Gateway 直接用 port 連線。比如說你把使用者服務安排在 port 3001、把選課服務安排在 port 3002,然後 Gateway 用 localhost:3001 連線使用者服務、用 localhost:3002 連線選課服務;selection-service 也是用 localhost:3001 連線使用者服務、用 localhost:3002 連線選課服務。 事實上假如你只在一台機器上運作的話,這種方法真的沒有什麼問題,甚至可以說是行之有年了。 多台機器上,服務如何互相連線? 不過假如我們進入到分散式的世界:把這堆服務打散到各個機器上,這樣的做法會碰到什麼問題呢?我們在第一章有分析出選課相關的功能相對耗資源,所以我們把「選課系統」獨立到不同的機器(這裡叫他機器 2)上。首先不同機器肯定會有不同的 IP,所以「機器 1」要連線到「選課服務」,肯定就不能用 localhost 連線了,我們肯定是要用「機器 2」的 IP 搭配上之前設定的 port 進行連線,也就是下面這張圖。 問題來了:IP 是永恆不變的嗎?機器的 IP 可能會因為區域變動(比如從新北機房移到高雄機房)而變化,我們也不一定能保證「選課服務」一定只在機器 2 上面。甚至說假如其他服務也開始有壓力,我們想要把它分出機器 1,我們也同樣需要關心到 IP 地址的議題。既然 IP 不是永恆不變的,我們就要關心起「如果 IP 改動時,會發生什麼樣的事情。」試想一下,我們把「選課服務」的 IP 換掉,我們需要改掉多少個服務連線位址呢? ...
聊聊微服務是什麼 – 閘道和服務通訊基礎
今年我 SITCON 有投一篇微服務的議程:「選課卡成狗?微服務架構帶你翻轉校園系統」。在 SITCON 之前,我打算每天在 Blog 上寫一篇和 Cloud Native 相關的短文,來當作議程的前導內容。當然針對每一篇短文的意見回饋(看不懂也是一種意見反饋 🥺),最終都有助於我產出更好的議程內容~ 這個 Tag 的第三個主題,就來補充我們昨天微服務中一直沒有提到的部分:「Gateway」吧!我們昨天聊了服務的拆法(領域拆分),以及 RPC 分查詢和更動的目的(CQRS),但是你會發現到有個服務長得和其他服務不太一樣:Gateway。Gateway 沒有 RPC 方法,而且是唯一一個連接到前端的服務。為什麼需要 Gateway,以及 Gateway 是怎麼和其他服務通訊的呢?這篇文章就來詳細解釋這個問題。最後,我們也會簡單說明微服務之間的通訊流程。 考慮到 Blog 本身不是一個很好的互動平台,我在每篇文章的底下都會留「💬 互動區塊」,連結到和這篇文章相關的社交媒體上。你可以在社交媒體上和這篇文章互動~ 什麼是 Gateway? 「Gateway」(閘道), 基本上就是你那些微服務的前台,負責給前端一組好用、封裝自 RPC 的 REST 或 GraphQL API,同時在轉送給微服務前進行正確的權限檢查(比如說「加入課程」只有管理員能執行)。這樣一來,前端就不需要知道所有微服務的位置、了解服務切分的細節,只需要和 Gateway 進行互動就好。 拆出 Gateway 的意義 你或許會疑惑「為什麼我們不要一步到位,讓前端直接連線這些微服務呢?」首先我們先看看讓前端連線微服務會發生什麼事情: 現在前端會直接連線到這些微服務上。假如沒有 Gateway,如你所見,「認證」和「授權」的重責大任就落在每個微服務身上了。身分認證的目的是判斷請求者持有的 token 是否有效,確定是對應使用者登入的;授權的目的是檢查對應使用者是否可以取用這個方法,防止使用者進行越權的操作。 因為每個微服務都需要做一次認證和授權,單個微服務會需要處理自身領域外的事情,增加複雜度1:首先,每個微服務都需要有自己一套進行認證和授權的程式碼,除了拖慢呼叫一個 RPC 方法的速度(現代微服務一個 Endpoint 可能會需要呼叫好幾十個 RPC 方法),微服務本身也會因為這些驗證而變得臃腫。接著,認證和授權都需要依賴「使用者服務」,如果「使用者服務」故障了,幾乎所有微服務都會停擺。最後,服務之間的通訊該怎麼認證呢?如果你的認證方式是 OAuth 的話,你很需要給所有服務組合產生一組 M2M token⋯⋯ 除了後端一團糟外,前端也會一團亂。你的前端需要先知道「我需要的方法在哪個服務上」,然後還需要知道這個服務的連線網址。你的 API 呼叫時需要指向各種不同的網址,當你要撤換服務時,需要一一檢查前端有沒有地方引用到這個服務,增加你撤換和更新這些服務時的困難度。同時你的這些服務因為都跟使用者的前端(也就是用戶端)扯上關係了,所以設計上又需要考慮用戶端會怎麼搞壞你的服務,並且需要花上更多時間把你的 RPC 方法封裝得更適合讓任意用戶端呼叫(比如因此捨棄簡單的 gRPC,轉為使用 REST API,去提升各個用戶端的相容性)。 ...
聊聊微服務是什麼 – 入門微服務
今年我 SITCON 有投一篇微服務的議程:「選課卡成狗?微服務架構帶你翻轉校園系統」。在 SITCON 之前,我打算每天在 Blog 上寫一篇和 Cloud Native 相關的短文,來當作議程的前導內容。當然針對每一篇短文的意見回饋(看不懂也是一種意見反饋 🥺),最終都有助於我產出更好的議程內容~ 這個系列的第二個主題,還是延續我們上次的選課系統設計。昨天我們發現到單體的方式開始造成資源的浪費以及資料庫的瓶頸,所以我們或許可以看看怎麼把選課系統拆成雲端原生的微服務架構。 考慮到 Blog 本身不是一個很好的互動平台,我在每篇文章的底下都會留「💬 互動區塊」,連結到和這篇文章相關的社交媒體上。你可以在社交媒體上和這篇文章互動~ 怎麼將單體服務拆分成微服務? 或許你會疑惑「微服務」是什麼。首先就「服務」這個詞來說,後端是個服務,前端也是個服務,基本上任何能提供 API 進行呼叫的都是服務。「微服務」本質上就是把我們的後端拆得更細緻:比如說我們可以把使用者相關的東西變成一個服務、把課程相關的東西變成一個服務、把志願序變成一個服務等等。 我們通常會把每個服務管轄的部分稱之為「領域」,只有這個區域內的服務可以直接操縱資料庫的資料,而不在這個區域的只能透過 RPC(遠端程序呼叫,比面向用戶端的 REST API 相對隨便,主要供內部使用的 API)撈資料。你可能會想「領域是不是就是資料表的名稱?」,但實際上其實不止於此,粒度通常會大得多,通常會追求「服務(的領域)可以獨立運作」。我們把以「領域」進行思考的一套模式叫做 DDD(領域驅動開發),實際展開的篇幅會相當長,這裡就不對拆服務和 DDD 多做說明(實際上你也不一定要學會 DDD 才能用微服務,靠經驗拆也是可以的!) 就以上面的例子來說,我自己認為使用者服務(user-service)、課程資訊服務(course-service)和選課服務(selection-service)是三個領域上可以獨立運作的服務——換言之,假如使用者服務掛掉,我預期我還能看課程資訊以及改動志願序;假如選課服務掛掉,我一樣可以更新我的選修學分。不過你應該也有發現到「選課服務」相對複雜一點,因為插入志願和最終志願序需要做很多判斷邏輯,需要連線到使用者服務看權重,以及連線到課程服務查詢限修規則,這時我們可能需要處理選課服務在其他兩個服務掛掉時的處理邏輯。但撇除掉這兩個 RPC 方法,服務大體上還是可以獨立運作的。 【🤔 想想看!】你覺得上面的微服務架構,是不是一個好的拆法? 微服務的水平擴縮 (scaling) 接著回答昨天的問題:我們這樣開發出的服務,可以怎麼降低資料庫的壓力,以及怎麼針對性的對服務進行擴充來分散壓力?首先,從上圖其實就能很明顯看到「我們把每個領域對應的資料庫都拆出去了,」換句話說,每個資料庫只需要負責自己領域內的事情(使用者資訊、課程資訊、選課資訊),壓力自然就比單體的「包山包海」小上很多。接著,其實每個微服務都應該可以水平擴縮 (scaling),所以你可以規劃「志願序服務的壓力比較大,所以我們可以開多一點服務來平衡」;「使用者服務幾乎不怎麼需要讀取,所以我們可以就開少少的機器就好」: 接下來我們也會講到很多微服務上的設計技巧,來發揮微服務更大的作用——比如快取。 【🤔 想想看!】我們要怎麼把請求分散到上面說的這三個微服務呢?是不是所有微服務都必須共用一套狀態(資料庫)?共用的缺點是什麼,以及快取區需要共用嗎? 查詢與更動分離 (CQRS) 你接著還會疑惑「查詢動作跟更動動作」差在哪裡。舉個例子,為什麼我們沒有選擇加一個「插入志願之後列出學生志願序」的查詢 + 更動 RPC,而是選擇分開變成「插入志願 RPC」+「志願序 RPC」呢?其實這種叫 CQRS,把「查詢」跟「更動(命令)」分開的一種設計模式。 為什麼我們要分開查詢(讀取)跟更動(寫入)呢?通常讀取動作不用擔心狀態問題,也就是說「就算我今天讀取 1000 次同一筆資料,只要沒有改動,得到的結果應該都要是一樣的」;寫入操作的狀態問題就複雜得多,執行順序、重複插入就足以造成大影響。所以: 讀取動作我們可以快取、可以在唯讀的資料庫 replica 實例讀取(對,很多資料庫系統是可以建立出很多個跟隨主要資料庫的唯讀 replica 實例的,通常我們叫這種功能為複寫 – replication) 寫入操作只能在主要資料庫進行操作,並且通常是不能快取的,相對來講效能改進的彈性會小一些。 在我們知道讀取和寫入兩個的複雜度不同後,CQRS 的設計就變得合理多了。就以「課程資料庫」來說,我們可以這樣規劃查詢和寫入: ...
聊聊微服務是什麼 – 從單體服務進行擴縮
今年我 SITCON 有投一篇微服務的議程:「選課卡成狗?微服務架構帶你翻轉校園系統」。在 SITCON 之前,我打算每天在 Blog 上寫一篇和 Cloud Native 相關的短文,來當作議程的前導內容。當然針對每一篇短文的意見回饋(看不懂也是一種意見反饋 🥺),最終都有助於我產出更好的議程內容~ 這個系列的第一個主題,就先從微服務這個主軸開始吧!但在這之前我們或許可以先聊聊「單體架構可能會遇到什麼樣的瓶頸」,以及我們要怎麼使用一些技術來稍微改善你的單體系統。 考慮到 Blog 本身不是一個很好的互動平台,我在每篇文章的底下都會留「💬 互動區塊」,連結到和這篇文章相關的社交媒體上。你可以在社交媒體上和這篇文章互動~ 單體服務的瓶頸 假設你今天要開發一套用比序來選課的系統,你或許會像下圖這樣來設計你的系統。其中後端就是一個很大的應用程式,前端去呼叫後端來選課。 乍看之下是個挺合理的設計吧?但我們設想一種情況:假如現在已經到了選課的尾聲,大家都會想要看看「自己選的課是否可以上得了」,所以「選課人數」Endpoint 的請求量也會隨時增加,然後系統的 CPU 資源就被「選課人數 Endpoint」吃光了。因為登入、選課、課程名單、志願序等等的 Endpoint 也在同個系統上,所以你的選課系統除了前端的部分會全部掛掉,學生們準備在 Dcard 上罵爆你的系統了。 擴縮單體服務 此時你會想到:那我們多開好幾套單體的後端 (replicas),然後前端隨機選擇 API(也就是所謂的「負載平衡」)呢?其實確實是個可行的方案,不過你首先要讓你的後端變成無狀態的 (Stateless) 的。「無狀態」是什麼概念呢?就以下圖來說,我們無論選到哪個 instance 的 Endpoint,呼叫結果都應該要是一致的。換言之,你的後端不可以儲存只有這個 instance 知道的東西,也就是所謂的「狀態」。當然取決於你的設計,你可能多少會不小心存一些狀態在後端裡面(比如登入的 session 以及 lock 檔案⋯⋯),所以你可能會需要花點時間重構這些邏輯,讓這堆狀態不要跟後端放在一起(或甚至變成不用儲存狀態也能判斷的東西,比如 JWT)。 【🤔 想想看!】哪些東西可能會導致一個服務變成有狀態的(Stateful)? 單體服務的擴縮問題 在完成相關的重構後,就算其中一個 instance 有著很大的負載,其他 instance 也能有效的分散掉請求,讓系統不至於完全停擺。不過這種方法粒度或許還是太大了——我們只有 1 個 endpoint 遇到瓶頸,但卻需要因此開出 5 個(甚至更多)完整的後端 instances,資源用量上會不會變得太多;而且所有 instances 最終還是連到一台資料庫上,遇到大量讀取、寫入的場景可能還是會 lag。如果我們用微服務、分散式系統的邏輯重新規劃後端,我們有沒有機會解決掉這個問題? ...
把 Python 的 venv 移到其他機器
前言 要怎麼在不重新下載東西的情況下,把一整包 code 包含依賴本身,移到新的地方呢? 舉個之前遇到的例子:我想在學校部署一個用 Python Streamlit 框架寫的程式碼評測工具,但是在測試部署時發現一個非常頭痛的問題:學校的連外網路特別慢,導致 pip 幾乎無法正常完成安裝。在嘗試了 pip download 以及一些打包方案後,發現 Streamlit 的執行最終都會缺幾個元件導致啟動失敗,最終都還是需要用 pip install 補全依賴。最後我想到一個 workaround:拿其他同學的 Windows 筆電先把程式準備好,再把準備好的程式複製到新的地方。 不過要怎麼「準備好程式」然後「複製到新的地方」呢? Python 不像 Go 和 Rust 可以編譯成靜態的執行檔,也不像 Node.js 和 PHP 有著各個專案獨立的 node_modules 或 vendor 資料夾,可以搬到其他地方而保持程式的依賴正常運作。不過 Python 有個很類似 node_modules 的東西——Virtualenv,搞不好我們真的能像 node_modules 一樣直接把整組專案複製到其他電腦上,專案就能跑了。 但是 Stack Overflow 的文章又提到「venv 通常不能直接複製到其他電腦上」。 In general you can’t copy virtual environments anywhere, Docker or otherwise. They tend to be tied to a very specific filesystem path and a pretty specific Python installation. If you knew you had the exact same Python binary, and you copied it to the exact same filesystem path, you could probably COPY it in as-is, but the build system would be extremely fragile. 1 ...
搭建一個有圖床和統計功能的 Blog
tl;dr 使用 Zeabur 部署 Blog 使用 Cloudflare R2 當圖床,Cloudreve 管理 使用 Umami 進行網站資料統計 選擇性部署 CodiMD / Hedgedoc 方便行動裝置編輯 常見的方案有什麼問題 純粹的 GitHub Pages 架設靜態 Blog,搭配 Google Analytics(或 Cloudflare Web Analytics)雖然是最便宜的選擇,但對於媒體管理上和草稿編輯還是不太方便。 統計工具方面,除了 Google Analytics 之外,幾乎沒有什麼功能特別強大,可以看單一使用者流向的統計工具。 圖床方面,媒體放在 GitHub repository 上會造成 repo 迅速膨脹,但又擔心其他免費圖床如 Imgur 會倒閉。而且 Imgur 不能上傳圖片以外的資源!🥺 草稿編輯方面,GitHub 沒有提供一個比較好的 Markdown 書寫工具,要獲得好的書寫體驗,就需要在電腦上用 VS Code 等等的 Markdown editor 書寫,局限了在手機上完成草稿或者編輯文章的能力。 怎麼解決? 作為一個 self-hosted 跟偏好 Cloud Native 方案的使用者,我會這麼規劃我的 blog: 這次我使用的 Blog SSG 是 Hugo,速度確實快,而且 template 比 Hexo 簡潔和清晰一點。 ...
重新整理 Pan.blog……
把 pan.blog 重新翻新了一下,主要是: 換成 Hugo,提升編譯速度 圖床放到 CDN 上,不跟 GitHub 放在一起了 其實 pan.blog 我前一陣子就想重新整理了,只是一直沒有動力來做。 不過 ChatGPT 開始支援 Web Search,讓我覺得「把文章寫在 Google 可以索引的地方,之後也能幫到自己」, 再加上 X 的走向讓人不太樂觀,所以我打算把一些有價值的東西用 Blog 的方式留存。 這個新 Blog 有把一些我覺得值得留存的東西從老的 Hexo 站移過來,之後也會寫一些技術短篇~
特殊選才踩雷心得
打擾了各位,想問一下如果想要透過特殊選材的話,有大量的競賽經驗/表現,還是有實作成品,哪個會比較好? 我當年特選是以實作為重的。我踩過坑了,所以我能告訴你 不要想著你的實作可以獲得教授青睞。 通常在高中年紀做的作品——比如自己寫的內核、寫的網站服務、寫的系統,都是垃圾。教授早已閱歷無數,你引以為傲的作品,可能對他們來說就是 print("Hello, World") 而已。除非你的作品真的很知名——就比如說你造出了一個每個月使用人次高達 10 萬的東西,要不然說實話,你只是證明「你對這個領域有很淺薄的研究」——但一點都不特殊。當然,假如你能把你的作品做出相當大的特色(你造出了一個 O(1) 的旅行者問題演算法),甚至你還因此發上期刊,這就另當別論。 所以既然大家都是菜雞,那教授要怎麼選出「特殊」的?當然是量化下來的能力。不要看不起 APCS 還有一堆競賽:這個是你唯一可以拿來說嘴的了。你可以在這些競賽中大談你是如何把基礎能力用到極致,用到把其他競賽者打爆的——其實這樣也有一點「專案」的效果了,都是基礎能力應用,但至少教授可以知道「你的基礎能力確實超越同儕。」 總結來說,不要以為你的專案用了些什麼「設計模式」、「物件導向」,就可以變成教授人人都想搶的人才——說實話,你的專案除非有名到教授想要知道,否則教授只會覺得你只是寫了一堆比較進階的 Hello, World。乖乖競賽,把你的能力用來打爆其他人,這才是特選成功的法則。 當然你也可以繼續拿你的專案當作是特選的題材,但就警告你不要害到自己一所學校都沒上然後學測還爆掉。我有個開發了一堆專案、甚至還算知名,而且還經常參與各種社群活動的朋友——他的 4 間特選全部爆炸,學測失利,最後分科上了間沒有契合他興趣的科系。我自己幸好還有些比賽,所以勉強上了間普普通通的大學,但也是挺後悔自己當初叛逆沒去考 APCS。 原文寫在《中學資訊討論群 CISC》:https://discord.com/channels/755456963265036309/1078522742057480232/1096319706664804394。