AlphaCamp_DevC4 完課心得
By Po-Ming Chen in Career
December 17, 2024
寫著這篇完課心得,難掩雀躍,同時也知道取捨了一些東西,像是 Capstone Project。更多的是,知道自己學了一些東西,但是距離可以求職面試、做一個合格的初階後端軟體工程師,還有一段路要走。基本地,除了履歷,我還需要一個 side project。
不過還是來做一下 ORID 吧~比較可以知道自己又累積了什麼,接下來又可以往哪裡去。
Reflective
Reflective1_上傳圖片功能&自動化測試
進入 C4 後半段,開始進入最後的『餐廳論壇』教案,也是整體複雜度最高的教案。C4_M4 從搭建網站基礎架構開始…首先建立餐廳管理後台,做到管理者可以新上架餐廳,新增餐廳分類,管理哪些使用者是 Admin 權限的功能等等。
其實我覺得網站能夠區分前後台,跟建立登入機制一樣很玄,不過學到這,才發現邏輯大致是一樣的!建立網站後台(Admin)其實就是用一個專門的路由模組 /admin,將其區隔出來,然後再搭配驗證策略,透過 middleware,像是 router.use('/admin', authenticatedAdmin, admin),讓滿足條件的使用者,得以進入到後台的路由模組,進而對網站資料進行 CRUD。同時這個過程也讓我更理解 Controller 跟 Router 是不一樣的!對於 Controller 作為 Model 和 View 的橋樑『定位』有更深刻的理解。
不過這個環節,覺得最有意思的是透過第三方套件 multer 實作出讓使用者上傳圖片,新增簡歷照片在 User Profile 頁面的功能。 讓我想到之前在 均一 ,請同事開發在客服流程可以上傳圖片,方便使用者得以更詳細說明遇到什麼樣的平台操作問題,覺得很妙,很好奇上傳圖片的功能到底是怎麼被做出來的,然後那張圖片要存在哪裡!?學到這裡,發現原來他並不是很遙不可及的事情…
整體來說,也是循著 MVC 架構,再加上專門的 multer middleware,像是 router.post('/restaurants', upload.single('image'), adminController.postRestaurant) 來實現,然後背後有一個操作 localFileHandler 函數的 file-helpers.js,讓上傳過程的檔案,可以從 temp folder 正式複製到 upload 資料夾。完成檔案正式上傳。
另外,教案批改作業也導入了自動化測試,第一次看測試檔,也挺有意思的,大致原則是看 describe > context > it,去瞭解這個測案要測什麼,用「測試驅動開發 (test-driven development)」去思考 MVC +Router,可以怎麼規劃,甚至是如何處理 edge case,感覺是滿有幫助的。
不過如何寫出好的測案,還有一些教案先省略的環境設定,像是 .yml,不曉得除了找機會跟前輩學,也想看看怎麼讓 AI 在這個環節可以幫上忙~
Reflective2_用 Sequelize 操作資料表關聯
隨著想給使用者的體驗越來越豐富,有時候後端從資料庫撈出資料的時候,勢必會不只一張表,像是撈出餐廳清單,也會想要知道餐廳的分類,餐廳與餐廳分類之間,是多對一關係;像是想撈取餐廳評論,就會涉及是哪一個使用者,在哪一家餐廳留下的評論,使用者和餐廳,在評論這個維度,是多對多關係。
這時候就要善用 Sequelize,先界定好 Model 之間,是一對一、一對多、多對多的關係,然後拿捏 {raw: true, nest: true, include: [TableName], limit: n, offset: n, order },這六個參數,將撈出來的資料,轉換成方便後續給 View 或前端使用的資料結構。
其中 include,大致可以理解為 SQL 的 JOIN,若想要處理多對多的關係,基本地就是在 include 內,寫下兩個物件(前提是已經在 Sequelize Model Instance 把 Model Association 設定好),像是以下:
Comment.findAll({
limit: 10,
order: [['createdAt', 'DESC']],
include: [User, Restaurant],
raw: true,
nest: true
})
若有兩個以上不同目的要分開撈,最好是善用 Promise.all,讓所有非同步處理的撈資料動作,都完成後再繼續往下(.then()),這對於平常就在操作 SQL 的資料分析師來說,並不是太難想像,反倒是要將撈回來的資料整理成方便運用的結構,甚至有時候也會需要加工出新的 JS 物件屬性(Property)後,才吐回給前端。這個議題,不管是走 MVC 全端開發的路線,或者是後端走純粹 API 提供資料,對 JS Object 的操作熟悉度是躲不掉的(像是 trinity operator, spread operator),所以該走的學習曲線,哪裡不熟,還是要走過的 XD
除了相對複雜的多對多關係(在 Sequelize Model 中也要額外設定比較多東西,像是收藏餐廳功能,User, Restaurant Model,都得設定 belongsToMany 的關聯),最後,我覺得像是使用者可以互相追蹤的『自關聯(Self-Join)』其實也滿有趣的,在現職 DA 不算常在處理這種情境;一個使用者可以被多個人追蹤,一個使用者也可以追蹤多個人,但是額外拉出一張關聯表(Followship Table),欄位名稱就無法依慣例命名為 user_id。就得改命名為 follower_id 和 following_id。然後 User Model 就得設定自己對自己的 belongsToMany,大致如下:
User.belongsToMany(User, {
through: models.Followship,
foreignKey: 'followingId',
as: 'Followers'
})
User.belongsToMany(User, {
through: models.Followship,
foreignKey: 'followerId',
as: 'Followings'
})
Reflective3_建立自己的 RESTful API
在整個『餐廳論壇』實作教案,基本上就是規律地在處理 MVC + Router,但是自從 AJAX 的技術出現後,他可以透過 API 只更新頁面上的部分資料,這個技術的實現,讓前端、後端分離的概念得以發生。
改寫成 API,是讓後端工程師不用去煩惱 View 的部分,只需要專注在如何提供資料,以及提供什麼資料。在這個教案之前,有一些 API 的操作經驗,但是建立自己的 API 還真的是第一次。乍聽之下是有點複雜,但是想到可以建立自己的 API 給別人用,同時也更了解 API 是怎麼一回事,也是滿期待的!
畢竟是後端專修,暫時不用煩惱 View 的部分,所以在實作指標作業的時候,也算是暫時地鬆一口氣。開始做 API 之後,感覺做的事情是大同小異,像是 Admin 也要有自己的路由模組,像是 routes/apis/modules/admin.js,一樣要跟餐廳前台(routes/apis/index.js)的功能分開來。另外也發現有一些新的概念要注意,像是撈出來的資料,最後多是以 res.json ,處理成 JSON 格式的資料後提供給使用者,而且最好是再建立一個 Service 層,將原本多在 Controller 處理的程式碼(包含撈資料的操作),分離出來,做到更好的關注點分離(SOC)。
讓商業邏輯與流程控制分開,後者就能更專注在提供給使用者 JSON 資料的那一哩路。整體流程變成了 Controller, Model + Service + Router,但是要小心像是 req.flash 的內容,還是要保留在 Controller 裡面。
接下來,搭建了自己的 API,自然也得測試給出來的資料,是否符合預期,若老是只能用瀏覽器修改路徑去確認,肯定不是個太有效率的做法!?所以要解決這個問題,就需要熟悉像是 Postman 這樣的本機測試介面,來確認 request 和 response 是否如預期。並且作為前後端工程師溝通的橋樑或協作文件。
最後,關於 JWT(JSON Web Token),那為什麼這時候需要認識 JWT !?
畢竟在 MVC 版本的全端開發,也只有具備 Admin 權限的使用者,才能夠進入到後台路由,那換成 API 進行 CRUD 的過程,原本習慣的 cookie & session 機制(cookie 是用戶端的憑證,像是會員卡;session 則是伺服器端的憑證對照表),只能使用在同網域,所以勢必要有其他的做法,來解決『驗證使用者登入』、『有沒有資格持續使用網站的服務』,確保其有資格做 CRUD 的動作。
改成 JWT 的方式,當使用者在 POST /signin 的時候,會用帳號和密碼向伺服器端換取一個 token,之後發送的每一個 HTTP 請求,都要夾帶這個 token 參數。然後再用一樣是寫在 config/passport.js 內的 JWT Strategy,將夾帶的 Token 和 Secret,還原成使用者的身份資訊(像是 user_id),然後就可以進行資料庫撈取,組合出要返還的 JSON 資料。
Interpretive
做到『餐廳論壇』教案,其實已經可以慢慢感覺到後端的工作有一定的規律,像是反覆用 MVC+Router,來完成 User Story。也感覺難的地方是抽象化思考,像是把反覆用到的程式碼,抽取出來維護,做到關注點分離(SOC)。用越少的設計(像是 API 設計規劃)滿足越多前端需求。另外就是隨著流量提高,逐步去思考資料中介層(GraphQL)的可能性,以及用資料庫讀寫分離來提升效率。這些都需要持續觀摩、實作才會進步,應該也是目前 AI 比較沒辦法取代的地方。
此外,做到建立自己的 API,前後端分離,後端只專注給資料,突然有一種感覺,這跟現職 DA,大概有 1/3 的時間,在撈資料產報表、做儀表板,思考 deliver 什麼樣結構的資料,可以符合使用者需求,進而輔助商業決策,其實有點異曲同工之妙。
最後,如果真的有件事可以重來,我覺得再早一點讓 GitHub Copilot 融入我的工作流程中,特別是他可以跟 VSCode 整合地很好,而不是還要切換分頁到 ChatGPT 把想問的程式碼貼進去,專注度自然就被打斷了,也可以省下許多時間。
但是還是要小心,剛接觸一個新的程式語言不久,可能要適度地關掉自動填補功能,可以跟 Copilot 聊,追問他,但是不要讓自己變成了 Tab-Tab Engineer,也剝奪了自己思考、嘗試的機會。
Decisional
下班後一點一滴學這門課,不知不覺也將告一個段落,難度和花的時間都比預期還要多 XD,不過就像開頭講的,距離可以求職面試、做一個合格的初階後端軟體工程師,還有一段路要走…基本地,是需要一個 Side Project。
在那之前,首先,想先稍微沉澱一下,再聽一次 【V018用經營公司的思維經營你的人生】 ,思考一下人生願景和自身優勢,DA 背景轉後端,還有自己的一些參與系統移轉專案、建立資料市集(Data Mart)的經驗,其中有沒有什麼優勢是別的求職者所沒有的?
加上隨著 AI 浪潮,junior 的缺變少,求職門檻也會變高,雇主對於有能力做全端的人才期待,相信是會越來越明顯。當然是得從前後端其中一個開始,不過也讓我想到若要做一個有競爭力的 Side Project,總不能忽略使用者體驗……
現職做 DA,陸續感覺到 Tableau 作為一個視覺化套裝軟體,相當地精細;花在設計、視覺化,進而嘗試找到商業洞見的的時間,有時會被『為了要保持對細節的操作熟悉度』打擾(像是雙軸怎麼拉、甜甜圈圖怎麼做、圖例選哪裡才能那樣擺),常常需要將工具書放在手邊,偶爾也會有 Tableau 版本落差的問題,那樣的過程對我而言更像是照本宣科地操作模仿,而不是創造價值。
特別是 DA 的工作像是 1/3 專案管理 + 1/3 資料的本職學能 + 1/3 產業知識,當工作重心若一陣子放在談需求、寫文件,回到視覺化操作,突然也會有點不上手…
再者,熟悉一個套裝軟體的使用延展性和長期價值,終究比不上熟悉一門程式語言,也比較難讓 AI Copilot 融入到工作流程中(如果現在就可以的話,我會很想知道 XD;也許幾年後 AI Agent 出來後可以動動嘴巴,說出你要的,然後他就可以代替你操作 Tableau,不過終究是要承認套裝軟體的限制是比較大的),讓我想到自己若能對前端知識多一點了解,就可以更靈活地精進使用者體驗和資料視覺化。
這也讓我在想,在做 Side Project 的同時(或者說之前),稍微再有系統地瞭解一下前端的世界,畢竟在學 C4 後端專修的時候,遇到前端介面的處理,首先 express-handlebar,相對已經模板化,而且有時候為了方便專注在後端的實作,教案會直接給前端的程式碼,必要時自己也會用 Copilot 直接生成 workable 的前端程式碼。這不是不行,但如果想走得長久,終究還是需要系統性走過一遍。
總結來說,我想可見的下一步是重新對焦自己的人生願景和優勢,然後找前輩聊聊,在 AI 浪潮下,想上岸轉後端,可以繼續怎麼走?比較不會重新發明輪子。
應該優先再把 JS 基礎打得更穩,並且將 Node.js 開發弄得更熟,以及接觸一些常見的後端應用功能場景呢?還是應該要分點心思補一點前端知識,讓個人的 Side Project 可以更具競爭力 ?(甚至做 Side Project 過程找一個 Mentor,可能也是不錯的考量)。
就先寫到這囉,期待 2025 可以持續穩健地成長~
Don’t overestimate the change that will occur in the next two weeks, and underestimate the change that will occur in the next two years.