閒談軟體設計:Android App Architecture

更新於 發佈於 閱讀時間約 11 分鐘

前言

這是 2014 年的舊文,稍加重新整理一下,會想重新整理這一篇是因為從前同事那裡聽到一些外包的趣事,所以把當初設計的思維和想法分享出來。當初開發的 App 已經上線了,不方便透漏太多設計的細節,文中介紹的是屬於泛用的的架構,適合大多數的 App,實作的細節則是隨專案的特性變化。

Model/View 分離

2013 年以 Android 工程師的身份進入水果公司,但就像是在遊戲中轉職一樣,沒多久就變成 iOS 工程師,在這之前,都在設計相同 App 的 Android 版的軟體架構,需要考慮的事情其實蠻多的,只是後來開始開發 iOS 版本後 (Android 版本暫緩),這些設計和想法就暫時放在腦中也沒機會整理下來。

設計時的考量主要有:(1) App 是 Internet App,在考量 UI 體驗和網路頻寬的消耗,多數資料需以某種形式 (例如:SQLite 或檔案) 儲存部分資料在行動裝置上;(2) 因此,會需要同步伺服器端和行動裝置端之間資料狀態;(3) 但行動裝置網路的穩定性不如一般網路可靠 (4G 也沒有比較好),要有足夠的自動化測試驗證正常的流程與異常的流程。

2014 年中,偶然的機會招募到數位 Android 工程師,於是 Android 版本準備開始復工,趁一些瑣碎的空檔時間,把當初想的結構給整理一下,個人對 Model 與 View 分離這件事十分堅持,讓自動化測試能夠極大化,所以基本的架構概念圖大概就如 Figure 1 所示。

raw-image

Platform-independent Model

架構圖主要分成幾個區塊,綠色是 Model 的部分,所有的商業邏輯都集中在此,這個部分原則上盡可能是 platform-independent 的設計,因此以 Java SE 和 Android SDK 交集的 API 完成,在自動化測試時,完全不需要 Android 模擬器,用一般 JUnit 即可,希望用最少時間達到最大的測試涵蓋率,過去曾經統計過,核心功能部分的程式碼約是二萬八千多行,由三萬二千多行的測試程式,約一千五百個測試案例驗證功能的正確性,全部測時能在 40 秒內完成,測試涵蓋率在 95% 以上。

這邊要特別強調的是 Model,對於習慣只把資料結構當成 Model 的人來說,商業邏輯可能四散在 View、Controller (這裡的 Controller 指的是 MVC 中的 Controller) 或 Activity 中,但資料結構只是 Model 的一部分,也就是圖中 Domain Data Model 那一塊,維護資料結構物件關係的邏輯,如何回應 Use case 或 user story 所定義的系統事件 (system event),這些處理系統事件的 main controller 都屬於 Model,也就是圖中 Business Logic Managers,責任是透過 Web Service Interfaces 和伺服器溝通,然後維護資料結構物件間的關係,最後透過 DAO Interfaces 將狀態保存到行動裝置中。

Platform-dependent adapters

橘色是 platform-dependent 的實作,例如用 Android 的 SQLite API 來實作DAO,然後以 Setter Injection 或 Interface Injection 的方式,將 platform-dependent 的實作注入,為了做到這點,綠色區塊不能直接依賴 platform-dependent 的實作,因此 Web Service Interfaces 和 DAO Interfaces 兩個區塊只定義介面沒有實作,由橘色區塊中的 Web Service Implementation 和 DAO Implementation 分別實作這兩個介面,藉此將依賴關係反轉 (Dependency inversion),因此也容易把 Web Service Interfaces 和 DAO Interfaces 的 mock object 給注入,方便測試。

橘色區塊還有一個責任是扮演 Android Service 的角色,Android 能讓 App 以 Service 的方式在背景執行,以需要頻繁更新狀態的 App 類型來說,能有在背景執行的 Service 非常有用。當 Activity 被喚起,只需 bind service 就能取得所有最新的狀態。不過,設計不好,Service 是非常耗電的,若能以 GCM 喚起 App 進行單次的網路存取,也是一種用來更新狀態的一種方式,不一定得用 Service。此外,Service 與 Activity 共用同一個 thread,不能讓 Service 的初始化佔用太多時間,否則 App 啟動時,UI 會卡住無法動彈,以額外的 thread 進行初始化需要注意 multi-thread 引起的問題。

