Bài học đầu tiên tôi có được từ large-scale app Electron đầu tay của mình

8 tháng trước, tôi bắt đầu phát triển một ứng dụng bằng framework Electron. Để hoàn thành project, tôi phải xây dựng 3 ứng dụng “con” riêng lẻ để chạy trong các môi trường khác nhau. Dưới đây là những bài học tôi học được trong quá trình đó:

Hoàn cảnh

Trước khi tôi đi vào chi tiết, hãy bắt đầu với một số thông tin cơ bản. Vào đầu năm 2019, tôi bắt đầu nộp đơn xin thực tập để có thể tốt nghiệp. Đến tháng 4, tôi đã gửi hàng tá cái CV và nhận được tổng cộng 0 phản hồi. Bạn có thể tưởng tượng, điều này khiến tôi xém trầm cảm khi nghĩ bản thân không đủ tốt cho bất kỳ công việc gì. Nhưng thay vì cho phép cảm xúc chiến thắng, tôi đã chọn sẽ tự chứng minh cho bản thân thấy rằng tôi là người hiểu biết và được việc. Cuối cùng, tôi hiểu rằng tôi thực sự không biết nhiều như tôi nghĩ.

  Kỹ thuật làm app bản đồ, tìm đường và tính năng bắt Pokemon GO

Tôi bắt đầu tìm các dự án cũ của mình để tìm ra thứ gì đó mà tôi có thể scale nó đủ lớn và đủ khó khăn để làm vực dậy ngọn lửa trong tôi. Cuối cùng, tôi đã chọn Binder, lúc đó nó chỉ đơn giản là một ứng dụng web quản lý các tệp Onedrive, Google Drive và Dropbox cùng một lúc. Mục tiêu là tạo ra một dịch vụ sao lưu có thể sánh vai với các dịch vụ trên, trừ mảng chia sẻ file.

Bước đầu của hành trình

Tôi đã lấy một ứng dụng hoàn chỉnh vận hành tốt và chật nó ra từng khúc, biến chúng thành những đoạn mã rẻ tiền, như của bọn tay mơ

Có lẽ tôi đã có thể hoàn thành dự án này nếu tôi không đặt ra một số mục tiêu “hoang đường” ngay từ đầu. Cột mốc đầu tiên tôi đặt ra cho bản thân là hoàn thành phiên bản alpha hoạt động được vào ngày sinh nhật của tôi, giữa tháng Bảy. Tôi ngay lập tức bắt tay vào làm. Đầu tháng 5 tôi đã clone Binder về và bắt đầu “tháo dỡ” nó. Loại bỏ đi nhiều tính năng “vô dụng” với tôi. Tôi đã biến một ứng dụng ngon lành thành một đống code rẻ tiền.

Tôi quyết định phát triển 4 ứng dụng cá nhân. Đầu tiên, một client native trên PC của người dùng. Thứ hai, một API backend để tạo điều kiện cho các request. Thứ ba, một cái cloud để đảm bảo tính toàn vẹn của tất cả dữ liệu được lưu giữ. Cuối cùng, một trang web “tiếp thị” vì mọi sản phẩm đều cần một trang web hào nhoáng.

Bản gốc của “Binder”

Đến phần chính nào

Mọi thứ trước đây đều có rất ít hoặc không liên quan gì đến Electron, chứ đừng nói đến việc phát triển ứng dụng quy mô lớn. Nhưng tôi cần thêm ngữ cảnh để bạn hiểu được tôi đã đúc kết ra những bài học như thế nào. Dưới đây là 5 bài học chính tôi học được:

#1 Hãy chắc chắn rằng bạn sử dụng các cấu trúc frontend/backend truyền thống vì IPC thật sự ngu ngốc

Đã quá nhiều lần tôi phát điên vì cách thức giao tiếp giữa các inter-process trong Electron. Chắc chắn, IPC có thể không được thiết kế để thực hiện javascript-esque trừu tượng, passing-functions-as-objects và whatnot. Nhưng nó chắc chắn sẽ rất có ích! Thay vì thiết kế một client “mỏng”, với phần lớn code nằm trong main process, tôi đã phải vẽ một ranh giới nghiêm ngặt giữa những gì người dùng phải và không phải đối mặt. Tôi đã tự lập một bảng đánh giá để quyết định cái gì sẽ có trong main process và cái gì sẽ có trong quá trình render, một câu hỏi đơn giản – code này có tác động đến những phần khác trong Electron không? Không quan trọng việc đoạn mã nhỏ như thế nào. Nếu nó có liên quan đến các đoạn code khác, nó sẽ tồn tại trong main process cu. Ngoại lệ duy nhất là endpoint thanh toán Stripe, vì lý do bảo mật, tôi muốn nó càng gần user càng tốt.

  Một vài lỗi mà những lập trình viên mới có thể mắc phải

#2 Rất khó để đảm bảo dữ liệu giữ được tính toàn vẹn

một Backdoor không khác gì front door, tất cả những gì Thay đổi là người sử dụng nó.

Đó là cho đến khi tôi bắt đầu làm Binder bằng Electron, tôi nhận ra rằng việc đảm bảo tất cả dữ liệu bạn nhận được từ một số lượng lớn khách hàng ngẫu nhiên vẫn chính xác và có thể truy cập được khó khăn đến mức nào. Giữ an toàn dữ liệu đã đủ khó, nhưng xác thực dữ liệu đó và đảm bảo dữ liệu đó phù hợp với dữ liệu khác mà không thực sự biết dữ liệu đó là gì, mới là khó khăn thiệt sự?!

