微服務絞殺遺留模組 —— 均一後端軟體工程師 Amy 技術分享

[前言]均一的程式碼基礎 junyiacademy 從 2013 年 fork Khan Academy 原始碼,一直發展到現在,程式碼的複雜度不可同日而語,開發和維護的難度越來越高,很根本而且不好償還的技術債逐漸浮上檯面,有些甚至成為新功能開發的巨大阻力。

於是,我們在去年三月決定從簡化程式碼下手,具體作為是從原本的單體式應用拆出一個負責內容管理的微服務,並將內容管理的邏輯逐步遷移到此服務,直到完全絞殺原始的內容管理模組。

Why we do this: 技術債

均一後端由 Python 撰寫而成,Python 有簡單清晰,語法優雅的優點,但因為極大的自由,例如動態型別與缺乏存取修飾(沒有 private),還有一些腳本語言的特性,例如容許 cycling import,專案長大容易變成一頭無法駕馭的巨獸。

筆者以為,尤其在大型專案,搭配因地制宜的編程規範才能將 Python 的優良部份發揮到最大。

模組化的大敵

先破個梗,從母專案 junyiacademy 拆出的微服務 JunyiContentService_py3 目前的 dependency graph 是這樣的:

Python3 Content Service dependency graph
Python3 Content Service dependency graph

如同普通基於 Flask 的 Web server,右下角的 main 是所有 API 路由的入口,也就是 dependency 最末端的節點。

從右下角開始每個節點順順往上指,越往上面就是越底層的邏輯;除此之外,可以看到圖中間群聚一些節點,是相關性很高的模組(Python module)。這張圖第一眼看到就可以觀察到明顯的秩序,是一個正常的 dependency graph。

而母專案 junyiacademy 是怎樣的呢?

2018 年時志工阿東大大曾幫忙畫過一張 dependency graph,當時是長這樣的:

2018 junyiacademy 全專案的 dependency graph

中間有兩個點,一樣是 API route 的入口,從中心往外可以看到內外兩圈節點,但節點之間代表相依性的線錯綜複雜,最多就是觀察到程式有大量的 cycling import。

嗯,沒錯。模組邊界已經從程式碼中消失,且模組之間勉強要定義位階(上層或底層)也很困難。

程式碼同源的 Khan Academy 後來的發展也遭遇類似困境,是 Khan Academy 2018 年發表 Untangling our Python Code 當中的 dependency graph,投入了數個人月重構,仍只有小幅度改善。

2018 Khan Academy 的 dependency graph
2018 Khan Academy 的 dependency graph

高內聚低耦合,最遙遠的距離

程式美學告訴我們,維持軟體的高度內聚和低度耦合乃是一切易讀性和可擴展性的根基;但「編寫乾淨且模組化的程式碼」卻在程式碼基礎逐漸增長的過程淪為道德勸說和精神指標。

於是工程師靈肉分離的重新打造輪子、在模組邊界搞曖昧(搭配 FIXME 和終將沉到甕底的技術債 issue),於是你看到前面佈滿線條,不知所以的兩個圈圈,於是用戶越來越多,我們敢承諾的功能卻越來越小,最後,我們起了殺意⋯⋯

How we do this 1: 絞殺者模式

開玩笑的,怎麼可能因為一點糾結的 dependency 就要殺掉多年的智慧結晶?身為台灣 K-12 線上教育的扛霸子,均一工程團隊做決策是講究科學根據、理性討論、實證導向的。

真正的殺機主因是 Python2 end-of-life,而 GAE (Google App Engine,均一採用的雲端代管服務)Python3 的 SDK 與 Python2 截然不同,需要人工修改大比例的程式才能搬遷至 Python3,我們認為也許長遠來看,把母專案 junyiacademy 絞殺掉遠比就地重構更適切!

當然,絞殺掉均一六年的基業是大事,不能信口開河,貫徹精實創業精神的均一教育平台工程團隊首先要小規模試驗,既然是小規模,好像很適合用一下很潮的微服務架構……

How we do this 2: 微服務小試身手