DAO Implementation 是 platform-dependent 的,所以用橘色標示沒什麼大問題,但 Web Service Implementation 卻是被標示為紫色,主要是因為以 JSON 格式傳遞資料的 Restful Web Services,是有機會只用以 Java SE 和 Android SDK 交集的 API (像是HttpURLConnection),或是是用 OkHttp,搭配 Android 上也能使用的 JSON Library (Gson 或 Jackson)來完成,也就是 Web Service Implementation 不一定是 platform-dependent 的實作,有機會能用 JUnit 來測試。

Views

淺灰色區塊即 View,主要是圖中 Android Activities & UI Flow Controls 區塊,這部分也能自動化測試,但需要 Android 模擬器或是使用實機,測試時間也較長,但 App 好不好用,這塊佔了很大的因素。此外,綠色區塊和橘色區塊的 API 會以 synchronous 的方式設計,為了不卡住 UI,Android SDK 本身有一些 Asynchronous 的輔助類別(例如AsyncTask),但我覺得還不夠好用,所以Asynchronous Supports & UI Components 會根據 App 的體驗需求客製化一些輔助類別,另外提供一些特殊的 UI 元件。

此外,Android 不允許非在 UI Thread 執行中的程式可以變更畫面,所以 Asynchronous Supports & UI Components 這區塊還要負責將不同 Thread 回來的更新通知轉到 UI Thread中。這個區塊以藍色標示,主要是因為這些元件應該設計成能跨專案共用的,當成是公司的資產,在開發新專案時就能夠使用才是長久之計。

大原則是這樣沒錯,不過準備開發的 App 會整合一個第三方的遊戲引擎,到時架構可能會有些許調整,例如在 Domain Model 或 Android Service 中多一些 Interface 與遊戲引擎的部分溝通,盡可能保護 Domain Model。最後,為了不讓不同層級的物件相互汙染,應該會用 Maven (或 Gradle) 的 module 機制將不同層級的物件歸屬到不同的 module 中,再利用 dependency 的方式限制 module 之間的可見度。希望 Android 版在需求相對明確 (已有iOS版) 的情況下,開發能夠順利些。

優缺點

最小交集

離開這專案後再回來想這個架構的優缺點,首先,為了讓自動化測試能不依賴 Android 模擬器,以 Java SE 和 Android SDK 交集的 API 完成有個缺點,要等到 Android SDK 正式支援 Java 8,才能在 Model 中開始使用 Java 8 的新特性 (像是 Lambda),不過,從 Android N 開始,已經開始支援大多數 Java 8 的特性,這缺點就沒這麼嚴重了。

跨平台共用

當初腦中確實有想過讓這 App 的核心能跨足到 PC 版,但跨平台不是最主要的考量,讓團隊成員能習慣從 domain 開始寫程式,才是這架構中 Model 與 UI 分開最主要的原因,不過後來真的開發 PC 版了,核心數萬行的程式不需重寫,想像一下,核心就像下圖中綠色的拼圖,無法單獨使用,需要其他的拼圖才能組成一個完整的 App,開發 PC 版時,則是提供藍色的拼圖整合核心的部分成為另外一個可以在 Mac 與 Windows 上執行的程式。

raw-image

相依性管理

在跨平台時有一點要注意,這也是當初沒有做好的部分,當初為了開發方便,Android 相關的程式與核心的部分是同一個專案的二個模組,不像是引入第三方套件的方式引入核心到 Android 專案中,PC 版也是以 link 的方式直接將原始碼引入,但一旦核心被二個專案以原始碼形式引用時,任何一邊對核心的介面做了修改,都會導致另一邊編譯失敗,較理想的方式,應該是將核心的部分獨立出去,任何修改後建置成一個 JAR 檔並加上版本布署到內部的 repository 中,Android 與 PC 版的專案以第三方套件的方式引入,這樣便能夠以管理第三方套件版本的方式,讓雙方隨時有相容的介面可以編譯。

快速測試

從剛剛提到的統計資料可以看出來,測試程式碼與功能程式碼之間的比例約是 1.14 : 1,這同時也代表寫測試程式所花的時間幾乎和寫功能是一樣的,甚至更多,但這投資是值得的,若要以人力的方式測試二萬八千多行的功能,絕對是不可能在 40 秒內完成的,但一千五百多個測試案例卻是在每次有人簽入程式時都執行過一遍,只要 40 秒就能知道核心功能有沒有被改壞,是否安心許多呢?

最後,這設計可能的缺點之一是對於 Model 與 UI 分離這概念不熟,或是對 OO 設計不熟的人來說,有點難以上手...

