閒談軟體架構:友善的距離. 因為組織調整 - Medium

文章推薦指數: 80 %
投票人數:10人

軟體架構有很多pattern,坊間也有很多書探討,像是《Pattern-Oriented Software Architecutre》系列、《Software Architecture in Practice》、《Patterns of ... GetunlimitedaccessOpeninappHomeNotificationsListsStoriesWritePublishedin閒談軟體架構閒談軟體架構:友善的距離因為組織調整,我又變成architect了,早期對architect有很多憧憬,面對問題,心中總有一張設計圖,但實際當architect後,發現這是一個很不容易的職位,特別是要能說服別人使用某個設計或不用某個設計,另外,是在有時程壓力下,對一個有點歪的架構上,如何微妙地讓它保持像比薩斜塔般不至於垮掉,還能持續成長,又是另一個難題。

在讀《建構微服務》有段內容讓我玩味很久:我們借用其他行業的名稱,稱自己為softwareengineer或architect,但我們不是,對吧?architect與engineer的嚴謹性和紀律性是我們在現實中無法冀求的,而且他們對社會的重要性是眾所周知的。

記得有一次我和一位朋友聊天,就在他成為合格architect的前一天,他說:『明天,如果我在酒吧裡建議你如何建立某個軟體,而它是錯誤的,我就得承擔責任,我可能會被告,因為,我在法律上是一個合格的architect,如果我犯錯,就必須負責』怎樣才是稱職的軟體架構師呢?老實說,我恐怕還沒那資格說。

軟體架構有很多pattern,坊間也有很多書探討,像是《Pattern-OrientedSoftwareArchitecutre》系列、《SoftwareArchitectureinPractice》、《PatternsofEnterpriseApplicationArchitecture》,但當我們套了這些pattern時,我們真的該用嗎?用對了嗎?還是只有有個殼而已,內容根本不是那麼一回事呢?若深究每個pattern的形式,都會找到情境(context)、遭遇的問題(forces)和對應的平衡解(solution),但再仔細想想,這些解都圍繞在separationofconcerns上,將不同的問題分離,以合適的方式處理,因為我們總是希望有個highcohesion及loosecouping的系統,但在面對實際的設計抉擇時,有時反而會做出違背上述兩原則的選擇。

例如,為了不重新造輪子,我們使用第三方的函式庫,這聽起來很合理,但我們真的了解我們引入的函式庫嗎?我們對該函式庫的掌握度有多高呢?每個被引入的函式庫意味著一種coupling,不論是在Java上使用Maven或Gradle或是在ObjectiveC中使用CocoaPods,在編譯時,會看到這些套件管理工具幫我們下載眾多的第三方函式庫,這意味著我們不用重寫這些東西,開發效率能提升數倍甚至數百倍,但我們真的都能掌握這些coupling嗎?當這其中任何一個環節出錯,我們的系統架構真的很優雅地應付嗎?這是為什麼我蠻喜歡OnionArchitecture(洋蔥架構)和HexagonalArchitecture(六角架構)的原因了,在過去的專案中,我並沒有刻意使用這二個架構,畢竟我進去時,早已有龐大的程式碼基礎,不可能說改就改,只有在Android專案起始時,因為我是較資深的軟體工程師(那時還不是架構師),主導整個架構走向,即便如此,我也只堅持domain要與AndroidSDK分離,維持使用而不相依的關係,而這也造就了後來開發PC版時,有完整的domain核心可以直接使用不需修改,雖然這也不在當初的規劃就是了,但也省去了大量重複開發的時間。

當要離職準備交接時,回頭檢視架構,上述二個架構的影子就穿插在程式碼之間了。

可能跟過去在學校的OOAD訓練養成有關,從problemcontext和usecase中提取名詞,接著提取動詞找出關係與函式,然後利用GRASP逐步建構出整個domainmodel與designmodel,這中間,完全沒思考過UI(但如何與系統互動很重要)與框架,可能是這樣,我後來在做設計時,很自然地就與框架保持距離,不論是用C#寫WindowsForms還是用Java寫Webapplications。

但這其實並不容易,我剛開始工作時,看《HibernateinAction》時,有幾句話讓我印象深刻,第一句是:Weusetransparenttomeanacompleteseparationofconcernsbetweenthepersistentclassesofthedomainmodelandthepersistencelogicitself,wherethepersistentclassesareunawareof—andhavenodependencyto—thepersistencemechanism.其實,我畢業前就自學了JPA,之後才學Hibernate,上面那句話讓我開始思考,雖說JPA的annotation很方便,但不正是破壞了transparency嗎?但Hbernate也無法達到完全的transparent:Weregardtransparencyasrequired.Infact,transparentpersistenceshouldbeoneoftheprimarygoalsofanyORMsolution.However,noautomatedpersistencesolutioniscompletelytransparent:Everyautomatedpersistencelayer,includingHibernate,imposessomerequirementsonthepersistentclasses.因為再怎麼樣抽象化,資料庫對資料的描述與物件導向語言對物件的描述,存在著無法消除的paradigmmismatch(有興趣可以找書來看,《HibernateinAction》在第一章的第二節,花了整整一節說明這不匹配的情況),這讓我想起《約耳趣談軟體》第26章抽象滲漏法則中的一段:所有重大的抽象機制在某種程式上都是有漏洞的。