除了很潮,講究理性辯證的均一工程團隊自然要端出一套冠冕堂皇的理由決策要素。微服務架構的優點很多,下面只列出對我們影響最大的好處:

高內聚低耦合,說到做到!

微服務是一群協同合作的小型自主服務,架構師中的架構師 Martin Fowler 列出微服務架構的第一項優勢即是 Strong Module Boundaries,具體是用服務邊界來規範模組邊界。

由於服務之間通常透過 Web API 之類的方式互相溝通,相對於同一個程式碼基礎中的另一個模組或函式庫,服務邊界顯然更明確,要搞曖昧也不是不行,但是眉來眼去的成本就高得多。

我的技術堆疊我決定

除了明確的模組邊界以外,微服務的自主性是一大關鍵。

你看看,母專案 junyiacademy 是 Python2 寫的,新服務當然不可能沿用。微服務是獨立的實體,在 GAE 框架下則是獨立的 service,可以自主決定使用的語言,擁有一組隨著流量自動擴充的虛擬機。

GAE service 還有一點非常適合微服務新手,就是和母專案共用資料庫。

因為微服務架構的成功與否幾乎由服務邊界的品質決定,而服務邊界需要時間淬煉,也就是要反覆調整才會穩定下來;調整的過程如果經常牽涉到折磨人的資料庫搬遷,大概會很快放棄,判微服務架構出局。

不過聊到這裡,有些讀者已經想到,既然可以換語言,Python2 轉 Python3 又因為 SDK 不相容沒有主場優勢,那 GAE 提供好幾個語言的環境都可以考慮啊!

沒錯,其實筆者手寫 Python3,心裡想的卻是 Golang,但為什麼不心手合一,直奔 Golang 呢?

筆者認為,均一工程團隊雖然對前沿技術心神嚮往,卻也懂得墊墊自己斤兩,白話文是資源有限,一次挑戰一個主題,小步前進是我們對專業的尊重。

現階段的主題是分解系統,用小服務取代原大專案的部分功能,我們把焦點放在找到好的服務邊界,確保相關的行為聚集在一起,且盡可能以鬆散的方式做跨邊界溝通。

高大上的東西交代到這裡,下面來談談我們實際做了什麼。

Our progress now 1: Python3 Content Service

前面有提過,直接分析程式碼尋求服務邊界不容易,我們轉向從產品角度切入,配合組織發展的目標,決定一號微服務由教材內容管理擔綱演出,以下稱作 Content Service。

暫態:Python2 Content Service

這個暫時的階段主要工作是解除多餘依賴。為了幫助我們在程式碼中釐清 Content Service 的合理依賴的對象,我們先複製純粹內容的 API 到暫時存在的 Python2 Content Service。

不要小看這一步,均一在線的 API 數目很大,而內容又屬於底層邏輯,切出幾個少數的 API 可以大幅簡化問題。

即使是簡化過的功能,複製出來的程式碼仍然包含了許多不合理的依賴性,例如下面示意圖中,Video(教學影片)需要依賴 User 邏輯即是一例,而 Topic (主題)和 Badge (徽章)之間的 cycling import 則更刺眼。

content service 相依性示意圖
Content Service 的相依性示意圖

解依賴的過程充滿了解和體諒,我們探討 Topic 和 Badge 你來我往的箭頭究竟怎麼出現的?又有哪些箭頭該塗上紅色?然後板起面孔,塗一輪紅色殺一輪。

就這樣迭代了幾次,讓內容的相依性只剩下身份驗證,快取與資料庫操作等基本元件,接下來切回 Python3 主戰場。

Package 依賴關係規範

為了避免重蹈原始專案的覆轍,參考 Khan Academy 的經驗,我們也建立了 package 之間依賴關係的規範:為每個 package 定義層級,依賴關係必須從高階至低階,且同階層之間不能有依賴關係。

下圖是 Python3 Content Service 目前每個 package 的依賴關係,包含了微服務的基本配備與 content 核心邏輯。

Python3 Content Service package 之間的依賴關係與階層
Python3 Content Service package 之間的依賴關係與階層

