[Building a Super App] Tiki’s solutions of building Mini App

Những bài viết liên quan:

Bài toán của Tiki

Tiki là một trong những sàn thương mại điện tử với traffic lớn ở Việt Nam, vì thế có rất nhiều đối tác muốn đưa sản phẩm và dịch vụ của họ lên trên nền tảng của Tiki. Bản thân Tiki cũng muốn cung cấp thêm nhiều sự lựa chọn cho khách hàng, để Tiki không chỉ bán các sản phẩm hàng hoá vật lý, mà còn bán cả các sản phẩm số hoá khác. Việc tích hợp một dịch vụ mới lên Tiki sẽ bao gồm 2 phần, tích hợp về mặt backend và tích hợp về mặt frontend.

Nếu như việc tích hợp về mặt backend là phổ biến và đã có những practice chuẩn, các đối tác và Tiki sẽ cung cấp các backend API để hai bên gọi lẫn nhau, thì việc tích hợp ở frontend gặp khó khăn hơn. Mỗi một dịch vụ ngoài việc có những luồng người dùng khác nhau, có các bước khác nhau để dẫn lối users tới hành động mua hàng, các dịch vụ này lại có cả UI và UX khác nhau nữa. Để đảm bảo được UI/UX của các dịch vụ, trước đây mỗi lần tích hợp một dịch vụ mới lên Tiki, các đối tác phải:

  • Làm việc với team phát triển của Tiki để thống nhất về UI/UX
  • Team phát triển của Tiki sẽ hiện thực hoá các luồng UI/UX này trên website và ứng dụng của Tiki
  • Sau khi dịch vụ được đưa lên Tiki, mỗi lần đối tác muốn chỉnh sửa hoặc tối ưu lại sản phẩm, sẽ cần có sự trợ giúp của team phát triển từ Tiki.

Cách làm như vậy làm cho việc đưa các dịch vụ mới lên Tiki sẽ bị giới hạn bởi capacity của team phát triển từ Tiki, dẫn tới rất khó để onboarding lên nhiều dịch vụ.

Chính vì thế, nhu cầu cần có một giải pháp để việc tích hợp một dịch vụ bên thứ ba vào ứng dụng Tiki đã xuất hiện. Giải pháp này cần đảm bảo các tiêu chí:

  • Bên thứ ba có thể độc lập phát triển ứng dụng/dịch vụ của họ mà không bị block với team phát triển của Tiki
  • Dịch vụ của bên thứ ba có thể chạy được trên ứng dụng/website của Tiki
  • Các ứng dụng của bên thứ cần chạy trên một môi trường sandbox và riêng biệt, điều đó đảm bảo rằng mỗi dịch vụ chỉ được truy cập vào các thông tin của dịch vụ đó, mà không được truy cập vào các thông tin của dịch vụ khác.

Tini App là giải pháp của Tiki cho bài toán này.

Trong buổi workshop lần trước, chúng ta đã nghe bài chia sẻ của anh Việt về hành trình phát triển Tini App trong 12 năm tại Tiki. Trong bài viết này, chúng ta sẽ cùng xem xét chi tiết hơn 3 giải pháp được phát triển gần đây nhất của Tini App bao gồm:

  • H5 App
  • React Native tbox app
  • và cuối cùng là Tini App - giải pháp hoàn thiện

H5 App

Năm 2019, Ticketbox - nền tảng bán vé sự kiện giải trí được sáp nhập với Tiki. Lúc này Ticketbox ngoài việc phát triển mảng bán vé sự kiện, còn phát triển thêm cả mảng bán vé xem phim. Tận dụng lượng người dùng có sẵn từ Tiki, Ticketbox tìm cách tích hợp cả 2 dịch vụ này vào ứng dụng Tiki.

Tại thời điểm đó, chúng tôi sử dụng cách tích hợp bằng WebView.

Trên ứng dụng của Tiki, mỗi lần mở một dịch vụ Ticketbox, ứng dụng của Tiki sẽ mở một website link tới website của Ticketbox.

Website của Ticketbox sẽ chạy hai phiên bản:

  • phiên bản chạy độc lập
  • phiên bản chạy trong ứng dụng Tiki

Cả hai phiên bản này đều sử dụng chung một code base của Ticketbox. Code base này được viết bằng ReactJS. Trong phiên bản chạy trong ứng dụng Tiki, khi mở webview lên, code base của Tiki sẽ inject thêm vào website của Ticketbox một bootstrap script để load bundle của Ticketbox.

Để tích hợp các luồng đăng nhập và thanh toán, giải pháp WebView này sẽ tận dụng lại phiên bản web có sẵn của Tiki để mở trang đăng nhập và thanh toán.

Kết quả cả giải pháp này như sau:

Ở bên tay trái là màn hình hiển thị ứng dụng Ticketbox trên Tiki, bên tay phải là màn hình hiển thị ứng dụng Ticketbox trên website của Ticketbox.

