Như đã nói ở phần một, Frontend Du Ký S1E2 | EGANY Apps sẽ kể về những lỗ hổng trong quy trình làm việc cũng như những vướng mắc về kỹ thuật mà team gặp phải trong quá trình phát triển EGANY Apps.
Nếu bạn chưa đọc phần một, bạn có thể đọc trước tại đây.
Sau khi thống nhất được quy trình làm việc cũng như công nghệ để thực hiện dự án, team bắt đầu quá trình phát triển.
Kế hoạch lúc bấy giờ bao gồm:
Đây là lúc các vấn đề bắt đầu xuất hiện. Để dễ dàng hơn cho các bạn thì mình sẽ chia các vấn đề thành hai nhóm chính, cụ thể:
Cùng bắt đầu tìm hiểu nha!
Trong bài viết mình sẽ gọi bên đối tác e-commerce (bao gồm Haravan và Sapo) là platform để tránh việc lặp lại tên của các nền tảng đó.
EGANY Apps không có một hệ thống xác thực hoàn chỉnh. EGANY chỉ đóng vai trò là trung gian cho phía platform. Flow xác thực sẽ như hình sau:
Một số bạn có thể thắc mắc là vì sao phía backend không gửi trực tiếp token về phía EGANY Apps luôn mà phải tạo ra một token trung gian. Lý do như sau:
Xong vấn đề về flow thì team gặp tiếp vấn đề về lưu trữ token. Mỗi ứng dụng sẽ có một token riêng và khách có thể đăng nhập một hoặc nhiều ứng dụng cùng một lúc. Hơn nữa, do EGANY Apps hỗ trợ nhiều platform nên khách có thể đăng nhập một ứng dụng trên nhiều platform khác nhau. Phức tạp phải không nào? Sau khi thảo luận và bàn bạc thì team chốt đơn như sau:
Team lựa chọn lưu trữ token dưới dạng Array
. Đây không phải là một sự lựa chọn hợp lý vì token thường được truy cập dưới dạng key
nên hiệu năng sẽ không tốt. Ví dụ:
// Array
const token = tokenArr.find(isCurrentAuthSession)
// => Về lý thuyết là O(n)
// Map
const tokenKey = getCurrentAuthSessionKey()
const token = tokenMap.get(tokenKey)
// => Về lý thuyết là O(1)
Tất nhiên, về lý thuyết là như vậy nhưng trên thực tế thì sẽ không nhận ra được ảnh hưởng rõ rệt do số lượng phần tử (ở đây là phiên đăng nhập của người dùng) khá là thấp. Dù vậy thì ở những phiên bản sau này, team vẫn quyết định thay thế Array
bằng Map
để tiện cho việc truy xuất.
Sau khi xác thực người dùng thành công, hầu hết các ứng dụng đều lưu trữ lại thông tin xác thực để sử dụng trong suốt thời gian ứng dụng hoạt động. EGANY Apps cũng không phải là ngoại lệ.
Để giải quyết bài toán này thì team có hai lựa chọn lúc bấy giờ:
Sau khi tham khảo một số nguồn trên mạng và trải nghiệm thử thì team quyết định chọn MobX. Lý do:
Dù vậy MobX vẫn còn một số hạn chế sau:
toJS()
để in dữ liệu do dữ liệu được lưu ở dạng Observable
Ngoài những khó khăn trên thì team khá hài lòng với giải pháp ở thời điểm hiện tại.
Sau khi có khung sườn xác thực người dùng cũng như móc nối thông tin vào global state thì team bắt tay vào phát triển giao diện dashboard.
Nếu các bạn chưa biết thì Next.js sử dụng file-based routing, nghĩa là đường dẫn file sẽ tương ứng với đường dẫn trang. Ví dụ:
pages/products/index.jsx
/products
hoặc
pages/products/productId.jsx
/products/productId
Có lẽ các bạn cũng nhận ra vấn đề ở đây rồi phải không? Trong thực tế sẽ xuất hiện vô số productId
và nếu phải tạo từng file cho mỗi trang chi tiết sản phẩm theo id
thì.. gần như không thể, đúng không nào?
Đó là vấn đề mà dynamic route (hay còn gọi là dynamic url) giải quyết. Nó sẽ tự động truyền productId
vào một trang (template) phù hợp và trả về HTML tương ứng.
Tiếc thay, ở thời điểm này, Next.js v7 chưa hỗ trợ sẵn mà buộc lòng team phải custom để xử lý. Cụ thể là sử dụng express
để quản lý Server-side Rendering cho Next.js. Một đoạn code mẫu cho dynamic route sẽ như sau:
server.get('/products/:id', (req, res) => {
const pageTemplate = '/products/id'
const productId = req.params.id
app.render(req, res, pageTemplate, { id: productId })
})
Tuy nhiên, khi chạy với custom server như trên thì sẽ mất đi tính năng hot-reload
(một dạng auto reload nhưng giữ lại state
hiện tại của ứng dụng), khiến cho trải nghiệm khi code giảm đi đáng kể, đặc biệt là khi làm việc với form hoặc modal.
Như đã đề cập ở phần 1 thì team đã quyết định dựng bộ component riêng dựa trên nền tảng CSS đã có từ các sản phẩm trước đó.
Do chưa có kinh nghiệm nhiều nên việc phân tách component cũng gặp tương đối khó khăn. Đáng lưu ý nhất có lẽ là việc tích hợp các thư viện bên ngoài, đặc biệt là thư viện rich-text editor.
Các thư viện rich-text editor đa số đều sử dụng object window
trong source code của mình. Ngặt nỗi khi render lần đầu tiên thì trang lại được chạy ở server, làm gì có object window
mà dùng. Ấy vậy là team lại phải làm đủ trò để page có thể được render thành công trên server.
Chưa hết, ngoài rich-text editor thì team còn phải optimize color-picker. Khi người dùng chọn màu, event onChange
sẽ được gọi rất nhiều lần. Nếu quản lý không khéo sẽ tạo ra hiện tượng giật/khựng UI rất khó chịu. Team chủ động áp dụng các thủ thuật debounce (một dạng delay function) để cải thiện hiệu năng cho component này
Khó khăn cuối cùng có lẽ là tạo dockerfile để triển khai ứng dụng.
Do cũng chưa có nhiều kinh nghiệm về mảng này nên lỗi cũng tương đối nhiều. Nổi bật nhất có lẽ là lệnh npm install --production
Nếu bạn chưa biết, --production
flag (cờ) sẽ loại bỏ toàn bộ package nằm trong devDependencies
và chỉ cài đặt các package có trong dependencies
. Về lý thuyết thì nó sẽ giảm thời gian deploy vì số lượng package sẽ giảm đi đáng kể. Trong thực tế, một số package ở devDependencies
lại cần thiết để build được project, đơn cử như node-sass
để compile file .scss
Nếu nhớ không nhầm thì team mất khoảng một buổi chiều chỉ để tạo và triển khai thành công ứng dụng bằng docker.
Nguồn ảnh: https://dribbble.com/shots/9707966-Web-Site-Developing-Process
Tuy trong quy trình đã chốt có bước tạo pull request cũng như review code nhưng khi bắt đầu phát triển thì khối lượng công việc phát sinh khá nhiều, không đủ thời gian để thực hiện review. Team quyết định bỏ bước review code để tiết kiệm thời gian.
Đây là quyết định không tốt và dẫn tới nhiều hậu quả xấu như:
Hiện tại team đã có một số giải pháp tạm thời để khắc phục tình trạng trên. Chắc để bài sau mình chia sẻ nhé!
Thường ở những bước quan trọng như merge code hoặc deploy thì chỉ có một người đảm nhận. Điều này là hợp lý vì họ là những người nắm rõ dự án nhất và khi làm việc với các team khác thì một người đại diện sẽ dễ trao đổi hơn rất nhiều.
Thế nhưng, nếu không có người backup thì sẽ là một tai họa. Đã xảy ra trường hợp EGANY Apps gặp lỗi lớn trên production
và không may hôm đấy bạn phụ trách deploy lại có việc cá nhân không thể lên công ty. Ấy vậy là anh em phải xin lỗi và hẹn khách lại vào ngày mai.
Đây là một thiếu sót lớn trong team và hiện đang dần được khắc phục bằng các buổi workshop training cũng như tài liệu đi kèm dự án.
Giao tiếp trong giai đoạn này có lẽ là nguyên nhân lớn nhất dẫn tới các khó khăn bên trên.
Tuy các thành viên chủ động liên hệ lẫn nhau khi cần merge code hoặc deploy nhưng ngoài những việc đó thì lại ít trao đổi những việc khác với nhau. Điều đó dẫn tới các vấn đề như không đồng nhất trong xử lý hoặc đôi khi là việc lặp code không đáng có.
Rất may là giao tiếp giữa các team với nhau khá ổn, làm việc rất chủ động và ăn ý nên dự án vẫn phát triển đều, không bị khựng lại nhiều.
Có công mài sắt, có ngày nên kim. Dù còn nhiều vấn đề trong quy trình cũng như các vấn đề liên quan tới kỹ thuật nhưng team vẫn hoàn thành được mục tiêu ra mắt phiên bản đầu tiên vào tháng 4 năm 2019 với thông số:
Chưa hài lòng với kết quả trên, team tiếp tục quá trình phát triển EGANY Apps với các mục tiêu sau:
Chặng đường còn dài, chắc hẹn các bạn ở bài viết tiếp theo nha!
Cám ơn các bạn đã đọc. Happy hacking!
Trong phần trước, mình đã chia sẻ với mọi người những khó khăn khi team…
Xin chào, tiếp tục loạt bài về trải nghiệm của mình trong việc xây dựng…
Cắm đầu cắm cổ dọn dẹp deadline và dọn nhà trước Tết nên ngâm bài…
Nếu bạn yêu thích phát triển sản phẩm với nhiều thử thách và cơ hội…
Trong phần 1, mình đã giải thích lý do tại sao EGANY chọn AWS làm…
Trong giới công nghệ hiện nay, Amazon Web Service không còn là một cái gì…