Our progress now 2: Content Package

在內容主邏輯部分,過去最大的困境是 Topic 和教材 (Exercise, Video, …) 之間互相 import,產生了很多的 cycling import。

重新架構的 content package 引入了工廠模式,透過內容工廠(contnt.factory)做相依注入

所以主題和教材之間不再有互相依賴,細節可以參照下圖的 content.internal.xxx。除此之外,content.xxx 是 package 的入口,也就是讓負責 api routing 的 main.py 呼叫的進入點,目前有 content.topic。

Content package 中 module 的相依關係
Content package 中 module 的相依關係

以上是 2020 Q1 勾勒出的 Python3 Content Service 架構,接下來的幾個月會不斷充實它。

為了避免美好清晰的架構隨著功能豐富而崩解,我們同時也堅持幾項規範,包含單元測試覆蓋率大於八成、pylint 沒有 warning 和 error,以及引入工具檢查前面介紹的 package 依賴關係是否符合規範。

想要了解更多可以參考或直接參與我們的開源專案


均一軟體工程團隊招募中!

你對教育有想法、對全端有些興趣,想要跟艾彌一起充實 Content Service 架構?我們正在招募軟體工程師,馬上到招募頁面了解詳情、投遞履歷!


作者|陳艾彌(均一平台教育基金會資深軟體工程師)
編輯|陳又慈(均一平台教育基金會實習生)

分享這篇文章:

相關文章

生命的改變從教室開始

在孩子長大成人之前,有將近一半的時間在學校度過,許多孩子的成長與改變也在這裡發生。有些孩子從討厭數學到數學成績名列前茅、有些孩子從討厭學習到願意學習,卻也有些孩子無法前進,不論是學習動機低落、教育資源受限,都是可能的原因之一。

也因為看見了這些孩子的困境,我們希望透過科技的力量,提供孩子們優質且免費的學習資源,落實教育平權,打造一座沒有牆的教室。

我發現,原來教學就該是看見孩子真正需要被幫忙的地方,而不是看教學指引而已。

大同國小.林政琦老師

教室裡的改變

均一在一次次與學校、課輔班的合作中,看到許多成長與改變的故事。

我們看到有孩子從一開始放棄數學、不敢發問,到後來能主動舉手發問,甚至能教其他同學;也看到有老師體悟到成績不是一切,重要的是孩子們的學習態度以及如何面對挑戰與困難。

可能有一些東西並不是,成績單上面看得到的,有的時候我們好像,太在乎這個學生的表現是集中在成績這一塊。

文英國中.李延慶老師

孩子有無限多的可能正在教室中發生,邀請你與我們一起,創造更多免費優質的教育資源,讓更多孩子的未來有好的改變。

你也能一起參與改變

均一是一個非營利組織,為了專注於我們的願景使命,我們不承接政府預算、不發展有對價關係的盈利,仰賴與我們有相同願景使命的大眾捐款支持,期待集合眾人之力,實現真實的共創與共好。

邀請你一起參與 >> 公益支持

不分城鄉,教室裡的學習弱勢

不論在都市或是偏鄉,教室裡都存在著學習弱勢。每個孩子的學習步調、吸收知識速度都不同,如果孩子們沒辦法在教室裡學到適合自己步調與發展需求的內容,都有可能處於學習弱勢。我們希望透過平台上免費有趣的學習影片與習題、科技化的平台輔助功能,讓這些孩子能夠按照自己的步調學習,培養自信找回成就感,發揮原生天賦。

我們藉由課輔班合作計畫與學習扶助計畫,讓更多學習速度不同的孩子,得到差異化的教學,弭平學習落差,並在過程中持續鼓勵、陪伴孩子與教師

課輔班合作計畫

透過與課輔班合作,均一提供平板筆電載具、專業師資培訓與觀課陪伴,協助課輔班老師能以遊戲化的數學學習模式,讓弱勢孩子重拾學習興趣、鞏固基本學力。合作期間,也看到許多老師陪伴孩子的動人故事,我們記錄這些過程與故事,也邀請有興趣的你,點擊下列文章更了解計畫成果,也認識課輔班老師的故事!

