Lời mở đầu
Tình cờ đọc bài viết Hype Driven Development làm mình nhớ lại hồi mới bắt đầu vào nghề, chạy theo công nghệ mới một cách mù quáng để rồi phải trả giá đắt bằng những đợt refactor/migrate kéo dài hàng tuần, thậm chí là hàng tháng trời.
Tuy là những trải nghiệm không vui nhưng đó đều là những bài học đắt giá team EGANY có được trong quá trình phát triển sản phẩm. Cũng nhân cơ hội này, mình quyết định "ra mắt" chuỗi bài viết kể về quá trình phát triển của những dự án frontend tại EGANY dưới góc nhìn của #1 Bug Contributor là mình. Tên chuỗi bài viết là Frontend Du Ký.
Mình sẽ chia mỗi dự án sẽ là một season (mùa, kí hiệu là S) bao gồm nhiều tập khác nhau (episode, kí hiệu là E). Ví dụ: S1E1 sẽ được hiểu là mùa 1, tập 1. Hi vọng chuỗi bài viết sẽ được sự đón nhận nồng nhiệt từ các bạn.
Mình sẽ bắt đầu mùa đầu tiên với EGANY Apps, một trong những sản phẩm đầu tiên mình tham gia tại EGANY.
Giới thiệu
EGANY Apps là dự án dashboard cho phép người dùng có thể cài đặt, nâng cấp cũng như thiết lập hầu hết các ứng dụng mà EGANY cung cấp trên các nền tảng thương mại điện tử (Haravan/Sapo).
Lúc dự án ra đời thì mình chưa vào công ty. Dựa vào thông tin từ git cũng như các tài liệu đi kèm thì tech stack khởi điểm lúc bấy giờ là bộ express application generator
mặc định: Express, Pug (HTML), Bootstrap Keen Themes (CSS) và JS.
Do lúc bấy giờ chỉ có 2 sản phẩm trên sàn điện tử nên team vẫn giữ nguyên kiến trúc monolithic (gộp chung frontend và backend). Tuy nhiên, sau một thời gian thực hiện thì team quyết định tách biệt frontend và backend để có thể dễ dàng phát triển cũng như giảm thiểu tỉ lệ "chết cùng lúc" của hệ thống.
Đây là thời điểm mình gia nhập công ty và cũng là khởi đầu của những chuỗi ngày đau đầu của team.
Lựa chọn tech stack
Để đảm bảo quá trình chuyển đổi được suôn sẻ, team đề ra một số yêu cầu cho thư viện/framework như sau:
- Hiệu năng tốt và ổn định
- Hỗ trợ SEO
- Hỗ trợ style bằng CSS hoặc SCSS càng tốt
- Dễ code
Một số thư viện/framework đáng cân nhắc bao gồm:
Create React App (CRA)
CRA có lẽ đã quá quen thuộc với team và đáp ứng được hầu hết các yêu cầu đưa ra. Tuy nhiên, một số điểm bất lợi mà CRA có:
- Client-Side Rendering nếu không biết cách optimize bundle sẽ rất chậm
- Phải cài thêm
react-helmet
để hỗ trợ SEO và cũng không đáp ứng được cho tất cả search engine lúc bấy giờ - Routing phải tự setup
- Bắt buộc eject nếu muốn "tự do" chỉnh sửa
Dù vậy, CRA vẫn được chọn làm công nghệ dự phòng trong trường hợp các thư viện/framework khác không thể đáp ứng đƯợc.
Gatsby
Gatsby lúc bấy giờ cũng còn khá mới. Tốc độ của Static Site Generator thật sự đáng gờm và gần như thống lĩnh thị trường trong giai đoạn đầu 2019 về hiệu năng. Tất nhiên, Gatsby vẫn có điểm yếu của riêng mình:
- GraphQL là một công nghệ tương đối lạ lẫm với team
- Tích hợp authentication khá phức tạp và không phù hợp với việc làm dashboard (theo góc nhìn của mình lúc đó)
- Tài liệu chưa tốt khiến việc tiếp cận gặp nhiều khó khăn
- Công nghệ còn khá trẻ, rủi ro cao nếu áp dụng vào production
React Boilerplate (RB)
Cũng như CRA, RB cũng là một dạng boilerplate (tạm dịch là sườn dự án) nhưng RB được tích hợp sẵn nhiều công nghệ cần thiết hơn cho dự án thực tế, ví dụ: react-router
, redux
, redux-saga
, react-helmet
, jest
, eslint
, … cùng nhiều tối ưu khác. Chính việc tích hợp này cũng là điểm trừ lớn của RB. Team bị "ngợp" khi phải tiếp cận quá nhiều công nghệ mới và điều này làm chậm quá trình chuyển đổi từ dự án cũ.
Vậy nhưng nói đi cũng phải nói lại, nếu team cần hầu hết các tính năng mà RB cung cấp và có đủ thời gian để tìm hiểu công nghệ thì RB không phải là một lựa chọn tồi để phát triển ứng dụng.
Next.js / NuxtJS
Do 2 framework tương đối giống nhau nên mình gom chung về một. Nhìn chung thì cả 2 đều đáp ứng tốt tất cả các yêu cầu team đưa ra. Điểm khác biệt duy nhất là thư viện frontend bên dưới. Next.js sử dụng React, một thư viện tương đối lâu đời và có cộng đồng developer lớn. Ngược lại, NuxtJS sử dụng Vue, một thư viện còn khá trẻ và chưa được nhiều công ty sử dụng trong production. Hơn nữa, do team cũng thiên về React hơn nên NuxtJS bị "bỏ qua" và Next.js trở thành công nghệ được chọn.
Ngoài việc đáp ứng được các yêu cầu team đặt ra ở trên, Next.js còn có các điểm mạnh như:
- Cho phép custom nhiều và sâu
- Tài liệu hoàn chỉnh, rõ ràng
- Dễ tiếp cận nếu đã có nền tảng React
Do kiểu gì cũng phải code lại toàn bộ (do code cũ sử dụng Pug + bootstrap) nên team quyết định sẽ dựng bộ component riêng bằng bộ CSS "homemade" (nhà làm) có sẵn trong quá trình phát triển các sản phẩm khác. Một công đôi việc phải không nào?
Bắt đầu thay đổi
Nguồn ảnh: https://dribbble.com/shots/2797795-Start-from-Scratch-Illustration
Sau khi lựa chọn được công nghệ sẽ sử dụng, team sẽ ngồi lại và cùng nhau thảo luận về các quy trình phát triển dự án để đạt hiệu quả cao nhất. Lý do tại sao lại có buổi thảo luận này? Một số lý do chính bao gồm:
- Dự án có thể xem lại "start from scratch", tức là làm lại từ đầu. Đây là một cơ hội tốt để khắc phục những thiếu sót có trong lần phát triển trước đó.
- Quy mô dự án lớn hơn trước. Với sự tham gia của nhiều thành viên hơn, đồng thời (sẽ có) nhiều tính năng hơn chắc chắn sẽ tạo ra nhiều sự thay đổi. Cần có một quy trình hoặc một "tiếng nói chung" giữa các thành viên để mọi thay đổi đều thống nhất và dễ dàng chuyển giao giữa các thành viên trong team.
- Thử sai. Là một trong những dự án lớn đầu tiên trong công ty, team cũng muốn thử nghiệm và áp dụng các phương pháp mới, các công nghệ mới để làm nền tảng cho những dự án sau này.
Cụ thể thay đổi ra sao, cùng nhau tìm hiểu nha!
1. Tài liệu
Tài liệu lúc bấy giờ trong team gần như không tồn tại. Có chăng chỉ là những tài liệu hướng dẫn dành cho khách hàng hoặc một vài cheat sheet dành cho dev. Nhận ra điều này, mình bắt đầu kêu gọi mọi người làm tài liệu cho chính những dự án đang làm.
Một số người cho rằng làm tài liệu rất mất thời gian và nếu dùng thời gian đó để phát triển tính năng thì hiệu quả hơn rất nhiều. Điều đó không sai, tuy nhiên họ vô tình quên đi mục đích của tài liệu. Dưới góc nhìn của EGANY, viết tài liệu là viết cho tương lai, cho những bạn mới bắt đầu hoặc cho chính các thành viên trong team khi vừa chinh chiến ở các dự án khác trở về. Đồng ý là viết tài liệu khá mất thời gian, chưa kể mỗi lần thay đổi tính năng lại phải cập nhật hoặc bổ sung thêm. Tuy nhiên, trên thực tế thì tài liệu giúp team khá nhiều:
- Tiết kiệm thời gian on-board. Thời gian on-board có nghĩa là thời gian bắt đầu tìm hiểu dự án. Hầu hết những điều cần biết về dự án đều đã có trong tài liệu nên các bạn mới tham gia sẽ dễ dàng nắm bắt dự án hơn. Việc trao đổi giữa các team cũng dễ dàng hơn nếu có tài liệu.
- Củng cố kiến thức. Việc viết tài liệu không hề dễ. Bạn sẽ phải dùng từ ngữ, hình ảnh hoặc thậm chí là video để mô tả tính năng, cách bạn triển khai chúng, tại sao bạn làm như vậy.. v.v… cho một người chưa biết gì về dự án. Điều này đòi hỏi bạn phải đào sâu, thu thập và nắm vững kiến thức để có thể giải thích cặn kẽ những điều bạn đã, đang hoặc sẽ làm. Không ít lần nhờ làm tài liệu mà mình học thêm được nhiều thứ mới và thậm chí tìm ra giải pháp hay hơn so với giải pháp hiện tại.
- Cơ sở đối chiếu. Trong suốt giai đoạn phát triển của dự án, chúng ta sẽ không tránh khỏi những buổi tranh luận, những thiếu sót hoặc những hiểu nhầm khi truyền đạt ý tưởng. Tài liệu chính là một dạng xác nhận những thứ chúng ta nghe, thấy hoặc tiếp thu là đúng, đủ và chính xác.
- Tăng giá trị dự án. Một dự án không có tài liệu thì dù hay và hữu ích tới mấy thì cũng khó lòng được người dùng (ở đây là developer) đón nhận. Bạn thử tưởng tượng React, Vue hoặc các thư viện/framework mà bạn đang sử dụng xóa toàn bộ tài liệu của họ. Để sử dụng chúng, bạn sẽ phải đọc và hiểu source code của thư viện/framework đó. Không dễ chút nào phải không nào?
Team quyết định sử dụng Markdown để viết tài liệu. Lý do team lựa chọn markdown mà không phải các định dạng khác vì:
- Đơn giản, dễ sử dụng
- Không yêu cầu cài đặt thêm phần mềm khác để đọc hoặc viết. Text editor có sẵn hoặc trình duyệt web (web browser) là đủ
- Khá thông dụng trên nhiều nền tảng, có thể convert thành HTML để hiển thị trên website
Ngoài ra, để giảm thời gian viết cũng như tạo điều kiện cho mọi người trong công ty thì mình có tạo ra nhiều mẫu tài liệu khác nhau, mỗi tài liệu sẽ phù hợp cho một mục đích khác nhau. Các bạn có thể tham khảo tại đây.
Git
Git thì không còn xa lạ gì với mọi người trong team nữa. Tuy nhiên, tính tới thời điểm lúc bấy giờ thì mọi người chưa có một quy trình git cụ thể quản lý version (phiên bản) của dự án. Từ commit message, branch, merge, cách tag version, … hầu hết là "ngẫu hứng". Sẽ không sao nếu quy mô dự án nhỏ, số lượng thành viên chỉ từ 1 tới 2 người. Tuy nhiên, quy mô dự án đã lớn hơn rất nhiều. Hơn nữa, nếu giữ mãi cách làm việc "ngẫu hứng" như vậy sẽ không tốt trong thời gian dài.
Để khắc phục điều này, team quyết định chọn theo mô hình git theo bài viết A successful Git branching model của Vincent Driessen. Tất nhiên, team sẽ có một chút thay đổi để phù hợp hơn với đặc thù công ty, cụ thể:
- Bổ sung nhánh
staging
để phục vụ quá trình test của tester. Nhánh này tương ứng với nhánhrelease
theo mô hình trên. Lý do xuất hiện nhánh này là để quá trình phát triển tính năng mới không bị "block" với các tính năng chưa được release đồng thời tăng tính ổn định cho môi trường test - Việc merge branch chỉ do một người phụ trách. Người này sẽ chịu trách nhiệm review code và làm việc với tester để đảm bảo mọi thứ ổn thỏa khi deploy lên môi trường
production
- Thay vì merge trực tiếp vào nhánh
develop
thì developer sẽ tạo pull request để đảm bảo rằng chỉ những tính năng chuẩn bị release mới được merge vào develop
Bên cạnh những thay đổi trên, team cũng tham khảo các dự án lớn khác để áp dụng thêm các quy định về commit message cũng như versioning (đánh tag phiên bản). Cụ thể:
- Commit message được thống nhất là sẽ sử dụng tiếng Anh, viết hoa đầu câu và luôn bắt đầu bằng động từ
- Đánh tag version sẽ tuân theo chuẩn SEMVER thay vì nâng theo kiểu tuyến tính như trước
Tất cả các thay đổi trên được áp dụng ngay sau buổi họp. Tuy nhiên, như ông bà ta có nói: Vạn sự khởi đầu nan. Team gặp khá nhiều khó khăn khi áp dụng:
- Không biết đặt commit message sao cho đúng do giới hạn về trình độ ngôn ngữ
- Tự ý merge nhánh tính năng vào develop mà không thông qua pull request
- Merge nhầm nhánh
- Khó khăn khi xác định version
Dù vậy, sau một thời gian làm quen thì team cũng bắt đầu thành thạo hơn và mọi thứ trở nên suôn sẻ hơn rất nhiều.
Custom React component
Nguồn ảnh: https://dribbble.com/shots/12531701-Design-system-elements
Như đã đề cập bên trên, team sử dụng Bootstrap Keen Theme cho hệ thống cũ. Tuy nhiên, để phát triển trong thời gian dài và dễ dàng đáp ứng các nhu cầu về nhận dạng thương hiệu thì team quyết định tạo ra bộ component riêng. Vì đã có sẵn bộ CSS riêng nên việc này sẽ không quá khó khăn về việc styling. Ít nhất đó là điều team nghĩ ban đầu.
Trên thực tế khi triển khai, ngoại trừ các thành phần cơ bản như header, footer, button, … thì các component khác tương đối khó sử dụng vì:
- Team chưa có kinh nghiệm
- Đặc thù dashboard khác nhau
- Scope dự án chưa rõ ràng
- Chưa có tài liệu cho component
Chính những nguyên nhân trên khiến việc phát triển dashboard thiết lập ứng dụng tương đối khó khăn. Team mất khá nhiều thời gian để áp dụng các component đã phát triển. Tính reusability (sử dụng lại) vẫn chưa cao, đôi lúc developer vẫn phải tự tạo custom component cho dashboard của riêng mình. Có thể nói đây là một lựa chọn không hợp lý cho thời điểm hiện tại. Dù vậy team vẫn cố gắng và cho ra đời nhiều phiên bản EGANY Apps trước khi quyết định thay thế chúng bằng một thư viện UI. Quyết định mãi sau này mới được đề xuất nên có lẽ mình sẽ trình bày ở một bài viết khác.
Tạm kết
Vì đây chỉ là giai đoạn khởi đầu, team chưa gặp nhiều khó khăn về mặt kỹ thuật. Những thay đổi đa phần tập trung vào quy trình hoặc những thứ liên quan đến toàn bộ hệ thống nói chung, cụ thể:
- Viết tài liệu
- Chuẩn hóa git flow
- Thống nhất cấu trúc ứng dụng
Khó khăn duy nhất lúc bấy giờ chắc có lẽ là việc tiếp cận công nghệ mới, làm quen với quy trình mới (chặt chẽ hơn). Lúc bấy giờ team vẫn chưa gặp phải những khó khăn về mặt kỹ thuật hoặc bắt gặp các lỗ hổng trong quy trình đã chọn. Có lẽ mình sẽ nói về chúng ở một bài viết khác.
Cám ơn các bạn đã đọc. Hẹn gặp lại các bạn ở bài viết tiếp theo trong series Frontend Du Ký. Happy hacking!