從 React 到 Nextjs(TypeScript):在醫療視訊看診公司的開發之旅
不知不覺,我已在軟體業打滾超過三年了並在其中學習和成長了許多。
作為一名前端工程師,我一直想要分享我的工作心得,尤其是在最新的一份工作中所學到的經驗。
作為一名醫療視訊看診公司的前端開發者,我在 React 到 Nextjs(TypeScript)的學習和應用中,以及在公司中的工作經驗中,獲得了許多寶貴的經驗和收穫。現在,我終於起心動念,要分享這樣的內容了。
嗨,我是一名前端開發工作者。
2020 年 6 月,我從化工工程師的職位轉職到前端領域,現在已經有差不多三年的經驗了。
面對了不同的挑戰,我也都努力的跨過去,讓我對於這份工作的熱情和興趣只增不減。每天都有不同的挑戰和學習機會,讓我不斷地挑戰自我,並且提高我的學習能力和事情分析能力。
我學習了很多關於前端開發的知識和技能,並且發現到軟體開發的領域不只是技術,更多的是溝通問題,這也使我不斷地成長和進步,近一步地加強了我的信心,這也讓我更有信心面對未來的挑戰和機會。
而目前在這家公司,我主要參與開發醫療視訊看診系統,這在疫情時期扮演著重要的角色。正是我們公司開發的應用程式,政府利用它來追蹤確診病例並提供診斷和治療建議。
我的工作內容主要是改進和優化產品,為舊產品新增功能並提高使用便利性。為了未來的開發便利性,我進行了全面升級,甚至加入了 prettier、husky 等工具,以提高開發效率。
此外,隨著疫情趨於緩解,我們公司也開始進行新專案的開發。在文章中,我也將介紹我們在新專案中所做的努力,包括採用的新技術和如何加速開發的方法。
首先,先來簡單介紹一下我公司背景吧!
公司背景
我的公司是一間專注在遠端醫療視訊看診系統的新創公司,主要目標是在解決,我們的產品旨在解決醫療機構所面臨的問題,並提供便捷的醫生看診和行政人員後續管理追蹤系統。這些是我在公司中主要負責的領域。
針對醫療機構方面,我們提供了一個方便的視訊看診解決方案,以支持醫生在遠端環境中進行看診。而這涉及到了處理視訊相關的技術挑戰,像是確保視訊品質跟穩定性,另外也開發了方便行政人員管理病人的系統,使得他們可以方便地管理以及追蹤病患的系統。
而針對病人方面,這部分是使用 React Native,開發了一個使得病人只要下載 app 就可以跟醫生約診看診的系統,而這部分涉及比較少一些,大致就是會幫忙 debug。
後來這個專案被政府看中,所以後來變成的疫情期間用來遠端確認是否確診的軟體,也著實幫助政府減輕了很多的疫情壓力。
有一次,當我需要去大醫院看診時,我親眼目睹了一個讓我覺得感動的場景。我也當場看到有醫生,一邊現場看診,然後一邊利用我寫的系統幫別人看診,著實自己也是滿感動的。我感覺到自己對於這個社會有盡到一份力量,這也是我一直很在乎的事情。也讓我認知到自己的工作能夠對於社會產生一份正面的影響,所以我以後也都會在這方面進行更多的努力讓自己可以持續產生正面的影響。
我的背景和經歷
關於我的背景,我是三年前從化工工程師轉職成為一名全端工程師。
對,沒看錯,我在第一家公司是先當全端工程師的,當初也有點誤打誤撞的被這家錄取,這是一段讓我成長的驚奇之旅。
透過學習和實踐以及熱情,讓我從矇矇懂懂的小小開發者到能夠了解整個開發流程,甚至後來我也為公司帶來了改進。這也多虧於當初轉職時的指導老師是一名厲害的資深工程師,帶給我很扎實的基礎知識。
而我在這份中掌握了完整的開發流程,從討論需求到資料庫、開 API 規格到前端的實作討論,甚至也有幸參與改版官網,然後為了新的官網,進行寫自動化測試以及持續整合/持續交付(CI/CD)流程的開發。使得我對於軟體開發有更全面的認識,並學會在迭代和快速交付的環境中高效工作。
在工作中,我本身就是喜歡解決問題的人,我是一個積極於提高效率以及改善流程的人,在我還是化工工程師的時候,我也很常為公司規劃更好的工作動線,指導新人,甚至是協助改善工安問題,即使不是我的工作內容。
而後來我也把這個積極心態跟這些經驗帶入第二份以及第三份工作,所以後續也直接或間接的改進了之後工作的開發流程,使得公司開發更加順利,提高團隊效率以及程式碼品質,而我也更加清楚我自己是一個什麼樣的人。
第二份工作的情況可以參考上面這篇
初期階段
當初在前一家工作時,我面對了很多挑戰而且也成功地完成了。也讓我學習到除了寫程式碼之外,溝通這件事情也很重要,因為清楚的溝通才可以讓專案更有效率的完成,而我在當時的接案公司,也確實證明自己有辦法面對溝通成本極高的環境,而且確實完成公司的需求。
這也讓我有十足的自信能夠面試新公司,也就是目前的遠端醫療公司,也因此很快就收到錄取通知,並開始在這家公司工作。
而一進去接手到的專案,基本上之前公司是屬於草創階段都只能請 junior 工程師的關係,所以整個產品架構不夠良好。我記得有四五個專案吧,後來三個就在其他工程師的建議之下砍掉重練了。
而我接手的專案是醫生端,也就是醫生在使用的 web 介面,這個專案是屬於勉為其難不需要砍掉重練的,但本身也是問題滿多的,像是架構面、效能面、可擴展性、UI/UX、DX(Developer Experience)等等的方面,所以由我把原本的整體做了改善。我也承襲了之前很嚴謹的風格,從添加新功能、重構到修正視訊介面等等,進行做了很多改善、優化跟重構,然後也因為碰到疫情大爆發,後來被政府採用,於是又多了更多的緊急功能開發。
也因為這間公司有一個比我更資深的工程師,在跟他討論溝通後,他告訴我專案不一定要用 Redux,尤其是現在有 Hooks 之後,所以我也慢慢改觀了。
我在前公司時,新的專案是有大量 API 的需求,我建議使用 Redux + Saga,雖然真的是很有挑戰性,但實作起來之後用起來很順,也能把大量 API 整合再一起。然而也許單純用 custom hook 包再一起也是個很好的解決方案。而我後來也在這間公司的新專案,採用了 React Query,這個套件的特性又更可以省下 Redux 的使用,降低專案的複雜度,這之後會再聊到。
原本的專案是大量使用 Redux,所以這裡我也有一份額外要做的事情,就是慢慢地透過開發新功能,去重構原有的程式碼並且移除對於 Redux 的依賴。
在這部分我學習到了,我學到了一個重要的觀念:將事情保持簡單,不一定要使用複雜的解決方案。這個觀念讓我逐漸提升了自己的能力。
漸入佳境階段
隨著疫情的嚴重程度不斷加劇後,平台的使用量也越來越大了,使得我們發現了更多有待優化的問題,其中一個要改進的點就是由於 SPA 的先天限制,例如客戶抱怨「開啟網頁時,白畫面的時間有點久」,但我知道這個是 React 的先天限制,因為我一直有在關注新的趨勢,所以我直接就意識到這是個問題。
幸運的是隨著 React 版本的更新,有了更多的方案來解決這些白畫面太久的問題,像是我們可以使用 Suspense componet 搭配 React.lazy
來延遲元件載入,並且載入完成前先顯示一些內容。新版本的 React 甚至可以直接搭配 Route 使用,這些都是非常有趣的功能。
那時,我也一併提出既然要做,就要做的全面一些,經過討論後,決定要做全面的改善,所以我引入了一些 pre-commit check 的工具。我們選擇了 AirBnb 的規範。棄用了原本前人自行撰寫的規定,因為這些自定規範導致我們的程式碼與常見風格不同,例如使用 Tab 而非空格。
這是我第一次在既有專案上面安裝這些工具,還好的是我之前已經有多次在新專案上面安裝這些的經驗,所以這次是除了安裝外,還需要把這些 Eslint 的錯誤改正,不多,就大概三五百個而已,哈哈。
這次升級不僅僅包括工具的安裝,還涉及到對數百個 Eslint 錯誤的修正。這些修改讓我意識到自己能夠處理這樣的挑戰。在當初轉行學習時,我看到 Eslint 的錯誤時會感到無能為力,但現在我能夠自信地應對這些錯誤。
所以也是一次性的升級了不少東西,把整個專案從不良漸漸的被我改進到一個品質良好的專案了,但這樣的轉變算是很大了,畢竟還有很多前人留下的東西是沒辦法通通改掉的,畢竟公司有公司的壓力,不可能讓我們去全面的修太多細節的部分。
這個過程證明了我有能力全面改善一個產品,使其變得更好。這正是我在之前的公司一直渴望實現的目標。
從零到一開始開發新產品
隨著疫情的越演越烈,這讓我們公司預感到指揮中心可能會快要解散了,畢竟疫情的毒性也漸漸變小了。這可不是好消息,因為這意味著我們的收入會減少,公司得找新的出路了。於是,在去年八月的時候,我們開始規劃下一代的產品。
我們希望這個新產品可以廣泛應用於不同的醫院、診所,但問題來了,某些功能只想開放給特定的診所或醫院使用。一般來說,我們都是用設定的方式來遮蔽功能,但這樣做有點煩人。首先,我們還是得把整個功能程式碼交給客戶,只是用遮蔽的手法來隱藏一部分功能。嘿,這樣不就造成了網路頻寬的浪費嗎?而且,如果遮蔽機制沒做好,客戶很可能就能免費使用本來不該開放的功能了!最重要的是,開發的時候也超級麻煩,因為功能和功能之間可能互相影響,簡直是個災難。
所以,我們公司決定採用一個叫做 mono repository 的結構,並且使用 nxjs (mono repo framework)為主要架構。
這東西有什麼好處呢?讓我們來看看主要的優點:
- 模組化:使用 mono repository 可以將各大功能獨立地開發為模組或 library,使得代碼更加模組化和可重用。這樣一來,我們可以更輕鬆地引用和管理各個功能,不再需要打包多餘的資源。
- 代碼共享:mono repository 允許不同的專案共用同一個代碼庫,這樣可以節省時間和資源,避免重複開發相同的功能。同時,也方便團隊成員之間的協作和代碼分享。
- 版本控制:使用 mono repository 可以更方便地進行版本控制,因為不同的模組和功能都在同一個代碼庫中。這樣可以確保各個功能之間的相容性,並且更容易追蹤和管理代碼的變化。
- 測試和部署:mono repository 提供了統一的測試和部署流程,可以更好地確保整個系統的穩定性和可靠性。同時,也能夠更快速地進行測試和部署,提高開發效率。
這個新的開發模式讓我們能更好地應對客戶需求,提供更靈活、高效、合乎需求的產品。同時,我們也學到了如何適應新的技術架構並解決傳統開發中的問題。這個轉變將為我們的新產品開發帶來更大的成功。
全端經驗的優勢
在新產品開發的過程中,公司給予了我更大的責任,讓我主導了整個 web 方面的架構。資深工程師規劃了 mono repo 的各個層級,使得後端的 DTO (Data Transfer Object) 可以與 app 和 web 共用。在這方面我也有相關經驗,在我的第一份工作中,後端是使用 TypeScript 和 Express.js 構建的,並採用了 DDD (Domain-Driven Design) 架構。
這邊寫解釋一下 DTO 是什麼?
DTO (Data Transfer Object) 是一個在不同層級或模組之間傳輸數據的物件。它通常用於將數據從後端傳遞到前端或其他系統,並在傳輸過程中將相關數據進行結構化。DTO 的主要目的是提供一種統一的數據格式,以確保數據的完整性和一致性。
所以 DTO 可以前後端共用,可以保證資料的正確性。
由於我在第一份工作的經驗,這使得我能夠更好地與後端團隊進行溝通和協作。在這次的開發中,得益於 mono repo 我可以輕鬆地在前端需要的地方引用 DTO,這樣的好處是可以保證前後端資料的正確性,這樣我們就不用花太多時間成本在解析後端傳來得資料,因為之前很常碰到一個問題就是前後端命名不太一樣,導致了很多的溝通問題,這是一個很好的解決方式。
前端技術選型與狀態管理
在 web 方面的架構規劃中,我成為了主導者,負責整體實作的規劃。我們最終決定採用 Next.js 框架,並搭配 mui (Material-UI) 和 emotion。
Next.js 提供了更好的服務端渲染能力,讓我們的應用程序更具優勢和效能。它還提供了許多有用的功能,如預渲染、靜態生成和動態路由等,能夠更靈活地構建和管理前端應用程序。
同時,搭配 mui 和 emotion,輕鬆地構建出具有優雅設計和可擴展性的使用者介面。mui 提供了一系列的預製組件和風格指南,而且可以套過快速套用 theme 的設定,使得我們可以透過注入快速變換色彩主題。
考慮到快速開發的需求,我們也購買了一套套版作為參考和修改,以加速開發流程。需要注意的是,這套套版是基於單一存放庫 (singal repo) 的結構,與我們採用的 mono repo 完全不同,所以就只是變成參考的對象。
而這次我還使用了 React-Query ,這取代了大部分的 Redux 的工作,在這之前我們用 Redux 最主要是要利用 middleware 來管理 API,而 React-Query 這樣的工具,可以 cache 住之前打過的 API 資料,甚至我們可以把 API 跟 React-Query 一起打包成 custom hook,這大大地使得我們的 code 變得更加簡潔。
透過這些前端技術的選擇和狀態管理方案,我們能夠以更高效的方式開發和維護產品。同時,我的全端經驗使我能夠更好地理解整個系統的需求和架構,並更好地協調前後端的開發工作。
接下來就是要討論醫生端視訊的部分了!
改善既有視訊看診模式節省開發量
在我們的討論過程中,我們提出了一種不同的視訊模式,這能夠大幅減少我們的實作時間。
這個想法主要針對改善醫生的視訊看診流程。傳統上,視訊系統需要使用全螢幕模式,醫生必須在這個全螢幕畫面中執行所有操作。然而,我們意識到這樣的模式實際上就是造成我們需要重工的部分,尤其是當醫生在看診完成後,要補充或修改一些內容是,就需要另外切換頁面、才可以修改建議或藥單時。
為了改善這個問題,我提出了一個不同的方法,即讓視訊畫面一直存在於畫面中,而醫生可以自由地在需要的頁面上進行看診的相關操作。這樣的設計可以大幅減少在視訊系統內部重複實作相同的功能,同時讓醫生能夠更加順暢地進行操作。視訊功能只提供一個快速鍵切換,方便醫生快速切換不同的功能,而不需要將一直保持視訊畫面佔據整個螢幕。這樣的設計不僅提高了操作效率,還節省了不少的開發時間和工作量。
這個改進的視訊模式還帶來了其他優勢。首先,我們能夠更加專注於開發其他重要的功能,例如在視訊畫面中增加更多豐富的功能,像是模糊背景、分享螢幕等。同時,這也提升了使用者體驗,讓醫生能夠更輕鬆地切換並使用不同的功能。這樣的改進不僅節省了開發時間和工作量,還為醫生提供了更好的使用體驗。
這邊都是理論的部分,接下來就是實作 Twilio 串接視訊的部分了!
挑戰串接 Twilio API
在我們開始改善視訊流程之前,讓我們先介紹一下 Twilio。Twilio 是一個知名的通訊平台,提供了各種功能強大的通訊 API,包括短信、語音和視訊等。透過 Twilio,我們能夠在我們的應用程序中輕鬆地實現通訊功能,並提供無縫的通訊體驗給我們的使用者。
原本公司舊平台已經使用了 Twilio,但在舊有的前端串接方式並不理想,因此我決定藉此機會,以更好的方式來串接 Twilio API。
為了了解 Twilio API 的使用方式,我首先閱讀了 Twilio 的官方文件,然而發現這些文件並不容易閱讀和理解。
於是我改變策略,轉而閱讀 Twilio 的相關模組內(node module)的 TypeScript 資訊。這也是讓我在一次感受到 TypeScripe 的好處。
而我透過查看我注意到 Twilio 是使用訂閱(subscription)的方式來觸發事件,而且 Twilio 提供了許多可觸發的事件。
為了更深入了解 Twilio 的串接方式,我下載了一個實作 Twilio 的範例程式庫。雖然整個程式庫無法直接運行,但通過仔細閱讀程式碼,我逐漸建立起對 Twilio 的理解。
我改變了串接方式,以訂閱的方式設定適當的事件監聽器,最終成功實現了完整的視訊流程。這次經驗也讓我第一次熟悉了整個串接 Twilio 的層級和工作流程。
這次的挑戰讓我更深入地瞭解了 Twilio API 的使用方式,並學到了如何有效地閱讀相關文件和程式碼來解決問題。
結語
在本篇文章中,我們分享了我們在開發新產品過程中所面臨的挑戰和改進的過程。從疫情影響下平台使用量的增加,到改善前端視訊流程和技術選型,我們探討了如何有效地提升產品品質和開發效率。
這個過程中,我們遇到了許多問題,但同時也學到了很多。挑戰了版本升級以及優化。同時,這也是我首次把整個產品都翻新,引入 pre-commit check 工具,使得程式碼的品質得到了提升,並且增加跟優化大多數的功能。
在整個新產品的開發過程中,我們意識到全端經驗的重要性。我的背景使我能夠更好地理解整個系統的需求和架構,並能夠更好地協調前後端的開發工作。
同時,我們選擇了 Nx.js(Mono repo framework),然後 web 方面使用了 Next.js 框架搭配 TypeScript 配合 mui 和 emotion,這個技術組合也是我第一次挑戰的,而我大概花了兩個月的時間就逐漸上手了,也讓我應證我自己的學習能力。
而後我也成功地挑戰了 Twilio API 的串接,透過研究文檔和參考其他範例,我們學會了如何使用 Twilio 提供的通訊功能,並將其整合到我們的產品中。更是近一步讓我對自己更有信心。
最後,我們注重程式碼的可讀性和維護性。在 mono repo 的環境下,優先將程式碼拆分成專用檔案,像是專用的 hook、專用的 config,這提高程式碼的可讀性和易於維護。這種做法不僅增加了團隊成員之間的合作效率,還使未來的開發和維護更加順暢。
而我的全端經驗在這份工作中,也增加了不少,因為我們是小公司,所以我也會需要去看看後端的程式跟資料庫。這次的開發過程讓我們獲益良多,並提高了我的技術能力和團隊合作能力。