有位平常學習上較落後的孩子,跟我分享,是磨數營讓她愛上數學。甚至跟我說 : 努力沒有做不到的事!

屏東躍愛課輔班 林綺漩 老師

學習扶助計畫

在 106 學年度,均一與苗栗縣和屏東縣分別合作進行「結合均一的課中補救」試辦計畫。藉由一般課堂的時間,抽離需要額外學習扶助的孩子到「學習扶助班級」,搭配均一平台的使用,有效診斷學生的學習斷點,提供個人化學習。

經過三年的顯著成效與現場教師的正面迴響,109 學年度起,均一在苗栗、屏東推動學習扶助「深化」模式,除了繼續數學課中學習扶助外,期盼藉由更深度投入的專案教師、更具規模的教師社群、更系統性的增能與支持,為學習扶助的師生帶來更有效的教與學。

學習扶助計畫進行的這幾年,我們不只看見許多孩子學習的進步,更看見許多老師教書育人的理念,邀請你點進下方文章,認識其中一位專案教師的故事。

苗栗文英國中李老師照片

帶孩子走出教室裡的無力感 —— 苗栗延慶老師分享

在眾多均一平台上的老師當中,今天想特別與大家分享延慶老師的故事。延慶老師是「均一課中學習扶助深化專案」的老師,他觀察到,傳統一體適用的教學當中,班級內存在的學習落差影響了孩子的學習信心;透過「課中學習扶助」,老師們能用不同的教學方式,幫助孩子建立學習成就感,以及對未來的信心。

了解更多 »

你也能一起參與改變

均一是一個非營利組織,為了專注於我們的願景使命,我們不承接政府預算、不發展有對價關係的盈利,仰賴與我們有相同願景使命的大眾捐款支持,期待集合眾人之力,實現真實的共創與共好。

邀請你一起參與 >> 公益支持

是老師,也是教育創新家

在均一有一群老師,不只出現在第一線教學現場,分享如何利用平台提供孩子們差異化教學,給學校或課輔班的老師,更設計出多元跨領域的課程,激發孩子們的學習動機。

我們在台灣擴大推廣 Code.org 的 Hour of Code 一小時玩程式,團隊夥伴製作中文化插電與不插電的程式課程、結合創意的教學設計,讓 Code.org 這套全球廣受好評的程式課程,在台灣的使用濃度達到世界排名第九、亞洲排名第二,讓臺灣的程式教育能夠與國際接軌。課程資源與師資培育,都逐步與國際接軌。

「模組化的課程設計,不論對教師教學、學生學習都有很大的幫助;因為課程規劃得很完整,老師能很清楚第一步要如何開始、接下來又該怎麼做,以及背後的教學目標,搭配程式闖關遊戲,小朋友會更有動機去嘗試、思考,甚至他們做完後、還會想再做一次,主動地去複習所學!」

太平國小 陳宜均老師

為了讓孩子透過程式學習運算思維,均一也設計了一系列 Scratch 課程,採取專案導向學習 (Project-Based Learning),以深入淺出的講義或影片引導,經由不同領域主題,’當孩子面對給予的任務,將學習如何解構問題、摘要重點、發現規律,循序漸進地練習程式的思考。

數電快閃教室

數電快閃教室計畫,是團隊夥伴到教學現場透過「數學 X 電腦科學」的跨領域課程,將好玩、互動性高的電腦科學融入數學的課程內容,讓孩子覺得原來數學可以這麼有趣,學到的知識也可以加以應用。均一也透過此課程和現場老師分享跨領域教學,探索更多的學習可能

後續雖遇上五月份的疫情,團隊發揮創意推出「線上快閃教室」,以線上的形式,快閃 18 所國小的線上教室,帶來「自學力就是你的超能力」主題分享,總計有 329 位學生參與,我們希望藉由這個活動,讓孩子在疫情期間能夠找到自己學習的目標和節奏。

當我們 Code 在一起說故事