留言
avatar-img
留言分享你的想法!
avatar-img
Spirit的沙龍
55會員
107內容數
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
Spirit的沙龍的其他內容
2024/03/23
這篇文章探討了在軟體開發中的技術債可能來自哪些原因,以及如何自動化偵測與修復技術債。作者透過分享不同情境下的技術債選擇,提供了對於技術債的思考與建議,針對開發人員在需要做出無奈的技術決策時,提供了一些建議。此外,還提供了一些在做出技術決策時的方法,如保留抽象層和避免vendor lock-in。
Thumbnail
2024/03/23
這篇文章探討了在軟體開發中的技術債可能來自哪些原因,以及如何自動化偵測與修復技術債。作者透過分享不同情境下的技術債選擇,提供了對於技術債的思考與建議,針對開發人員在需要做出無奈的技術決策時,提供了一些建議。此外,還提供了一些在做出技術決策時的方法,如保留抽象層和避免vendor lock-in。
Thumbnail
2024/03/09
今天來聊個最近很夯的主題 DDD,但不是 DDD 的本尊 Domain Driven Design,而是無所不在的 Database Driven Design,Database Driven Design 不是不好,只是你的模型容易變成貧血模型,邏輯都集中在 service 層等等。
Thumbnail
2024/03/09
今天來聊個最近很夯的主題 DDD,但不是 DDD 的本尊 Domain Driven Design,而是無所不在的 Database Driven Design,Database Driven Design 不是不好,只是你的模型容易變成貧血模型,邏輯都集中在 service 層等等。
Thumbnail
2024/03/02
有趣的是,Model 其實沒什麼嚴格的定義,所以每個人對 Model 的解讀也不盡相同,有人覺得資料怎麼儲存屬於 Model 的一部份 (受 ORM 工具的影響),有人覺得工作流程 (workflow) 是 Model 的一部份,我個人也有自己的想法,而且隨專案的規模和特性,也不是總是一樣的。
Thumbnail
2024/03/02
有趣的是,Model 其實沒什麼嚴格的定義,所以每個人對 Model 的解讀也不盡相同,有人覺得資料怎麼儲存屬於 Model 的一部份 (受 ORM 工具的影響),有人覺得工作流程 (workflow) 是 Model 的一部份,我個人也有自己的想法,而且隨專案的規模和特性,也不是總是一樣的。
Thumbnail
看更多
你可能也想看
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
Android 應用程式開發的50 個提示 Android程式碼審查與優化: 程式碼審查建議:“建議對此程式碼片段進行改進:[此處的程式碼片段]。” 性能優化:“建議優化此程式碼性能的方法:[此處的程式碼片段]。” 程式碼重構建議:“推薦重構此程式碼的最佳實踐:[此處的程式碼片段]。”
Thumbnail
Android 應用程式開發的50 個提示 Android程式碼審查與優化: 程式碼審查建議:“建議對此程式碼片段進行改進:[此處的程式碼片段]。” 性能優化:“建議優化此程式碼性能的方法:[此處的程式碼片段]。” 程式碼重構建議:“推薦重構此程式碼的最佳實踐:[此處的程式碼片段]。”
Thumbnail
不管用哪種語言開發軟體,除非是那種一個 function 寫個幾萬行的人 (來人啊,把這種人拖去砍了),不然,一般都會根據某些因素,切割成模組或是特定功能的區塊 (一個 class 或是一個 function),但要完成一個特定功能,這些模組或區塊勢必要一起合作,因此這些模組與區塊就發生了關係。
Thumbnail
不管用哪種語言開發軟體,除非是那種一個 function 寫個幾萬行的人 (來人啊,把這種人拖去砍了),不然,一般都會根據某些因素,切割成模組或是特定功能的區塊 (一個 class 或是一個 function),但要完成一個特定功能,這些模組或區塊勢必要一起合作,因此這些模組與區塊就發生了關係。
Thumbnail
在軟體開發領域,MVC(Model-View-Controller)是一種被廣泛使用的設計模式,它有助於將應用程序的不同部分進行組織、分離,以實現更好的可維護性和可擴展性。本文將深入介紹MVC模式的核心概念,以及如何在您的項目中應用這種強大的架構。
Thumbnail
在軟體開發領域,MVC(Model-View-Controller)是一種被廣泛使用的設計模式,它有助於將應用程序的不同部分進行組織、分離,以實現更好的可維護性和可擴展性。本文將深入介紹MVC模式的核心概念,以及如何在您的項目中應用這種強大的架構。
Thumbnail
每次看到 REST 就讓我想起以前念研究所和老師一起想論文題目時,曾提過國外常會玩這種文字遊戲,像是將 Representational State Transfer 變成一個很簡單的單字 REST,但我的東西不管怎麼想,卻想不出什麼有趣的東西 Orz
Thumbnail
每次看到 REST 就讓我想起以前念研究所和老師一起想論文題目時,曾提過國外常會玩這種文字遊戲,像是將 Representational State Transfer 變成一個很簡單的單字 REST,但我的東西不管怎麼想,卻想不出什麼有趣的東西 Orz
Thumbnail
設計時的考量主要有:(1) App 是 Internet App,在考量 UI 體驗和網路頻寬的消耗,多數資料需以某種形式儲存部分資料在行動裝置上;(2) 因此會需要同步伺服器端和行動裝置端之間資料狀態;(3) 但行動裝置網路的穩定性不如一般網路可靠,要有足夠的自動化測試驗證正常的流程與異常的流程。
Thumbnail
設計時的考量主要有:(1) App 是 Internet App,在考量 UI 體驗和網路頻寬的消耗,多數資料需以某種形式儲存部分資料在行動裝置上;(2) 因此會需要同步伺服器端和行動裝置端之間資料狀態;(3) 但行動裝置網路的穩定性不如一般網路可靠,要有足夠的自動化測試驗證正常的流程與異常的流程。
Thumbnail
程式開發有趣的地方,同樣的目標,不同的團隊會因不同的因素做出不同的設計抉擇。而這往往也是為什麼一個資深的工程師在開發速度上不一定比較快的原因之一,一個越是資深的工程師,思考的因素會更多,不過,不是考慮得越多就結果就一定越好,有時還會變成 over design 較糟的結果。
Thumbnail
程式開發有趣的地方,同樣的目標,不同的團隊會因不同的因素做出不同的設計抉擇。而這往往也是為什麼一個資深的工程師在開發速度上不一定比較快的原因之一,一個越是資深的工程師,思考的因素會更多,不過,不是考慮得越多就結果就一定越好,有時還會變成 over design 較糟的結果。
Thumbnail
相信有在開發Web應用的朋友應該對於Postman這套工具相當熟悉, 這套工具可以協助我們在產品尚未完成之前可以先進行一些基本的介接測試,甚至我們可以使用Postman去呼叫雲端的API,像是Google的語音辨識、文字翻譯、字典查詢…,這類大廠相信也都開放許多標準API(Application P
Thumbnail
相信有在開發Web應用的朋友應該對於Postman這套工具相當熟悉, 這套工具可以協助我們在產品尚未完成之前可以先進行一些基本的介接測試,甚至我們可以使用Postman去呼叫雲端的API,像是Google的語音辨識、文字翻譯、字典查詢…,這類大廠相信也都開放許多標準API(Application P
Thumbnail
在開發產品過程中,不難發現研發和設計團隊時常因各自所處的角度不同,使得在溝通來回上花了不少時間。所以小弟整理些過去常在工作場景下遇到的一些資訊技術的專有名詞,化解那些雞同鴨講的無效溝通。
Thumbnail
在開發產品過程中,不難發現研發和設計團隊時常因各自所處的角度不同,使得在溝通來回上花了不少時間。所以小弟整理些過去常在工作場景下遇到的一些資訊技術的專有名詞,化解那些雞同鴨講的無效溝通。
Thumbnail
這次錯誤在Android 11 發生 去年12月底 , 有客戶反應 , 在 android 11 的手機 , 公司 app 開不起來 或開起來跑很久 , 空白頁..........登入畫面空白 之類奇怪的問題 一開始用 Android studio 的模擬器試 , 沒問題 看來需要實機了 於是就開始
Thumbnail
這次錯誤在Android 11 發生 去年12月底 , 有客戶反應 , 在 android 11 的手機 , 公司 app 開不起來 或開起來跑很久 , 空白頁..........登入畫面空白 之類奇怪的問題 一開始用 Android studio 的模擬器試 , 沒問題 看來需要實機了 於是就開始
Thumbnail
Laravel本身是MVC架構的Framework,但隨著專案越來越龐大,若不把系統架構分工再切細一點,可能會導致日後維護的困難。 例如可能會很常發生controller要與model溝通拿資料,又要處理商業邏輯,就會導致controller越來越肥,因此本文要介紹的是....
Thumbnail
Laravel本身是MVC架構的Framework,但隨著專案越來越龐大,若不把系統架構分工再切細一點,可能會導致日後維護的困難。 例如可能會很常發生controller要與model溝通拿資料,又要處理商業邏輯,就會導致controller越來越肥,因此本文要介紹的是....
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News