而且有時候這些框架或工具會反過來影響domainmodel的設計,舉例來說,從OO設計的角度來看關係,若要好維護,一般會以單向關係(unidirectionalreference)為主,但若要使用ORM或CoreData工具,為了確保工具能檢查資料完整性,會反過來在domainmodel上加上雙向關係(bidirectionalreference),但程式碼卻不見得需要去維護這雙向關係(部分是ORM工具處理),這導致讀程式碼時會有點奇怪。

另一個例子是,過去在學RDBMS時,會學到正規化(normalization)、主鍵(primarykey)、外來鍵(foreginkey)、索引(index)及一些RDBMS能在資料完整性幫上忙的工具,像是cascadedelete等東西,因此ORM工具也常把這些資訊滲漏出來,滲漏也許還好,但把物件關聯的維護轉交給ORM工具上(依賴cascadedelete刪除不該存在的關聯),就是值得討論的設計,到底這物件間關聯的維護是商業邏輯層的責任,還是資料儲存層的責任?如果哪天,資料儲存層換了,偏偏不支援原有的metadata(例如不支援JPA的annotation),那物件關聯的維護該怎麼處理?所以重點是如何取得平衡?以上述的ORM工具來說,極端的兩邊:完全不使用ORM工具和毫不顧忌的讓ORM工具散布在domainmodel中,又或者是將ORM的滲透透過其他方式控管在特定的範圍中,例如:再建立一層抽象(DAO或Repository),在實作中建立ORM所需的datamodel;又或者是使用污染性較低的方案,例如:以傳統的XML取代JPAannotation描述metadata,事實上,這沒有標準答案,每個軟體架構師的選擇都不同,上述二兩種折衷方案我都用過,也曾經完全不使用ORM工具,完全視情境而定,但原則到沒什麼不同,與框架及工具保持友善的距離,這同樣影響我之後在開發iOS時使用CoreData的方式。

或許是這樣,感覺自己比較像是old-school的軟體架構師,在選擇第三方函式庫或是框架時,相對比較保守,有時,還會為組織內部重新打造輪子,像是曾經在Android專案中復刻iOSSDK的NSNotificationCenter,事實上,在GitHub上可以找到類似的第三方函式庫,像是EventBus,但要不要採用一個第三方函式庫,除了該函式庫穩不穩定、文件夠不夠充足,還要看是否符合專案與組織的特性。

就專案來說,Android專案分成兩個子專案:一個是只有domainmodel的pureJava專案,另一個是實際AndroidUI的專案,若要導入EventBus,就只能在AndroidUI的專案中使用,因為domainmodel沒有相依EventBus所需的AndroidSDK,這樣並無法滿足當初想用NotificationCenter減少model與UI之間coupling的初衷;另外,考量到希望iOSdeveloper也能協助開發Android,所當時以決定自己動手寫,並且在進行在復刻時,API命名特意維持與NSNotificationCenter相似。

因此,軟體架構不是一旦決定了就穩固了,它需要後續開發時,時時想著當下這個設計是否會把架構搞歪了,架構需要細心的照顧,否則很容易歪掉,歪掉也許沒事,程式也可能還能繼續正常執行,但埋伏在裡面的技術債,何時會引爆則是未知,一旦反撲,對專案的影響不僅是時程,還有開發團隊對整體架構的信心。

系列索引下一篇:《閒談軟體架構:發生關係》29Morefrom閒談軟體架構一些軟體架構上的心得Readmorefrom閒談軟體架構GetstartedDuSpirit498FollowersFollowRelatedDomainDrivenDesign—SolvingtheproblemsforsolutionsAcompleteunderstandingofMicroservicesMicroserviceisanarchitecturalstylethatstructureanapplicationasacollectionofservices.Wecanseehowinthelastyearslotsof…WhatIwasdoingwrong — managingmicro-servicescommondependenciesDomaindrivendesigneCommerceInthepreviousarticleihaveexplainedwhatisDDDandwhyweneedtouseitDDD.HelpStatusWritersBlogCareersPrivacyTermsAboutKnowable



請為這篇文章評分?