Việc tích hợp bằng WebView cũng có những điểm tốt:

  • Tích hợp nhanh, team Ticketbox chủ động phát triển tính năng mới độc lập so với Tiki
  • Khi ứng dụng Tiki mở Ticketbox bằng WebView, dịch vụ của Ticketbox được chạy trên một WebView độc lập, tách biệt so với ứng dụng Tiki và các dịch vụ khác.

Cách tích hợp này có một số điểm hạn chế:

  • Bản thân ứng dụng Tiki rất khó để kiểm tra được chất lượng dịch vụ của Ticketbox.
    • Mỗi khi Ticketbox update tính năng mới, Tiki hoàn toàn không biết về các tính năng này
    • Khi website của Ticketbox gặp lỗi (ví dụ khi deploy version mới), bản thân ứng dụng của Tiki cũng không biết và vẫn đưa users vào trang web này
  • Trải nghiệm của users trên ứng dụng Tiki khi sử dụng Ticketbox chưa tốt, nhất là ở các màn hình liên quan tới đăng nhập và thanh toán do phải sử dụng màn hình từ phiên bản web

React Native app

Tháng 8/2020, Ticketbox team chuyển thành Social Commerce Team trong Tiki. Nhiệm vụ của team lúc này là xây dựng ứng dụng Social Feed trong nền tảng của Tiki.

Trong quá trình phát triển Social Feed, chúng tôi nhận thấy một số thử thách tương tự với quá trình tích hợp Ticketbox vào ứng dụng Tiki, đặc biệt là các luồng về đăng nhập và thanh toán.

Social Feed cũng có thể coi là một Mini Program trong Tiki. Một phần ứng dụng Tiki đã được phát triển bằng React Native, vì vậy chúng tôi cũng lựa chọn giải pháp này để phát triển Social Feed.

Giải pháp chúng tôi phát triển được gọi là tbox-miniapp , giải pháp này nhằm phát triển các Mini Program bằng React Native. Để các Mini Program được load nhanh hơn, chúng tôi để ý rằng các code base React Native đều sử dụng chung một tập các thư viện, vì thế để load một Mini Program, thay vì phải load tất cả các thư viện này, phần thư viện chung chỉ cần load một lần duy nhất. Mỗi lần mở một Mini Program, chúng ta sẽ load tới phần thư viện tương ứng với Mini Program đó.

Làm như vậy, bundle size của Mini Program sẽ nhỏ, việc load các Mini Program này sẽ nhanh hơn.

Như trong hình ở trên, khi ứng dụng Tiki phát triển 3 tính năng khác nhau:

  • Social Feeds
  • Tiki Live
  • và Seller Store

Cả 3 tính năng này đều được phát triển bằng React Native. Thay vì việc mỗi lần phát triển một tính năng, chúng ta phải tạo ra bundle Javascript riêng cho từng ứng dụng, chúng ta sẽ tách các phần thư viện sử dụng chung như: React, React Native, Video Player, Fast Image, … thành một DLL (dynamic linking library). Thư viện này sẽ được được load một lần duy nhất, từng tính năng khi cần sử dụng chức năng nào sẽ trỏ tới phần thư viện xài chung DLL. Làm như vậy, bundle của từng tính năng sẽ rất nhỏ, việc load từng tính năng sẽ nhanh hơn.

Để các Mini Program có thể làm việc được với Native API, ví dụ như tương tác với các màn hình đăng nhập hoặc thanh toán từ app Tiki, chúng tôi sẽ định nghĩa sẵn một số API có sẵn, và viết chúng thành các Native Modules của React Native. Các Native Modules này chịu trách nhiệm để giao diện để gọi tới các hàm ở tầng Native.

image

Vậy, các bundle này được sinh ra như thế nào?

image

Để sinh ra bundle riêng cho từng, chúng tôi tạo ra môt công cụ được gọi là create-tbox-app. Ở bên dưới, create-tbox-app sẽ sử dụng webpack để phân tách các thư viện xài chung thành một bundle DLL, đồng thời sinh ra bundle của từng feature. Bundle mới sẽ được đẩy lên CDN của Tiki. Khi app Tiki cần load feature nào, app Tiki sẽ gọi tới CDN để download phần bundle này về.

Giải pháp này giúp cho việc sử dụng các Native Module tương đối đơn giản, cũng như việc load các bundle của React Native khá nhanh. Tuy nhiên, do các bundle của các App đều cần access vào phần thư viện chung, nên các bundle này sẽ cần access vào chung một JS Engine Executor. Chính vì thế các bundle của từng app sẽ được isolate với nhau, khi một app bundle gây ra crash, việc crash này có thể dẫn tới crash của toàn app Tiki.

Vì thế, create-tbox-app chỉ phù hợp để phát triển các features khác nhau cho internal team, để có thể đưa create-tbox-app ra cho tất cả các external team thì chưa thực sự phù hợp.

Tini App - Hybrid solution

Sau khi nghiên cứu kỹ hơn về Mini App - Mini Program, chúng tôi nhận thấy kiến trúc Mini App - Mini Program rất phổ biến ở Trung Quốc. Thậm chí một nhóm các công ty ở Trung Quốc đang cùng nhau xây dựng một chuẩn về Mini App - Mini Program

