thuật ngữ IT cho Comtor. #4 – gitflow
tiếp theo bài trước.
chân thành cảm ơn thợ code TuanDA đã cho advices về các chi tiết technical và proof reading giúp
Trong các dự án phát triển phần mềm, source code (mã nguồn ソースコード) là một tài sản quan trọng và cần được quản lý. Trong bài này, ta sẽ cùng tìm hiểu các thuật ngữ có liên quan đến việc quản lý source code này (các thuật ngữ sẽ được bôi đậm)
Trong IT có một nguyên tắc gọi là Separation of Concerns (SoC 関心の分離), theo nguyên tắc này một hệ thống được chia thành các phần nhỏ độc lập, mỗi phần chịu trách nhiệm một mảng nhất định, do đó giảm thiểu sự phụ thuộc giữa các thành phần và giúp cải thiện tính bảo trì (maintainability 保守性) và tính mở rộng (extendability 拡張性) (nghe hơi tương đồng với nguyên tắc Chia để trị (divide and conquer 分割統治)).
I. Sự phân chia nơi chốn
Bất luận thế nào, ngày nay source code thường được chia ra quản lý ở những nơi chốn khác nhau và một Comtor. nên biết những thuật ngữ kỹ thuật liên quan
+ Hãy bắt đầu với một công cụ quan trọng đóng vai trò như một trung tâm lưu trữ/ quản lý source code (nói tắt thì là source) và cung cấp nhiều tính năng liên quan khác, đó là Gitlab (ギットラブ) hoặc Github (ギットバブ) (thể hiện ở khối giữa trong ảnh trên).
+ Phần trên của ảnh thể hiện các môi trường (environment) của dự án, thông thường một dự án sẽ có 3 môi trường tách biệt: Môi trường phát triển (Development env. 開発環境), Môi trường Kiểm thử (Staging env. ステージング環境) và Môi trường Sản xuất (Production env. 本番環境).
Về nguyên tắc,
Dev. env. chỉ dành cho đội phát triển (Dev. team 開発チーム) bao gồm các lập trình viên (programmer/ developer 開発者) hay còn gọi dân dã là coder (コード職人) để viết code và sửa lỗi, nó thường ít ổn định vì liên tục bị thay đổi.
Staging env. dùng cho cả team phát triển, tester và các stakeholder khác (những bên liên quan như là PO, Sales, trial User …. 利害関係者) kiểm thử ứng dụng trong một môi trường mô phỏng (simulation シミュレーション・疑似) gần giống với Production env.
Production env. là môi trường chính thức, nơi application được triển khai và sử dụng bởi người dùng cuối (end user エンドユーザ). Nó phải luôn hoạt động ổn định, liên tục và an toàn.
+ Phần dưới của ảnh thể hiện máy tính cá nhân của các programmer trong Dev. team. Thông thường các programmer sử dụng IDE (Integrated Development Environment 統合開発環境 môi trường phát triển tích hợp) để viết, chỉnh sửa, và gỡ lỗi (debug バグ潰し) mã nguồn trực tiếp trên PC cá nhân. IDE là công cụ (tool ツール) cục bộ phục vụ riêng cho từng cá nhân programmer trước khi đẩy source lên GitLab hoặc Github, Bitbucket …
II. Hoạt động qua lại giữa các nơi chốn ấy
Như đã giải thích, Gitlab/ Github có nhiệm vụ và chỉ tập trung vào nhiệm vụ quản lý source code, chỉ Dev. team mới có thể truy cập vào đây.
Trong khi đó, môi trường chính thức nơi ứng dụng (application) được triển khai (deploy 展開) lại là Production env. , nơi end user truy cập vào để sử dụng dịch vụ của application.
Ở đây, Comtor. cần hiểu mối quan hệ giữa source code và application.
Không có source thì không có application, thế nhưng:
+ Source code về cơ bản là các file text chứa các dòng text được tạo ra bởi programmer và con người (vd. programmer) có thể đọc hiểu được.
+ Application về cơ bản là các file có thể thực thi (executable 実行可能) bởi máy tính, được viết bằng ngôn ngữ máy (machine language マシン言語), chỉ máy mới hiểu chứ con người (kể cả các programmer thông thường) không thể hiểu được.
Vậy điều gì xẩy ra ở đây?
Trước khi đưa cho máy thực thi, source code cần được dịch từ các ngôn ngữ lập trình (programming language) ra ngôn ngữ máy. Thời trước, công đoạn “dịch” này được gọi là compilation (翻訳)/ interpretation (通訳), tuy nhiên ngày nay trên Gitlab/ Github công đoạn này nằm trong bước gọi là build (xây dựng ビルド), build bao gồm cả compilation cùng vài việc khác nữa.
Ở đây, programmer sử dụng công cụ tích hợp sẵn trên Gitlab/ Github để build source code thành một tập hợp các file executable, sau đó tiếp tục dùng công cụ trên Gitlab/ Github để deploy các file đó lên Dev env. (hoặc Staging env. …) theo cấu trúc/ trình tự nhất định và kết quả là tạo ra application trên environment mục tiêu. Các hoạt động build/deploy này được minh hoạ bằng các mũi tên trong hình vẽ phía trên.
Trước đây, việc build/ deploy như thế thường được tiến hành thủ công (manual 手動) trải qua nhiều bước và sử dụng nhiều câu lệnh (command コマンド) khác nhau. Hiện nay, CICD đã ra đời để tự động hoá (automate 自動化) quá trình đó và Gitlab/ Github cung cấp một nền tảng CICD (Continuous Integration/Continuous Deployment Tích hợp và triển khai liên tục 継続的インテグレーションと継続的デリバリー/デプロイメン) như vậy.
Nói nôm na thì CI/CD sẽ tự động hóa hai việc chính: build và deploy application. CI/CD giúp tự động test, tích hợp (integrate 統合) source và deploy application vào các môi trường Dev./ Staging/ Production một cách liên tục, từ đó giảm thiểu bug và tăng tốc độ phát triển phần mềm. Với Gitlab, CICD được định nghĩa trong các file .gitlab-ci.yml.
Lưu ý bản thân Gitlab/ Github… thì là các dịch vụ trên Cloud của một vài hãng global có tên tuổi chứ không thường thuộc sở hữu của Dev. team.
Trên Gitlab/ Github thì source được lưu trữ cũng trong các thư mục thôi, nhưng thuật ngữ gọi các thư mục chứa source như vậy là repository (リポジトリ) hay repo (リポ). Thường thì một dự án sẽ có nhiều repo và trong một repo lại chứa nhiều các “thư mục” con mà Gitlab/ Github (sau đây xin gọi chung là Git) gọi là branch (nhánh ブランチ).
Tạm bỏ qua repo, bài viết sẽ nói về các branch.
Về cơ bản, trong phát triển phần mềm, các nhánh (branch) thường là các bản sao chép (copy 複製) khác nhau của cùng một codebase (コードベース) nên chúng giống như các phiên bản (version バージョン/ 版)khác nhau của cùng một thứ (hãy nghĩ về các version của iOS hay Android các đời điện thoại bạn đã sử dụng).
Tương tự như việc một dự án có nhiều môi trường, cũng có nhiều branch khác nhau với các mục đích sử dụng khác nhau.
Trên lý thuyết, thường có các branch như sau:
- Master Branch: Đây thường là nhánh chính, ổn định và được triển khai lên Production env.
- Development Branch (dev branch): Là nhánh dùng để phát triển các tính năng (feature 機能) mới, tích hợp từ các feature branch.
- Feature Branches: Các nhánh này được tạo ra để phát triển một feature mới hoặc sửa chữa một bug (lỗi バグ・不具合・障害) cụ thể. Sau khi hoàn thành, chúng sẽ được hợp nhất (merge マージ・統合) vào dev branch.
Như thế, các nhánh feature chỉ chứa những thay đổi cục bộ, còn dev và master branch sẽ chứa tổng hợp thay đổi từ các feature branch.
Việc tổ chức source thành các branch giúp quản lý code hiệu quả, vừa đảm bảo tính ổn định (stability 安定性) của nhánh master, vừa tạo điều kiện cho các Dev. member có thể làm việc song song (parallel 並行・パラレル) trên các feature mới.
Có thể hình dung các branch không cố định mà như những thực thể sống, chúng tiến hoá, thay đổi, trao đổi source code với nhau thường xuyên. Vậy chúng làm điều đó thế nào, điều này xảy ra bên trong Git với Merge Request (MR) (hay còn gọi là Pull Request プルリク)
Xem xét hai branch master và dev chẳng hạn, đó là 2 version (source) khác nhau. Sự khác nhau (diff 差異) này thường nằm trên branch mới hơn, và sau khi Dev. team đảm bảo phần diff này – thường tương đương với một (vài) feature mới – sẽ nâng cao giá trị của application và là an toàn để đưa lên Production env. (release 本番化 – tức việc build nhánh master rồi deploy lên Production env.) , nó sẽ được phản ánh vào/ đưa vào branch master. Và Merge request chính là một yêu cầu phản ánh (merge) diff từ một branch vào một branch khác, mà trong trường hợp này là từ dev vào master.
Sau khi MR này được chấp thuận và thực thi, về cơ bản hai branch này sẽ trở nên giống hệt nhau, không còn sự khác biệt (diff) nào về source giữa 2 branch này nữa.
Như thế, bằng cách tạo và chấp thuận thực hiện MR trên Git, source code được trao đổi giữa các branch khác nhau. Thường thì Dev. member tạo MR và phê duyệt (approve 承認) MR là những người khác nhau.
III. Lịch sử tiến hoá của một branch luôn được đánh dấu và lưu trữ đầy đủ
MR ở phần trước là câu chuyện giữa các branch. Ở phần này ta đi sâu thêm một chút vào bản thân branch.
Về cơ bản ta có thể hình dung một branch như một tập hợp các “đoạn thay đổi” trên source code. Các thay đổi trên source do các programmer tạo ra liên tục, nhưng không phải chúng được phản ánh tức thời (real time リアルタイム) vào branch hiện tại.
Thường thì chỉ đến khi một đoạn thay đổi đủ tốt, đáp ứng đúng đặc tả (Spec 仕様) cùng các tiêu chuẩn (standard 標準) của team thì developer mới phản ánh chính thức đoạn đó vào branch. Việc “phản ánh chính thức đoạn thay đổi vào một branch” như thế gọi là commit (コミット).
Mỗi commit chứa toàn bộ nội dung source của branch tại thời điểm commit, bao gồm đoạn thay đổi chính thức mới nhất cùng với toàn bộ các đoạn thay đổi chính thức sẵn có trên branch.
Như vậy, một branch trong Git chứa một chuỗi các đoạn thay đổi theo thứ tự thời gian với toàn bộ lịch sử thay đổi được đánh dấu bởi bởi các commit.
Như ảnh minh hoạ ở trên thì commit 1 trỏ đến đoạn thay đổi A, commit 2 trỏ đến đoạn thay đổi A + B, commit 3 tương ứng với nội dung A + B + C ….
Trên Git, khái niệm commit tương đương với khái niệm snapshot (スナップショット). Mỗi commit trong Git đều là một snapshot hoàn chỉnh của một branch và liên kết với các commit trước đó.
Bây giờ, có một thực tế là không mọi commit đều quan trọng như nhau. Có những commit quan trọng hơn các commit khác. Thông thường, các commit tương ứng với bản phát hành (release version リリース版) mà được deploy lên Production env. là các commit quan trọng nhất.
Để đánh dấu một commit quan trọng trong lịch sử commit, người ta sử dụng “tag” (タグ ). Một tag trỏ đến một commit cụ thể trên một branch. Tag đơn thuần chỉ là sự đánh dấu một commit quan trọng.
Trong ví dụ dưới, giả sử đây đang là branch master và commit 3 tương ứng với release version 1.0, thế thì commit 3 được gắn tag là “v1.0”, trong khi các commit khác thì không có gắn tag.
IV. Giữa IDE và Git
Trong phần này ta đi đến các hoạt động tương tác giữa Git với PC của các programmer, cụ thể hơn là với IDE cài trên máy programmer.
Hình dung đơn giản nhất về câu chuyện đó là như sau:
Một programmer ở mức độ tối thiểu chỉ cần biết 3 hoạt động sau:
. Lấy hay kéo (pull プル) source từ Git về IDE trên local. Lúc này trên PC local của anh ta sẽ có các repo chứa source giống hệt như các repo trên Git. Chúng giống hệt nên chúng là những bản copy, tuy vậy chúng vẫn tách biệt nên repo trên local PC gọi là local repo (ローカルリポ), còn repo trên Git thì gọi là remote repo (リモートリポ)
. Tạo các thay đổi trên local repo và chính thức hoá chúng bằng cách commit (cũng trên local repo), hoặc có thể tạo hẳn branch mới trên local repo, sau đó
. Đẩy (push プッシュ) để phản ánh các commit mới hoặc branch mới từ local repo lên remote repo trên Git
Như thế, trên lý thuyết thì một developer có thể thay đổi code của một branch (ví dụ branch staging) và commit trực tiếp thay đổi ấy vào branch đó mà không cần dùng đến merge request (by pass luôn MR):
Ví dụ trong Git, developer có thể làm như sau:
- Chuyển sang branch
staging
bằng lệnhgit checkout staging
. - Thực hiện các thay đổi trực tiếp trên code.
- Commit các thay đổi đó bằng lệnh
git commit
. - Đẩy các commit lên remote repository bằng lệnh
git push
.
Với cách này, developer không cần tạo một MR mà thay vào đó có thể tự trực tiếp thực hiện các commit trên branch staging
.
Tuy nhiên, cách này có một số hạn chế:
- Không có sự review và kiểm tra của các thành viên khác trong team.
- Không có cơ chế kiểm soát để đảm bảo code mới không gây lỗi hoặc ảnh hưởng đến các features khác.
- Khó quản lý và theo dõi các thay đổi nếu không có merge request.
Vì thế, sử dụng merge request vẫn là cách tiếp cận tốt hơn để đảm bảo chất lượng code và sự hợp tác hiệu quả giữa các member trong team. Điều này dẫn ta đến với Gitflow. Tuy nhiên, trước đó hãy nhìn lại toàn bộ bức tranh một lần:
V. Khái quát về Gitflow từ góc độ developer
Để phòng tránh hạn chế của việc commit code trực tiếp vào các branch, đảm bảo kiểm tra của các member khác trong team cũng như hạn chế việc phát sinh bug, phát sinh degradation (ảnh hưởng không mong muốn đến các chức năng có trước デグレ), các developer thường được yêu cầu tuân thủ một quy trình nhất định khi làm việc với Git và CICD. Trong một tổ chức, quy trình đó có thể được gọi dưới cái tên: Gitflow and Environment.
Dưới đây là ví dụ một gitflow & env.:
- Copy branch main sang branch feature X bằng lệnh git checkout từ branch master (hoặc branch main, tuỳ quy định)
- Thực hiện các thay đổi trên branch feature X
- Commit các thay đổi đó trên feature X bằng lệnh git commit.
- Trong khi chưa merge feature X vào branch master, nếu master có bất kỳ thay đổi nào (có bất kỳ tính năng nào khác feature X được release hoặc có hot fix), phải merge từ branch master vào branch feature X bằng MR (bước này rất quan trọng, nhằm đảm bảo code của feature X luôn được đồng bộ và cập nhật với master)
- Đẩy các commit lên remote repository bằng lệnh git push
- Thực hiện kiểm thử (test 試験/テスト) trên local branch feature X
- Sau khi fix xong lỗi tìm thấy ở 6., push local branch feature X lên remote branch feature X bằng git push
- Merge branch feature X vào branch dev bằng MR
- Thực hiện test feature X trên branch dev theo bộ test case (テスト項目) cho Dev
- Sau khi fix xong lỗi tìm thấy ở 9. trên branch feature X, merge branch feature X vào lại branch dev
- Merge branch feature X vào branch staging bằng MR
- Thực hiện test feature X trên branch staging theo bộ test case cho staging
- Sau khi fix xong lỗi tìm thấy ở 12. trên branch feature X, merge branch feature X vào lại branch dev
- Merge branch feature X vào lại branch staging bằng MR
- Tạo tài liệu Release note (リリースノート) (và bộ test case cho Production nếu cần) để chuẩn bị release feature X (Với developer, Release note là một tài liệu mô tả chi tiết các bước cần làm để tiến hành công việc đẩy feature mới lên Prodution env., tài liệu này được tạo sau đó cần được approve từ các senior member trong team)
- Thực hiện release lên Production theo Release note: merge branch feature X vào branch master bằng MR
- Merge branch master ngược lại về các branch dev và staging bằng MR (sau khi release, lý tưởng là tất cả developer cần đồng bộ và cập nhật lại code với master nhằm phát hiện sớm, loại trừ sớm các code conflict (ソースコンフリクト) tiềm ẩn)
- Thực hiện các confirm/ test sau Release theo Release note (nếu có if any あれば)
Bạn đọc có thể tham khảo các bài trước trong cùng series: