軟件工程實踐之 Git 開發流

軟件工程實踐之 Git 開發流

軟件工程實踐系列文章, 會着重講述實際的工程項目中是如何協做開發軟件的。 本文主要介紹如何使用 Git 來支撐整個開發流。html

outline

本文包括如下內容:git

  • operation: 團隊保持一致的操做github

    • commit: 提交原子性的代碼
    • history: 保持線性乾淨的歷史
    • release: 遵循科學的發佈規範
  • tool chain: 搭建自洽的工具鏈web

    • gitlab/github: 使用現代的開發平臺
    • ci/cd: 讓系統把控代碼質量
    • sentry/k8s: 用版本鏈接整個系統
  • conclusiondocker

operation: 團隊保持一致的操做

Git 提供了一套自由而又強大的 api, 咱們能夠經過它以各類姿式來完成代碼協做。 但俗話說得好, 選擇越多人越懵。並無這句俗話 因此在團隊協做時, 保持一致的操做是很重要的。api

commit: 提交原子性的代碼

Git 的最小單元就是一個 commit。 咱們團隊遵循的最佳規範是保持每一個 commit 的原子性: 一個 commit 只作一件事情。markdown

好比一個關於缺陷修復的 commit 能夠很是簡單, 它只有兩行: 一行修復了代碼邏輯, 一行加了單元測試。框架

另外一個關於重構的 commit 可能會修改 200+ 個文件, 但也由於只作了一件事情, 因此不會給 code review 帶來很大負擔。工具

img

原子性的 commit 不只能很好地支持 revert/cherry-pick/bisect 等一系列 Git 的原生命令, 並且在保持線性乾淨的歷史這一點上, 也是相當重要的。oop

history: 保持線性乾淨的歷史

隨着時間的推移, Git 的每個 commit 會成長爲一個枝葉繁茂的歷史樹。 基於 fast forward 的合併能讓 Git 的歷史樹保持乾淨與線性。

img

這是咱們項目 git log 翻到四個月之前的一張截圖, 能夠看到歷史依舊是線性乾淨的。

線性的歷史意味着在每一個人提交代碼前須要 rebase。 一個例外是在發佈分支(master)上提交 hotfix 後, 合併回開發分支(dev)須要視狀況關閉 fast forward (–no-ff)。 並且要求你們 rebase 則對團隊成員的 Git 水平以及合併習慣提出了必定要求。

乾淨的歷史則須要你們都嚴格遵循 commit 的原子性, 以及要按照標準撰寫 commit message。 關於 commit message 的撰寫, 阮老師有一篇《commit message 編寫指南》講的夠好。 咱們也能夠在 git hook 中開啓對 commit message 的校驗, 以確保格式的整潔統一。

經過fast forward merge + 統一的 commit message, 咱們就能維護一個不斷成長、但又幹淨線性的歷史樹, 能最大程度地給各類 git 的版本操做提供便利。

release: 遵循科學的發佈規範

咱們使用 git tag 來做爲版本發佈的標誌。

img

由於咱們的項目是一個 web 服務端項目, 咱們同一時刻基本上只須要維護最新的版本, 因此咱們使用了日期型的版本號數字(v2019.9.9)。 在大部分開源工具裏, 都會使用語義化的版本號(semver: v2.0.0)

基於原子的 commit、線性的歷史, 在每次版本發佈時, 咱們都會自動化地生成 tag/changelog。

img

一個遵循了良好規範的 tag 能最大程度地利用工具鏈的集成功能, 給開發、測試、上線、監控提供完備的功能。

tool chain: 搭建自洽的工具鏈

在注重團隊協做、開發流程、發佈質量的軟件工程中, 會有一系列開發工具圍繞 Git 的代碼歷史樹, 提供了自洽的工具鏈。

gitlab/github: 使用現代的開發平臺

咱們使用 GitLab 來管理代碼項目, 其中重度使用的是 Merge Request 來做爲 code review 的載體。 不過咱們跟着 GitHub 的設定,管它叫 PR (Pull Request)