Hiện tại Tini App của Tiki đang follow theo chặt chẽ kiến trúc này. Chúng tôi gọi kiến trúc này là kiến trúc Dual Thread.

Một Tini App khi được chạy lên sẽ có 2 thành phần, tương ứng với 2 threads khác nhau:

  • Page Render là một WebView để hiển thị UI của một page. Mỗi một page của Tini App sẽ ứng với một Page Render
  • Worker Thread là một JS Engine Context để execute toàn bộ logic của Tini App. Một Tini App chỉ có một Worker Thread mà thôi

Việc tách biệt render và worker giúp cho Tini App có thể khởi tạo được nhanh hơn. Trong việc phát triển Web bình thường, render thread và script thread là chạy trên cùng một thread. Nếu một đoạn script chạy lâu có thể làm tăng thời gian loading của một web page. Với việc tách biệt render và worker ra thành 2 thread riêng biệt điều này không còn là vấn đề nữa.

Ngoài ra, nếu với H5 app, Tiki app không thể kiểm soát được chất lượng dịch vụ của một ứng dụng từ đối tác, thì với giải pháp Hybrid, ứng dụng của đối tác được compiler compile thành một file bundle. File này sẽ được load và cache lại trong Tini App, vì thế thời gian load của ứng dụng cũng nhanh hơn, chất lượng dịch vụ của ứng dung cũng được tăng lên.

Việc tận dụng công nghệ Web có sẵn, cũng làm cho Tini App có sẵn khả năng được tách biệt với nhau. Logic của mỗi một Tini App sẽ nằm trong một JS Engine Context. Các Tini App không thể access với nhau, và chỉ được access một tập các API cho trước từ Native.

Việc sử dụng React Native, cũng làm cho việc phát triển các API cho cả 2 nền tảng Android và iOS dễ dàng hơn. Ngoài ra React Native cũng giúp cho Render Thread và Worker Thread có thể access vào các Native API của Tiki. Từ đó, các màn hình đăng nhập và thanh toán được sử dụng, sẽ là các native screen, chứ không phải là các WebView screen như bản H5 app.

Để đảm bảo tính bảo mật, ngoài việc sử dụng các JSContext để isolate logic của từng app, Tini App còn phát triển một compiler riêng để compile code của TXML và JS Logic thành các bundle khác nhau.

Với Tini App, các developers không can thiệp trực tiếp vào DOM Element trên WebView của Render, mà thông qua một DSL được gọi là TXML. Sau khi developer viết các TXML, Tini App compiler sẽ compile các TXML này thành các React Element. Thông qua việc không cho phép developers can thiệp trực tiếp vào DOM, chúng tôi đảm bảo rằng các developer chỉ có thể được truy cập vào các API được cho phép trên UI, và không thể điều hướng users tới những trang web chưa được review.

Công nghệ Compiler không chỉ đảm bảo về mặt UI, mà cả về mặt logic, các file JS cũng được compile để đảm bảo các code của developers chỉ được truy cập vào những biến cụ thể. Các biến nằm trong black list sẽ không được truy cập, ví dụ như các biến Window, XMLHTTPRequest, …

Kết luận

Giải pháp Tini App hybrid cho tới thời điểm hiện tại đã đảm bảo đủ 4 tiêu chí của Tiki khi đánh giá một giải pháp phát triển Mini App - Mini Program:

  • Speed: tốc độ phát triển nhanh
  • Security: tất cả các tini app đều được isolate với nhau, và isolate với chính app Tiki, vì thế các app được chạy trong một môi trường riêng độc lập
  • Stability: do việc chạy trong môi trường độc lập, nên nếu một app có bug, thì cũng không ảnh hưởng tới app khác
  • Simplicity: tận dụng lợi thế dễ mở rộng của TXML, các Tini App có thể dễ dàng phát triển các UI dựa trên một bộ design system có sẵn

Dù rằng còn nhiều điểm cần cải thiện, chúng tôi tin rằng giải pháp Hybrid của Tini App sẽ là giải pháp tốt để scale và giúp ích cho cộng đồng các công ty khởi nghiệp phát triển ứng dụng nhanh hơn và tiện lợi hơn.


Ngoài ra, để hiểu thêm về lí do tại sao Tiki đầu tư phát triển Mini App, từng bước trở thành một trong những super app hàng đầu, bạn có thể tham khảo thêm những chia sẻ từ anh Nguyễn Hoàng Việt - Phó Tổng giám đốc khối Công nghệ tại Tiki, cũng là người đi tiên phong tìm hiểu và phát triển công nghệ này.

Nếu bạn có thắc mắc hoặc bất cứ vấn đề nào liên quan cần trao đổi, đừng ngại để lại comment bên dưới để cùng thảo luận.

12 Likes

Cảm ơn anh Kiên vì một bài viết vô cùng tâm huyết. Respect anh! :ok_woman: :ok_woman: :ok_woman:

6 Likes

Cảm ơn anh Kiên vì bài viết rất nhiều thông tin chất lượng!

2 Likes