Việc xác nhận (validate) nên diễn ra càng sớm càng tốt và nên lặp lại (ở mức độ thấp hơn) dọc theo luồng dữ liệu. Việc duy trì tính nhất quán có thể được thực hiện dễ dàng hơn bằng cách áp dụng mô hình transactional bất cứ khi nào thay đổi dữ liệu. Nhưng sự thật là, có rất nhiều metadata (siêu dữ liệu) đi kèm với dữ liệu thực tế (actual data) và việc quản lý chỉ dễ dàng hơn một chút. Ý tưởng thực hiện một chức năng đọc dữ liệu người dùng và kiểm tra tính toàn vẹn nghe có vẻ hay đấy. Tuy nhiên sau khi cân nhắc rất lâu, cuối cùng tôi ngẫm thấy rằng một backdoor cũng không khác gì front door, tất cả những gì mà thay đổi là NGƯỜI SỬ DỤNG NÓ.

#3 Hãy đối xử với UI của bạn như một đôi giày custom

UI của Blinder

Một cách tuyệt vời để thiết kế một giao diện người dùng (UI) đẹp, hiệu quả, là xem nó như một đôi giày custom. Điều đầu tiên tôi tự hỏi khi thiết kế là: Người dùng sẽ thấy UI của Binder như thế nào? Lưu ý rằng, ở đây tôi dùng chữ “thấy” chứ không phải “sử dụng”. Bởi vì ngoại hình là tất cả. Tôi đã tham gia một số dự án tốt trong quá khứ và tôi có thể nói với bạn rằng, sẽ không một ai cho feedback về ứng dụng của bạn nếu UI không vừa mắt.

Tôi bắt đầu với việc vẽ những bản phác thảo nhỏ trong cuốn sổ tay (khi tôi tự đặt mình là người dùng và tưởng tượng về UI). Những phác thảo đầu tiên của tôi đã làm nổi bật bố cục tổng thể của giao diện và khi tôi vẽ nhiều hơn, tôi đã nhận ra những gì tôi muốn như các chi tiết của mỗi trang page sẽ trông như thế nào. Đối với tôi, làm cho mọi thứ dễ nhìn quan trọng hơn những thông tin nhàm chán.

#4 Không có định nghĩa viết code quá an toàn

Thành thật mà nói, tôi không biết bạn nghĩ như thế nào nhưng suy nghĩ về việc tồn tại lỗi trong API sau khi tôi vừa nhận được một khoản thanh toán từ khách hàng khiến tôi lo lắng. Khi tôi bắt đầu triển khai dịch vụ thanh toán, tôi đã tự nhủ với bản thân rằng không thể để bất kỳ sai lầm nào được tồn tại. Tôi đã tự mình thực hiện các bước bảo mật ở mọi nơi, ngay từ khi API nhận được yêu cầu mua gói dung lượng cho đến khi Stripe thông báo cho các webhook và kích hoạt gói. Sự cẩn thận này chắc chắn sẽ làm chậm quá trình phát triển của tôi, nhưng tôi không cảm thấy hối tiếc. Nhờ vậy tôi sẽ biết chính xác khi nào thanh toán được gửi, những gì chúng được gửi và trạng thái của bất kỳ hành động nào cần được thực hiện sau đó.

Kết bài

Rất vui vì bạn đã đọc toàn bộ bài viết của tôi. Có thể bạn biết hoặc không, nhưng Binder đã hoàn thành. Trong khi viết bài này, tôi đã release bản đầu tiên (beta 4) dựa trên Electron. Tôi không nghĩ mình có thể biến Binder thành một sản phẩm hoàn hảo, tuy nhiên, tôi đã xây dựng nó để hoạt động như một sản phẩm thực tế. Bạn có thể xem qua thử trang web “hào nhoáng” này ngay tại đây 😉.

Đôi lời

Tôi đã up mọi thứ liên quan đến việc sử dụng Electron để xây dựng Binder trên trang GitHub này. Tôi sẽ đăng các bản cập nhật ở đó (đó cũng là cách bạn tải xuống máy local client và cách nó tự cập nhật). Nếu bạn học được bất cứ điều gì từ bài đăng này, hoặc nếu bạn có gì góp ý, xin vui lòng ở dưới. Tôi thực sự đánh giá cao nó và cảm ơn bạn!

Ồ, ngoài ra, đây là một số thống kê tôi đã tính toán trên 4 ứng dụng phụ, hy vọng sẽ có ý với các bạn:

binder-local (Electron client)

binder-web (fancy webpage)

Tôi đã không chạy 2 phần còn lại thông qua bộ đếm là vì lý do bảo mật.

binder-api

JavaScript: 21 files, 4117 lines
Other files: ~ 150 lines

binder-mongo (integrity service)

JavaScript: 16 files, 2374 lines
Other files: ~ 140 lines

Total lines of code: 30,015

Đừng bỏ qua những bài viết hay trên trang TopDev nhé:

Lộ trình học fullstack web PHP dành cho developer

Giải bài toán cộng 2 số bàng javascript 

Xem thêm việc làm IT tại Hồ Chí Minh, Hà Nội, Đà Nẵng trên TopDev