爲了維持 PR 的原子性, 大部分狀況咱們遵循單個 commit 對應單個 PR, 這樣既方便 review 也方便分支管理。 不過這樣的開發流會產生很是多的 PR, 須要團隊開發者都保持在一個更積極的開發狀態下。

現代的開發平臺還會集成更多工做流上的功能, 咱們還重度使用的是把 GitLab Runner 做爲咱們 ci/cd 的工具載體。

ci/cd: 讓系統把控代碼質量

img

在提完 PR 之後, 系統會自動化地啓用一系列的 Python/Django 檢查。

img

經過 git tag 發佈版本後, 系統會自動化地跑構建、灰度等一系列部署任務。

除了 GitLab Runner, 其它像 Jenkins/Travis CI/GitHub Actions 也能夠相似的 ci/cd 功能。

集成 ci/cd 能讓整個開發流變得更加柔順, 讓每個改動的影響均可以即時地經過數據展現出來。 ci/cd 加上 code review, 能最大程度地讓代碼庫保持活性, 長遠地能避免「往屎山上堆屎」的發生。

前面提到咱們的 PR/release 頻率都會比較高, 因此 ci/cd 也須要在更短的時間內跑完, 以免龜速檢測致使的各類心態爆炸、skip ci。 目前咱們項目平均能在 5min 內跑完包括 96% 覆蓋率的單元測試的多項檢查, 也能在 5min 內跑完從構建、灰度到全量的整個發佈流程。

整個 ci/cd 的流程其實也跟寫接口這樣的業務相似, 是須要不斷迭代、不斷優化、不斷適應更好的開發流的。

sentry/k8s: 用版本鏈接整個系統

在開發的流程走完之後, 軟件工程還關心發佈的流程、質量把控的流程。

咱們綁定了 docker image tag 與 git tag, 最終發佈部署在 k8s 上的每個版本也跟 git tag 的版本強關聯。 這樣的設定之下, 好比像 kubectl rollout 的一系列操做就會跟 Git 歷史樹關聯上。

img

> 咱們也使用了 sentry 來檢測管理代碼的線上問題。

全部的外部系統都使用着統一的 tag version 來關聯問題, 這樣咱們就給 debug, 歷史溯源,分鍋都提供了統一的工程語言。

conclusion

基於 Git 的開發流不是一個一成不變的框架, 它會由於項目特質、團隊成員習慣、工具鏈的不同而有着不一樣的表現形式。

咱們團隊在軟件工程的實踐中, 保持並維護着這麼一套開發標準:

  • 保持 commit 的原子性,一個 commit 只作一件事情。
  • 遵循編寫 commit message 的標準,而且會在 code review 時關注。
  • 統一團隊成員的操做習慣,使用 rebase + fast forward merge。
  • 自動化地生成 git tag 以及 changelog,並基於此作代碼發佈。
  • 搭建快速全面的 ci/cd 流程,自動化地作掉全部代碼檢查。
  • 使開發流與社區最佳實踐一致,瞭解並利用好各種工具的集成功能。

這套開發流也給咱們提出了這些挑戰:

  • 要對 Git 有必定了解,包括歷史樹操做等進階知識。
  • 除了編碼時,在協做時也要保持積極的態度,以及協做上的高標準。
  • 最重要的,對最佳實踐的追求,以及不懂就學的態度。

這樣的 Git 開發流,最終帶來了這些效果:

  • 線性的歷史讓 debug、追溯變動、瞭解項目發展過程都變得很是友好。
  • 項目一方面能保持快速活躍的開發效率,另外一方面能保證長期維護的質量。
  • 最佳實踐的討論以及迭代,讓團隊內部一直維持着很好的工程師文化。

軟件工程的實踐中, 好的 Git 開發流是不可或缺的一部分。 之後咱們再以不一樣的視角來分享更多軟件工程的實踐。

(完)


原文連接

相關文章
相關標籤/搜索