「當我們 Code 在一起說故事」專案計畫,也就是平台上「電腦科學起步走|一起說故事」課程,是源自 Google 開發的 CS First,均一除了將其中文化翻譯,並且配合 108 課綱將課程內容和教學模組在地化。課程內容以程式作為跨域學習的槓桿,融合電腦科學、語文、音樂、藝術,鼓勵孩子用想像力編寫動人的故事,並且練習程式的思考。

此課程也獲選「 第三屆未來教育.臺灣100 – 全臺年度百大創新教學專案」的獎項殊榮。

每個孩子都希望能創造屬於自己的故事,細緻的課程架構,並附有專人引導的自學影片,孩子可以根據自己的學習和創作速度前進,人人都有成就感!

KIST: 拯民國小.宋亭緻老師

你也能一起參與改變

均一是一個非營利組織,為了專注於我們的願景使命,我們不承接政府預算、不發展有對價關係的盈利,仰賴與我們有相同願景使命的大眾捐款支持,期待集合眾人之力,實現真實的共創與共好。

 邀請你一起參與 >> 公益支持

教室裡的風景

每個人的生命當中,都有那麼幾位令人印象深刻的老師。有的老師幽默風趣、有的嚴厲而堅毅,有的老師像是再生父母,讓我們從學習與探索中,發揮生命更大的價值。

在 2021 年 的停課期間,有一種老師大量增加了,他們是守護孩子學習不中斷的「抗疫老師」,在短短幾天內,設法與孩子取得聯繫、使用各種數位工具,並給予遠距支持。

事實上,在在台灣的每一個角落,一直都能看見這些義無反顧為孩子付出的身影。以下是均一在推動教育改變的路上,遇到的幾位老師,希望透過簡短的文字、影片,與你一起分享,均一在教育現場的看見。

均一教師的身影

安溪國中——靜怡老師

靜怡老師任教於新北市安溪國中數學科,七年前開始使用均一教育平台,並將均一應用在「適性分組班」與自己的班級教學當中。

「讓孩子不會只是之前的挫折一直累積到最後,讓他可以在這裡找到讓他產生信心的地方。」/ 靜怡老師

點我看靜怡老師的完整分享 >>

 

安溪國中靜怡老師

 

高雄岡山教會課輔班——子婕老師  

子婕老師雖罹患罕病,仍完成中央大學數學、資工雙主修,更因為從小便與媽媽在教會服務弱勢孩童。研究所時對數位教學產生興趣、畢業後即投入弱勢教育。2020 年導入均一教學後,子婕老師與課輔團隊投入其中,幾乎天天討論到深夜。雖然孩子的學習成就並沒有一飛沖天,但她認為,孩子的正面心態、學習品格才是第一順位。

「我希望這些孩子記得,小時候有這麼一群人拼 死拼活努力去愛他們,他們是值得被愛的。」/ 子婕老師

點我認識「弱勢課輔班計畫」>>

均一如何支持教師

均一經由支持教師,更規模化地影響孩子。

在子婕老師參與的弱勢課輔班計畫中,均一在兩年內培訓了 110 位教師,其中有 87% 的老師過去未曾使用數位平台輔助教學,在經過師資培訓後,提升了 20% 老師的教學信心,大多數老師更能夠獨立於課堂中教學,陪伴孩子探索數位學習平台,找到適合的學習內容。

除了弱勢課輔班計畫之外,均一長期與苗栗、屏東學習扶助班級合作,培養學習扶助科技教師。疫情期間,更曾累積上千名老師同時在線參與研習培訓,支持全台教師、家長陪伴孩子停課不停學。疫情之後,超過半數的現場教師仍持續採取科技搭配教學,數位學習將是教師、學生、家長不可或缺的關鍵能力。我們期待持續投入培訓資源與教學法開發,支持現場教師,進而支持更多孩子。

你也能一起參與改變

均一是一個非營利組織,為了專注於我們的願景使命,我們不承接政府預算、不發展有對價關係的盈利,仰賴與我們有相同願景使命的大眾捐款支持,期待集合眾人之力,實現真實的共創與共好。

邀請你一起參與 >> 公益支持