如何在團隊成功導入新方法?

大家可能都遇過公司想要導入一些技術或是方法來解決團隊的某些問題,不論是公司驅動或是內部成員發起,導入的過程通常會面對重重關卡,而且失敗的例子也是時有所聞,本篇文章是我在漸強實驗室工程團隊成功導入 Clean Architecture 與 DDD 的架構,改善程式碼品質與開發效率例子,從發現問題、尋找解法、導入技術、到成功執行解決問題的過程,在這個過程中我有蠻多學習的,寫成一篇文章來跟大家分享交流。

先打預防針:本篇文章不會提到技術相關的深入內容,主要在探討如何導入一個新技術方法的過程,有哪些步驟? 效果如何? 以及學習到的經驗!

起因

時間回到 2021 年初開始,公司的產品 MAAC (https://www.cresclab.com/)已經在台灣市場上站穩龍頭位置,但是快速成長的代價,免不了技術債的堆積,隨之而來的是越來越多 PM 想推出的功能,在 review 的過程中開始有因為技術債而需要被調整甚至是打槍的情況,團隊開發的速度也越來越慢,工程師們開始對估算開發時程缺少信心,當時這是一個走了兩年左右的專案,工程團隊普遍對於產品上日趨複雜的商業邏輯開發感到頭痛。

定義問題

產品上由於功能的開發與各種第三方串接甚至是客製化功能,商業邏輯越來越複雜,過去開發規範除了遵守開發者社群跟框架規範外,其餘的規範比較鬆散,主要透過 code review 來共識作法,在開發過程當中不乏許多嘗試性的需求,商業邏輯的堆疊越來越猖狂,各種程式碼片段東插西插,導致許多改動的單元測試變得難以撰寫,越大範圍的改動,受影響功能的評估變得難以估計(不知道大家有沒有遇過同樣的遭遇!?),面對技術債當然是每個團隊的課題,當時我的認為應該要有一個更適合的 codebase 開發管理架構,幫助大家有效的梳理商業邏輯,讓新的東西不要再重蹈覆徹,舊的東西也才有依據能夠有系統地還上債務,所以定義了兩個要解決的問題:

  1. Codebase 的管理架構要能夠支撐更大更複雜的擴張
  2. 如何有效地維護以及管理複雜的商業邏輯

如何解決

關於解決這兩件事情我開始有了一些研究,基於過去的一些知識概念,在軟體架構上我重看了一次 Clean Architecture,並且爬了很多軟體架構管理的文章,試著尋兩大問題該如何解決,在這個過程中我接觸到了 DDD(Domain Driven Design),最後我認為在原本的框架中,透過 Clean Architecture 分層的概念來重新架構 codebase,然後結合 DDD 的概念來對複雜的商業邏輯建模,應該是條正確的道路。

於是我從最熟悉且邏輯最複雜的後端服務開始嘗試,公司後端使用的技術棧主要是透過 python 的 Django + Celery 框架,我開始建立空白專案在本地環境嘗試,參考許多的網路文章,試著建立一個可相容現在專案且可擴展的分層架構,當時遇到最大的問題是 DDD,這對當時的我來說是軟體設計思維上的提升,學習花了我一陣子的時間,但當時我認為在沒有經驗的情況下,畢竟是個門檻較高的方法,整套 DDD 導入成功的機率應該是零,但裡面的一些思考模式跟概念還是很值得拿出來利用的,包含 Ubiquitous Language 的概念以及 Tactical Design 裡面的建模方式。

所以如何務實的,在框架上結合 Clean Architecture + DDD 的概念有效的解決問題,是我的研究重點,如何分層?要分幾層?如何收斂商業邏輯?Dependency Inversion 怎麼做?這非常有趣,是我的熱情之所在,決定之後開一篇文章專門講這個,本篇將著重在導入過程與學習。

有了初步的結論後就開始導入的旅程~

導入的過程

我把導入過程分成四個階段:

  1. 研究解決方法:
    如上述,3~4 月份的時候開始定義問題,且研究如何解決,重點在降低上手門檻,以及務實解決問題。
  2. 種下導入的種子:
    大概 4~5 月份的時候,我開始跟團隊部分成員討論導入這些概念的構想,並且給了整個團隊幾場相關知識概念的分享並附上簡單的 demo 來幫助理解,在這個過程中,可以跟已經知道這些概念的成員做知識上的對齊,也讓沒聽過這些知識的成員有一個初始的概念,這是我認為非常重要的一步,我認為導入這種偏重心法的東西,重點要讓團隊理解方法帶來的好處,比起給方法先照著做,有驅動力上的不同,會在最後面的經驗與學習上提到。
  3. 技術導入也需要的 MVP !:
    6~7 月份我開始對某一個後端的小專案,切了一個 branch,直接整個專案試著改寫成我想像的樣子,來當成實際情境上的 demo,並且寫了第一次的文檔跟大家討論如何運用這些概念,並且擴展實作到現在的專案上,同時跟部分有興趣的成員在大專案上的小功能上也嘗試使用;這個時期是碰撞最多火花的,也是導入成敗的關鍵,透過 MVP 的概念來搜集團隊的回饋,然後在我提出的架構上做初步的調整。
    這些調整非常重要,有提到務實的運用方法解決問題才是關鍵,所以在這個過程中,我會解釋我為何把架構這樣定,好處跟壞處是什麼,跟初期在小專案與小功能上實驗的經驗,同時集合大家的意見,根據大家過去開發上的經驗來討論,可能是我沒思考到的使用情境,也可能是大家認為還可以再簡化的做法,這是一個開始讓成員們體驗跟共識的過程,集合大家意見且在方法上做調整,可以讓這個架構更符合團隊的需求。
  4. 實行與迭代:
    8 月開始有累積一些使用心得與共識後,開始在後端專案上全面實行,並且持續對遇到沒定義好的狀況做討論跟解決,同時訂了一些重構上的方案,基本上新架構在同一坨 codebase 上是完全跟舊的 code 隔離的,所以當開發上遇到會影響到舊的 code 的時候,就將舊的 code 部分重構成新的設計,一開始實際執行的時候,因為有上手跟學習的成本,而影響一些開發進度,但大概在大家都執行過一次開發後,速度上基本就恢復正常。

結果與影響

結果:

  • 分層架構對測試的幫助非常顯著,新架構有九成左右的測試覆蓋率。
  • 在新架構上的開發,工程師們普遍覺得開發體驗上有所提升,不管是測試或是商業邏輯的組織,都有正面的回饋。
  • 遇到舊 code 的部分 refactor 成效不如想像好,主要是 refactor 的時間與開發時程上的取捨。
  • 架構設計最後寫成 guideline 放在 notion,讓新加入的人可以學習。
  • 從跑半年多左右回頭看有沒有解決當初定義的問題可能還太早,但是就目前來看,不論是擴展性跟商業邏輯的組織,現階段來看都有獲得解決。

影響:

  • 新加入的工程師需要花多一點力氣入門,直接影響新人上手開發的時間,需要再多花時間在這方面的知識上做同步。
  • 開始使用學習了之後,驅動大家接觸這方面的知識,團隊成員都會持續在這些方法上學習跟鑽研,有效的提升團隊軟體架構能力。
  • 前端也開始在小專案導入嘗試。

經驗與學習

經驗:

  • 當時是八人小團隊,且大家都有一定的開發經驗,溝通成本並沒有太高,再者當時向上負責的對象是 CEO ,但 CEO 並不管技術細節,沒有向上溝通的成本,這點是大家要注意的,因為向上溝通這件事情會直接影響導入新方法的成敗。
  • 導入的過程其實蠻冗長的,一方面是有原本的事情要做,一方面是規劃上有種下種子讓知識發酵的過程,就結果來看,因為知識發酵的過程,兩三個禮拜就會看得到,主要還是要調節原本開發的節奏,讓成員有時間心力來接觸新知跟理解,這點時間的規劃上並沒有做得很好,不能期待所有人都會在工作外的時間接觸這些東西。
  • 推行長期改善的計畫的勇氣,因為推行這種東西,在公司角度短期甚至是拖慢進度,而長期是否改善的量化指標其實也很難定義,所以某種角度上,我基本上是靠信仰之力在推動…,甚至也沒有在 report CEO 的 Team Lead meeting 上提到這件事情。
  • 還是有遇到一些阻力,新的方法的推動意味著開發習慣上的改變,可能是開發上要遵守的事情變多,或是寫 code 的習慣要重新調整等等,基本上這方面的阻力還是靠溝通,確保大家對遇到的問題有共識,並且對解決的方法有信心。

學習:

  • 會特別利用先種種子讓知識發酵是從我個人經驗得到的,因為我發現每當我學到新的技能知識的時候,會很想運用它(我發現大部分的工程師都有這種心態),但是如果是有人逼我做的話,我會下意識的有點排斥,所以在還沒有要正式導入之前,先用散播知識的方式,讓大家接觸這項東西,知道它的用處,不只對日後導入有減少排斥的幫助,還會讓團隊在先理解之後帶來更多知識上的碰撞,加大導入過程的回饋進而提高成功率。
  • 導入技術或是流程的時候,我都追求一個帶大家入門,然後可以因為好用跟有解決問題,讓團隊成員自動自發地把這些東西發展起來,幾次的經驗,我覺得重點首先放在要讓團隊理解這個技術跟流程到底在幹嘛,然後是讓團隊成員參與去做一些回饋跟決定,這樣可以提高成員的 ownership,同時保持彈性接收回饋持續調整跟優化,讓導入的東西是活的可變的,這樣大家才有心力去發展它。
  • 在導入不管是新技術或是方法的過程中,其實成敗都是在人,如何說服或驅動團隊成員來採納新的做法,主要還是要靠溝通,我的作法是會私下找有興趣的成員討論出一些初步的結論,來幫助你在團體討論會議的時候,有除了自己以外的成員,能夠主動的加入討論給建議,讓意願較低的成員可能感受一點同儕壓力 😅 ,會幫助大家更投入團體會議,進而得到大多數成員的回饋。

最後

導入的過程中,我從 Clean Architecture 書中截了兩段話,跟團隊成員分享,我覺得非常深刻,這邊也跟大家來分享:

The primary purpose of architecture is to support the life cycle of the system. Good architecture makes the system easy to understand, easy to develop, easy to maintain, and easy to deploy. The ultimate goal is to minimize the lifetime cost of the system and to maximize programmer productivity.

以及

Just remember: If architecture comes last, then the system will become ever more costly to develop, and eventually change will become practically impossible for part or all of the system. If that is allowed to happen, it means the software development team did not fight hard enough for what they knew was necessary.

身為開發者的你是不是也心有戚戚焉呢?

希望這個導入的分享對大家有幫助,也歡迎大家互相交流!

--

--