Blog

  • Hiểu và phân biệt các Distribution Methods

    Hiểu và phân biệt các Distribution Methods

    Overview

    Đối với lập trình viên iOS, việc archive và distribute app là một kỹ năng quan trọng cần phải có. Xcode cung cấp cho người dùng khá nhiều phương pháp để distribute một ứng dụng, việc hiểu và lựa chọn phương pháp phù hợp với từng yêu cầu sẽ giúp ta rất nhiều.

    Xcode cung cấp một số phương pháp Distribution như sau:

    1. App Store Connect
    2. Ad Hoc
    3. Enterprise
    4. Development
    Distribution Methods

    1. App Store Connect

    Đây là phương pháp Distribution được sử dụng nhiều nhất trong những dự án làm Product, khi phát triển các ứng dụng đã, đang và sẵn sàng đưa lên App Store. Phương pháp này sẽ tạo ra một bản Distribution nhằm mục đích upload trực tiếp ứng dụng lên App Store Connect. Xcode cho phép lựa chọn hỗ trợ upload tự động hoặc xuất ra .ipa file để người dùng upload thủ công. Sau khi upload ứng dụng lên App Store Connect, ta có thể test lại ứng dụng thông qua TestFlight và Submit For Review để chờ Apple review qua lần cuối trước khi chính thức đưa ứng dụng lên App Store.

    Lưu ý: Phương pháp này chỉ hỗ trợ các ứng dụng được build & distribute với certificate của tài khoản Apple Developer thông thường (99$).

    Có 2 lựa chọn: Upload tự động hoặc xuất .ipa

    2. Ad Hoc

    Phương pháp Ad Hoc có cùng một cơ chế và cấu hình như App Store Connect, mục đích là để kiểm thử ứng dụng mà không cần đến App Store Connect/TestFlight. Các cấu hình có phân chia Sandbox/Production như APNs sẽ được nhận Production khi sử dụng Ad Hoc. Ad hoc hỗ trợ xuất ra file .ipa có thể cài đặt trực tiếp vào iPhone thông qua Xcode hoặc iTunes, trình duyệt Safari (OTA). Có một số điểm mạnh của Ad Hoc có thể liệt kê:

    1. Tạo ra phiên bản hoàn toàn giống với App Store, thuận lợi cho việc test trước khi go live
    2. Không phụ thuộc vào App Store Connect: Không mất thời gian chờ Processing Binary, không cần phải invite user vào TestFlight
    3. Linh động và đa dạng trong việc cài đặt ứng dụng, hỗ trợ cả OTA

    Tuy vậy, Ad Hoc cũng có những hạn chế:

    1. Thiết bị iPhone cần đăng ký liên kết với tài khoản Apple Developer để có thể cài đặt được ứng dụng
    2. Mỗi tài khoản Apple Developer có giới hạn 100 thiết bị, Apple chỉ cho phép xoá mỗi năm một lần vào thời điểm Renew Payment
    3. Mỗi lần đăng ký thêm một thiết bị, cần build và distribute lại ứng dụng mới có thể cài được trên thiết bị mới
    4. Ứng dụng sẽ không thể sử dụng khi certificate/provisioning profile dùng để distribute hết hạn

    3. Enterprise

    Enterprise là phương pháp khác biệt nhất trong 4 phương pháp, việc đầu tiên cần phải kể đến là yêu cầu cần phải có tài khoản Apple Developer phải tham gia vào chương trình Enterprise (299$). Việc đăng ký tham gia chương trình Enterprise khá nhiều thủ tục và yêu cầu những thông tin khó tiếp cận hay sở hữu (DUNS). Bù lại, những lợi ích phương pháp này mang lại rất lớn.

    Đầu tiên, đó là việc Distribute ứng dụng đến người dùng một cách không giới hạn mà không cần sử dụng đến App Store. Mục đích của phương pháp Enterprise là tạo ra một bản ứng dụng với cấu hình Production với mục đích phát hành nội bộ bên trong một tổ chức, doanh nghiệp thay vì công khai trên App Store. Việc này sẽ đảm bảo tính bảo mật của doanh nghiệp, sự nhanh chóng và linh hoạt trong việc cập nhật vì không bị phụ thuộc vào App Store. Theo đó, sẽ có nhiều mục đích khác được sử dụng như phát hành game lậu, ứng dụng lậu, các ứng dụng vi phạm bản quyền hoặc bất cứ chính sách nào đó của App Store, hoặc đơn giản là vì không muốn phụ thuộc vào App Store.

    Ngoài việc phá bỏ các rườm rà liên quan đến thiết bị của Ad Hoc, Enterprise vẫn giữ được các điểm mạnh như hỗ trợ nhiều phương pháp cài đặt (Xcode, OTA, …). Tuy vậy, ứng dụng vẫn có thể không thể sử dụng nếu certificate/provisioning profile bị hết hạn.

    4. Development

    Development là phương pháp tạo một bản ứng dụng với môi trường Sandbox, có thể cài đặt với những tài khoản được đăng ký liên kết với Apple Developer Account dưới role Developer hoặc Admin. Đây là phương pháp thường sử dụng để phân phối bản build cho Tester trong giai đoạn IT khi không muốn tác động đến môi trường Production. Phương pháp này cũng có điểm hạn chế về việc phải build lại ứng dụng khi thêm một tài khoản mới. Phương pháp cũng hỗ trợ các hình thức cài đặt giống như Ad Hoc (Xcode, iTunes, OTA).

    Authors

    MinhNN44

  • Cách cấu hình Gitlab CI chỉ kiểm tra các file thay đổi với merge request

    Cách cấu hình Gitlab CI chỉ kiểm tra các file thay đổi với merge request

    Chúng ta sẽ thường hay cấu hình chạy kiểm tra code quality cho tất các các nhánh và merge request trên Gitlab CI. Nhưng Gitlab runner job sẽ chạy scan toàn bộ source code nên sẽ mất thời gian đối với merge request. Ngoài ra đôi khi do source code cũ của khách hàng lỏm sẽ dẫn tới lúc nào merge request đó cũng sẽ bị failed.

    Dưới đây là sample về Gitlab CI chạy python lint với cấu hình chạy cho nhánh develop và merge request.

    pylint:
      stage: lint
      before_script:
        - mkdir -p public/badges public/lint
        - echo undefined > public/badges/$CI_JOB_NAME.score
        - pip install pylint-gitlab
      script:
        - pip install -r requirements.txt
        - pylint --rcfile=.pylintrc --exit-zero --output-format=text $(find -type f -name "*.py" ! -path "**/.venv/**") | tee /tmp/pylint.txt
        - sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' /tmp/pylint.txt > public/badges/$CI_JOB_NAME.score
        - pylint --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter $(find -type f -name "*.py" ! -path "**/.venv/**") > codeclimate.json
        - pylint --exit-zero --output-format=pylint_gitlab.GitlabPagesHtmlReporter $(find -type f -name "*.py" ! -path "**/.venv/**") > public/lint/index.html
      after_script:
        - anybadge --overwrite --label $CI_JOB_NAME --value=$(cat public/badges/$CI_JOB_NAME.score) --file=public/badges/$CI_JOB_NAME.svg 4=red 6=orange 8=yellow 10=green
        - |
          echo "Your score is: $(cat public/badges/$CI_JOB_NAME.score)"
      artifacts:
        paths:
          - public
        reports:
          codequality: codeclimate.json
        when: always
      only:
        - develop
        - merge_requests
      tags:
        - docker
    

    Để giải quyết các vấn đề trên và có thể tập trung vào chất lượng code của các bạn member tốt hơn, chúng ta có thể tạo thêm 1 config mới cho merge request event. Với config mới chỉ cần kiểm tra code quality trên các file thay đổi là được.

    pylint_merge_request:
      stage: lint
      before_script:
        - pip install pylint-gitlab
      script:
        - echo CI_COMMIT_SHA=${CI_COMMIT_SHA}
        - echo CI_MERGE_REQUEST_TARGET_BRANCH_NAME=${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
        - git fetch origin ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
        - FILES=$(git diff --name-only ${CI_COMMIT_SHA} origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME} | grep '\.py'$)
        - echo "Changed files are $FILES"
        - pip install -r requirements.txt
        - pylint --rcfile=.pylintrc --output-format=text $FILES | tee /tmp/pylint.txt
      only:
        - merge_requests
      tags:
        - docker
    

    Hi vọng nó hữu ích với mọi người và có thể apply nó vào dự án của mình.

  • Kiểm soát chi phí sử dụng AWS thông qua việc tạo AWS Budget

    Kiểm soát chi phí sử dụng AWS thông qua việc tạo AWS Budget

    Bạn đã trải nghiệm với các dịch vụ trên AWS, nhưng không may bạn nhận được một bất ngờ không mong muốn trên hóa đơn AWS vào cuối tháng?

    Hoặc có lẽ ai đó trong tổ chức của bạn đã hỏi bạn về việc chi phí AWS tăng cao, có cách nào nhận thông báo chi phí đã sử dụng trên AWS theo hằng ngày được không.

    Đây là việc mà có lẽ hầu hết các kĩ sư cloud đã trải qua.

    AWS Budget sẽ giúp các bạn giải quyết các vấn đề đó. Theo dõi các bước bên dưới để thiết lập nó nhé.


    (1) Đăng nhập vào tài khoản AWS của bạn. Nhập AWS Budgets ở ô tìm kiếm. Sau khi hiển thị kết quả chọn AWS Budgets.

    budget1

    (2) Ở màn hình giao diện Budgets, chọn Create budget.

    budget2

    (3) Ở Step 1, chọn Budget types là Cost budget, sau đó ấn Next step.

    budget3

    (4) Ở Step2, nhập các thông tin budget như hình. Ở chỗ nhập Enter your budgeted amount nên nhập giá trị nhỏ, để Budget sẽ dễ dàng kiểm tra và thông báo cho bạn được thường xuyên. Mình hay để chỗ này tầm 5 hoặc 10$.

    budget4

    (5) Ở Step3, chọn Add an alert threadhold để cài đặt alert.

    budget5

    Trên giao diện Alert, mình sẽ cần nhập thông tin như bên dưới:

    • Threshold: Phần trăm cost sử dụng so với giá trị budget đã set ở Step2 để trigger thông báo. Mình hay để chỗ này tầm 50 hoặc 60.
    • Email recipients: Nhập các email bạn mong muốn để nhận thông báo cost. Các email sẽ cách nhau bởi dấu (,)

    budget6 Sau khi đã nhập xong thì mình chuyển sang step tiếp theo.

    (6) Ở Step4, mình sẽ để default không thay đổi gì cả và chuyển sang step tiếp theo. budget7

    (7) Ở Step5, mình sẽ nhìn lại các cài đặt ở các bước lúc trước. Nếu không có vấn đề gì thì mình chọn Create budget. budget8

    (8) Bạn sẽ nhận email có nội dung như bên dưới. budget9

  • CÁCH KHÔNG NHỚ LỆNH GIT MÀ VẪN DÙNG ĐƯỢC GIT NGON Ơ

    CÁCH KHÔNG NHỚ LỆNH GIT MÀ VẪN DÙNG ĐƯỢC GIT NGON Ơ

    TABLE OF CONTENT

    • Định nghĩa về Sourcetree
    • Cài đặt
    • Một số chức năng <br>

    Bạn có phải là một developer?

    Bạn đã từng tương tác với git qua những câu lệnh trên terminal rồi phải không?

    Bạn có bao giờ cảm thấy phát cáu vì bị lẫn lộn hoặc không nhớ được câu lệnh của git không?

    Nếu câu trả lời là không… vậy thì bye bye bạn nhé, bạn không cần phí thời gian để đọc bài viết này đâu.

    Nếu không phải case trên, xin chúc mừng vì tôi có một giải pháp cho bạn đây.

    SOURCETREE

    Sourcetree là một phần mềm giúp cho developer tương tác với git remote repository thông qua giao diện người dùng. Giao diện này thân thiện và dễ hiểu bởi con người hơn so với những dòng lệnh terminal khô khan. Nó thân thiện đến nỗi kể cả một user không phải developer cũng có thể dễ dàng đọc hiểu và tương tác được là bạn phải hiểu như thế nào rồi đấy.

    Xong phần định nghĩa, tiếp theo đi vào 1 trong những chủ đề chính đã được nêu ra ở title đó là

    CÀI ĐẶT SOURCETREE

    Download đã nào: các bạn download phần mền tại link Download SourceTree for Windows – Free – 3.4.5 (digitaltrends.com) hoặc có thể search với từ khóa download Sourcetree để download trên các trang khác.

    Đợi git được install xong thì click next nhé

    Nhập email mà bạn dùng để kết nối với git vào đây rồi click next nhé

    Tại đây click No nhé

    Vậy là việc cài đặt Sourcetree đã hoàn thành rồi. Bây giờ cùng xem cách sử dụng như nào nhé

    SỬ DỤNG SOURCETREE

    Như đã nêu ở phần định nghĩa, Sourcetree là một phần mềm giúp cho developer tương tác với git remote repository thông gia giao diện người dùng. Từ đó suy ra chúng ta phải kết nối được git trên remote repository với repository trên local thì mới sử dụng được. Vậy bây giờ chúng ta sẽ thực hiện đồng thời 2 việc clone project trên remote repository về máy local và connect remote repository với local repository nhé.

    Mở phần mềm Sourcetree lên và chọn tab Clone.

    Source Path / URL: link clone project lấy từ git

    Ví dụ, link source path lấy từ gitlab

    Destination Path: vị trí lưu project sau khi clone về

    Sau khi nhập đầy đủ các thông tin trên bạn click vào button clone

    Sau một vài giây nếu cửa sổ sau được hiển thị thì chúng ta đã cài đặt thành công.

    Phần BRANCHES là những branch trên local repository.

    Phần REMOTES là những branch có trên remote repository.

    Kết nỗi giữa local và remote repository đã xong, giờ đây bạn có thể thực hiện các chức năng thêm, sửa, xóa nhánh, add, commit, push, pull các nhánh và các chức năng khác của git thông qua chiếc tool có giao diện thân thiện này. Sau đây là ví dụ về một số chức năng của Sourcetree.

    1 Lấy nhánh từ remote repository về local repository

    Chuột phải vào tên nhánh trên remote và chọn checkout

    2 Đẩy thay đổi từ local repository lên remote repository

    Mình thử comment 1 dòng code

    Để add thay đổi click vào dấu cộng nhé

    Mở remote repository ra ta có thể thấy thay đổi mà ta vừa đẩy lên

    3 Tạo nhánh mới và đẩy lên remote repository

    Push nhánh vừa tạo lên remote repository (nếu có thay đổi source trên nhánh vừa tạo thì phải thực hiện commit source trước)

    Nhánh mới đã có trên remote repository

    Trên đây là hướng dẫn cơ bản để cài đặt và sử dụng chiếc tool sourcetree thay cho những dòng lệnh khô khan và khó nhớ ở git terminal. Hi vọng rằng bài viết này hữu ích đối với bạn.

  • IOS/Swift: Cách sử dụng Lazy Sequences để tối ưu hoá performance app ios

    IOS/Swift: Cách sử dụng Lazy Sequences để tối ưu hoá performance app ios

    Article overview

    Nói về Lazy property chúng ta đã quá quen thuộc với lazy var, nhưng bạn đã bao giờ sử dụng lazy property vào sequences ? Bài viết này sẽ giúp các bạn cách sử dụng lazy vào các phép xử lý map, filter, reduce một cách hiệu quả và tối ưu hoá performance app ios.

    Table of contents

    Lazy Sequences là gì ?

    Chúng ta cùng xem ví dụ sau, cho một collection mảng số nguyên từ 1 tới 1000, lọc mảng số nguyên chỉ lấy những giá trị là số chẵn, sau đó nhân đôi từng giá trị lên, rồi trả về kết quả giá trị đầu tiên value lớn hơn 10. Nếu không sử dụng lazy chúng ta có kết quả như sau:

    Image of article

    Nếu sử dụng lazy chúng ta sẽ có kết quả như sau:

    Image of article

    Chúng ta có thể thấy kết quả 2 bên đều = 12, nhưng có sự khác biệt lớn ở trường hợp không sử dụng lazy, phép xử lý filter chạy duyệt hết 1000 phần tử rồi tới phép xử lý map chạy tiếp và tương tự chạy 500 phần tử rồi mới tới phép xử lý tiếp theo. Nhưng nếu sử dụng lazy chúng ta thấy filter chỉ cần chạy 6 lần, map chỉ cần chạy 3 lần.

    Ở trường hợp không sử dụng lazy chúng ta thấy phép xử lý phải chạy hết 1000 phần tử nhưng với điều kiện bài toán của chúng ta thì không cần thiết phải duyệt hết 1000 phần tử, lazy sẽ giúp chúng ta chạy song song các phép xử lý tức là khi filter chạy duyệt 1 phần tử chúng ta có được 1 kết quả của phép filter sau đó kết quả này sẽ dùng chạy tiếp cho phép xử lý map rồi đến first và cứ lặp lại như vậy khi có được kết quả thoả mãn điều kiện bài toán sẽ dừng lại không chạy tiếp. Ở ví dụ này thì chúng ta thấy con số tương đối nhỏ nhưng hãy tưởng tượng nếu chúng ta có một bài toán tương tự nhưng phạm vi mảng tới hơn 1 triệu thì lazy sẽ giúp chúng ta tối ưu rất nhiều số lần duyệt mảng từ đó hiệu suất ứng dụng app sẽ tốt hơn.

    Nếu chúng ta có một collection ít phần tử thì việc sử dụng lazy cũng không mang lại tối ưu nhiều chính vì vậy chúng ta tránh lạm dụng lazy, chỉ nên sử dụng nếu chúng ta có một collection với nhiều phần tử.

    Lazy collections không được cache lại, với lưu ý này chúng ta cùng xem ví dụ sau:

    let modifiedLazyNumbers = (1...4)
        .filter { number in
            print("Even number filter")
            return number % 2 == 0
        }.map { number -> Int in
            print("Doubling the number")
            return number * 2
        }
        
    print("Ket qua ne print lan 1: \(modifiedLazyNumbers.first!)")
    print("Ket qua ne print lan 2: \(modifiedLazyNumbers.first!)")
    
    // Even number filter
    // Even number filter
    // Even number filter
    // Even number filter
    // Doubling the number
    // Doubling the number
    // Ket qua ne print lan 1: 4
    // Ket qua ne print lan 2: 4
    
    let modifiedLazyNumbers = (1...4)
        .lazy
        .filter { number in
            print("Even number filter")
            return number % 2 == 0
        }.map { number -> Int in
            print("Doubling the number")
            return number * 2
        }
        
    print("Ket qua ne print lan 1: \(modifiedLazyNumbers.first!)")
    print("Ket qua ne print lan 2: \(modifiedLazyNumbers.first!)")
    
    // Even number filter
    // Even number filter
    // Doubling the number
    // Ket qua ne print lan 1: 4
    // Even number filter
    // Even number filter
    // Doubling the number
    // Ket qua ne print lan 2: 4
    

    Các bạn có thể thấy sự khác nhau chính là vì lazy collection chỉ chạy các phép xử lý khi có request tới, chính vì vậy giá trị kết quả cuối cùng sẽ không được lưu ở output array, mỗi khi có request tới phép xử lý phải chạy lại.

    • Kết luận Chúng ta có thể thấy lazy collection mang lại hiệu quả tốt với performance nhưng chỉ nên áp dụng nếu chúng ta xử lý bài toán với phạm vi mảng lớn.

    Authors

    [email protected]

  • Gitlab CI/CD cho người mới bắt đầu

    Gitlab CI/CD cho người mới bắt đầu

    CI-CD in gitlab

    Chắc hẳn mọi người đã từng nghe tới CI-CD, rồi thắc mắc không biết nó là gì và chúng ta có thể làm gì với nó? Mình cũng như vậy, thắc mắc ấy đưa mình đến việc viết chuỗi bài này để chia sẻ về những gì mình đã học được về CI-CD.

    Trong bài này thì mình sẽ tập trung vào CI, cũng như cách config file .gitlab-ci.yml và chạy trên share runner của gitlab.

    I. Vậy CI-CD là gì?

    CI (Coutinous Integration) – tích hợp liên tục, là quá trình mà code của chúng ta được build và test trước khi tích hợp vào nhánh chính.

    CD (Continous Delivery) – truyền tải liên tục, là quá trình mà code được triển khai lên môi trường như development hoặc production, và nó diễn ra ngay sau CI

    II. Triển khai CI như thế nào?

    1. Thành phần

    Để có thể triển khai được CI thì trước hết, chúng ta cần biết về 2 thành phần chính cấu thành nên nó. Đó là file gitlab-ci.ymlgitlab runner.

    Mọi người có thể hiểu nôm na nếu gitlab runner như một anh tài xế mà bạn thuê, anh ta rất nhiệt tình, sẵn sàng lái xe đi bất cứ nơi đâu thay cho bạn, nhưng khổ nỗi anh lại không biết đường. Hmm… Làm sao bây giờ? File gitlab-ci.yml lúc ấy xuất hiện như một tấm bản đồ vạn năng.

    File này sẽ được gitlab tự động nhận diện khi bạn commit code lên từ local, và sẽ cấp cho bạn một anh "tài xế" shared runner để đi làm những việc bạn đã vạch sẵn ở trong gitlab-ci.yml.

    Lưu ý:

    Mặc định, gitlab có một số share runner mà người dùng có thể dùng ngay lập tức. Vì vậy, đối với một project vừa và nhỏ, số lượng job cho runner còn ít, thì bạn có thể tận dụng luôn những runner đã có sẵn này. Nhưng với một project lớn hơn, khi mà số lượng cũng như tần suất chạy job ngày càng tăng lên, thì chúng ta nên config riêng một gitlab-runner trên server của mình.

    2. Template

    
    stages:          
      - build
      - test
      - deploy
    
    build-job:      
      stage: build
      script:
        - echo "Compiling the code..."
        - echo "Compile complete."
    
    unit-test-job:
      stage: test   
      script:
        - echo "Running unit tests... This will take about 60 seconds."
        - sleep 60
        - echo "Code coverage is 90%"
    
    lint-test-job:   
      stage: test   
      script:
        - echo "Linting code... This will take about 10 seconds."
        - sleep 10
        - echo "No lint issues found."
    
    deploy-job:     
      stage: deploy  
      script:
        - echo "Deploying application..."
        - echo "Application successfully deployed."
    

    Templete cho một file gitlab-ci.yml

    Chúng ta sẽ cùng nhau đi qua một lượt xem nó có ý nghĩa gì nhé!

    Đầu tiên là stages: đây sẽ là khi chúng ta định nghĩa ra các giai đoạn mà trong pipeline, hay nói cách khác là các job mà runner sẽ phải thực hiện. Như đa số project, workflow sẽ bao gồm 3 giai đoạn, đầu tiên chúng ta sẽ tạo ra một bản build của project, tiếp sau đó sẽ test, và khi đã qua được các bước trên thì sẽ deploy lên môi trường development, staging hay production.

    stages:    
      - build
      - test
      - deploy
    

    Tiếp theo, chúng ta sẽ đi cụ thể tới các build stage nha (Các giai đoạn sau cũng tương tự).

    • build-job là tên của job, cái này các bạn có thể tự thay đổi theo ý mình nhé.
    • stage chỉ ra job này đang nằm trong giai đoạn nào trong 3 stages mà chúng ta đã định nghĩa trước ở trên.
    • script là những câu lệnh mà chúng ta sẽ chạy trong job này.
    build-job:      
      stage: build
      script:
        - echo "Compiling the code..."
        - echo "Compile complete."
    

    Ngoài ra thì còn rất nhiều những thông tin config khác mà các bạn có thể tìm ở đây nha!

    Và như bạn đã thấy ở templete trên, thì một pipeline có thể có nhiều giai đoạn và một giai đoạn có thể chứa nhiều job khác nhau và các job đó có thể được thực hiện song song.

    3. Ví dụ

    Mình sẽ lấy ví dụ từ bẳng việc check lint của một project nodejs nha!

    Bước 1: Chúng ta sẽ phải cài đặt eslint và babel-eslint cho project của mình.

    npm install eslint babel-eslint --dev
    

    Bước 2: Tạo file .eslintrc để config lint rule mà mình muốn:

    {
      "env": {
        "node": true,
        "es6": true,
        "mocha": true
      },
      "parser": "babel-eslint",
      "parserOptions": {
        "ecmaVersion": 2017
      },
      "extends": "eslint:recommended",
      "rules": {
        "comma-spacing": [
          "error",
          {
            "before": false,
            "after": true
          }
        ],
        "indent": [
          "error",
          2,
          {
            "SwitchCase": 1
          }
        ],
        "linebreak-style": [
          "error",
          "unix"
        ],
        "quotes": [
          "error",
          "double"
        ],
        "semi": [
          "error",
          "always"
        ],
        "no-unused-vars": [
          "off"
        ],
        "no-console": 0
      }
    }
    

    Bước 3: Thêm script cho việc check lỗi và fix lỗi lint trong file package.json

    Trong dấu "{}" ở câu lệnh lint là các folder mà mình muốn check lint, các bạn có thể để folder khác cho phù hợp với project của mình nhé!

    Bước 4: Chạy lần lượt hai câu script trên và đẩy code lên git.

    Bước này là để trước khi các bạn check xem những nhánh phụ merge vào có đúng theo rule lint mình đã định nghĩa không, thì nhánh chính của mình đã thỏa mãn những rule đó từ trước.

    Bước 5: Tạo file .gitlab-ci.yml

    
    
    stages:   
      - checklint
    
    lint-test-job: 
      stage: checklint    
      image: node:12.18-alpine 
      only:           
        refs:
          - merge_request
      script:
        - npm install eslint babel-eslint
        - npm run lint
    
    

    Ở đây sẽ có 2 từ khóa mới:

    image: dùng base image là node:12.18-alpine để tạo một node instance chạy các câu lệnh mình định nghĩa ở phần script

    onlyrefs: giới hạn việc chạy job này chỉ khi có merge request

    Bước 6: Tách nhánh mới, đẩy lại code lên gitlab và tạo merge request

    • Đây là ở merge request trước khi chúng ta đẩy file gitlab-ci.yml lên remote repo

    • Sau khi đẩy file gitlab-ci.yml lên

    Bây giờ nếu như mọi người thấy biểu tượng pipeline running như hình 2 ở trên là mình đã thành công rồi nha!

    Từ bây giờ mỗi khi bạn đẩy code mới lên remote repository thì gitlab runner sẽ tự động chạy test lint cho chúng ta!

    Nếu thích bài viêt này thì các bạn nhớ like and và share để ủng hộ mình có động lực viết phần tiếp theo về gitlab runner và CD nha <3

    P/s: Đây là bài viết đầu của mình nên không thể tránh khỏi những thiếu sót, có gì mong được mọi người bỏ qua và góp ý cho mình nha! Cảm ơn mọi người nhiều <3

  • ANT DESIGN – Điều gì khiến thư viện này vượt “mặt” Material-UI của Google?

    ANT DESIGN – Điều gì khiến thư viện này vượt “mặt” Material-UI của Google?

    anhbia Ant Design – Điều gì khiến thư viện này vượt "mặt" Material-UI của Google?

    Nếu bạn là một Front-End developer và thường xuyên sử dụng những thư viện UI cho các dự án của mình thì chắc chắn các bạn đều sẽ biết đến những cái tên rất quen thuộc như Material-UI (MU) do Google phát triển hay Bootstrap do hai kỹ sư tại Twitter làm ra, tất cả đều là các thư viện hỗ trợ thật sự tuyệt vời về tính Responsive cho các màn hình thiết bị khác nhau, các components Javascript có sẵn.

    Tuy nhiên, bạn biết đó, thời nào cũng sẽ có những anh hùng hào kiệt, một cái tên khác đang phất lên rất nhanh và cũng nhanh chóng được yêu thích của cộng đồng developers React Front-End đó là ANT DESIGN (ANTD) đạt 73,1k sao trên github và đang vượt lên so với Material-UI (70k sao). Có lẽ điều đầu tiên bạn sẽ biết về ANTD đó là thế lực tạo ra nó – Alibaba.

    Vậy ANTD có gì mà có thể vượt lên so với MU – một thư viện UI/UX do Google phát triển rất lâu trước đó?

    Tổng quan bài viết

    ANT DESIGN và ANT DESIGN PRO

    Bạn có phải lần đầu biết đến ANTD? Có khoảnh khắc nào trong những giây phút "chilling" bạn search google với keyword "ant design là gì?" nhưng chắc có lẽ bạn vẫn chưa biết tới cái tên ANT DESIGN PRO nếu chưa bao giờ sử dụng ANTD.

    ANT DESIGNANT DESIGN PRO là hai phần khác nhau của ANTD.

    ANT DESIGN: Dành cho những components đã được viết sẵn, bạn chỉ cần import và tái sử dụng lại những components đó, ví dụ như Carousels, Form, Upload, Modal, Badge,…etc.

    • Điều khiến ANTD trở nên đặc biệt là Document cực kì rõ ràng, các api của components đều có demo và ví dụ đi kèm, bạn có thể xem code trong codeSandbox/codepen/stackblitz. Một số components được ANTD viết với TypeScript, cùng nghía qua một "tí tẹo" document của ANTD nha:

    document

    Nếu những điều này chưa khiến bạn phải "quaoooo" thì hãy xem tới các props của ANTD và khả năng hỗ trợ Customize Base component của nó.

    Bạn biết đấy, đôi khi làm việc với các thư viện, bạn sẽ muốn thay đổi các base components để đáp ứng như cầu của khách hàng/dự án và props của ANTD sẽ là công cụ đắc lực giúp bạn dễ customize hơn và viết code tối giản hơn nhiều.

    Vậy còn ANTD PRO thì sao?

    ANT DESIGN PRO thì khác, nó là một theme gần như hoàn chỉnh dành cho các trang Admin, CMS ( Control Management System). Bạn có thể thấy được những gì mà ANTD PRO có thể hỗ trợ bạn qua <a href="https://preview.pro.ant.design/" target="_blank">website preview</a>.

    • Cài đặt ANTD PRO với npm hoặc yarn:

    install

    Sau khi cài đặt, bạn sẽ thấy rằng điều bạn cần làm là chọn những phần components bạn muốn và bắt đầu gọi API từ phía Back-end hoặc gỉa lập API với file _mock.js có sẵn của ANTD PRO luôn mà không cần phải đau đầu suy nghĩ về UI hay viết code làm sao. Rất tiện lợi đúng không?

    Chưa hết, ANTD PRO còn mang đậm tính "all-in-one", chỉ 1 lần cài đặt mà bạn có thể sử dụng luôn:

    1. Webpack (Webpack giúp tăng tốc độ cho dự án, đóng gói thành một file duy nhất,…)

    2. Less ( một CSS preprocessor giống với SCSS )

    3. Sự tuyệt vời đến từ UmiJS – cái tên bạn … chưa nghe qua bao giờ đúng không?

    UmiJS: chính là một thư viện Plugin enterprise-level cho React. Nghe thì xa tầm với nhưng ý lại nằm trong lời, UmiJS bao hàm bên trong là redux-saga, gọi api thay vì với Axios thì sẽ là Request.

    Ai cũng biết Axios hỗ trợ việc gọi api request tốt và "uy tín" như thế nào nhưng UMI-Request lại hơn thế đấy, cùng xem bảng so sánh của umi-request với Axios và Fetch sau:

    install

    Bạn đã bị thuyết phục chưa? Nếu chưa thì hãy tới mục số II nha.

    WEB COMPONENT vs MOBILE COMPONENT

    Giống như sự hỗ trợ của ANTD dành cho web version thì ANTD cũng đã dành điều đó cho cả <a href="https://mobile.ant.design/docs/react/introduce" target="_blank">mobile version</a>.

    Version dành cho Mobile là cái mà Material UI chưa làm nhưng ANTD đã làm và còn đầu tư chất lượng cho document của mobile không kém cạnh gì cho web version.

    => Có thể thấy ANTD là một thư viện UI được đầu tư, phát triển mạnh mẽ và đến đây chúng ta cũng có thể hiểu tại sao số sao trên github dành cho ANTD lại vượt nhanh hơn cả MU.

    Tips và ví dụ customize sử dụng PROPS của ANTD

    Từ mục I và II chúng ta đều được biết tới sự hỗ trợ "xịn xò" cho các developers React Front-End nhưng lại không biết nhược điểm của nó là gì và tips để sử dụng ANTD hiệu quả đúng không?

    Nhược điểm của ANTD:

    1. Document của ANTD vẫn còn một vài chỗ viết bằng tiếng Trung, đặc biệt là Document của ANTD PRO/UMIJS

    => Việc tiếng Trung còn nhiều khiến cho các developers gặp khó khăn khi muốn customize components hoặc đọc về API/Props hỗ trợ.

    1. Trên các trang như Stackoverflow, dev.to,… có ít các bài được giải thích hoặc hỗ trợ cho ANTD.

    => Vậy nên khi gặp bug, các bạn cũng có thể mất kha khá thời gian để sửa và kiểm tra lại.

    1. Tuỳ chỉnh Theme

    => Khả năng tuỳ chỉnh theme của ANTD không mạnh bằng MU khi chỉ có thể thay đổi các mặc định về màu sắc, kích thước,…

    Tips khi sử dụng ANTD:

    1. Hãy đọc kĩ các phần API, props của ANTD hỗ trợ.

    => Có thể khi đứng trước một vấn đề mà vấn đề đó cần customize một base component của ANTD mà bạn chưa có ý tưởng bắt đầu làm như thế nào, hãy đọc kì api/props mà component đó có, có thể bạn sẽ nhận ra mình đỡ bỏ lỡ một sự kết hợp hay ho đó.

    1. Hãy viết style bằng less

    => ANTD cũng không quá khắt khe cho việc viết style như khi dùng bootstrap nhưng để tối ưu việc style, responsive và sự tương thích với các trình duyệt khác nhau thì hãy viết với less nhé.

    • Ví dụ về customize sử dụng PROPS của ANTD

    Customize dropdown của <Select> với infinity scroll

    Có 5 bước chúng ta cần làm (nguồn: <a href="https://codesandbox.io/s/antd-select-infinite-scroll-90shp?file=/index.js:1649-2578)" target="_blank">click here to open codeSandbox</a>)

    Bước 1: Import các phần cần thiết và viết một component:

    import React from "react";
    import ReactDOM from "react-dom";
    import "antd/dist/antd.css";
    import "./index.css";
    import Select from "antd/lib/select";
    const { Option } = Select;
    
    class LazySelect2Input extends React.PureComponent {
      render() {
        return <div className="App"></div>;
      }
    }
    

    Bước 2: Viết hàm để render mock data:

    // Fetch at most 200
    // On scroll uses a queue
    // Pop
    
    const children = [...Array(20).keys()];
    const range = (start, stop, step) =>
      Array.from({ length: (stop - start) / step + 1 }, (_, i) => start + i * step);
    const handleChange = (value) => console.log(`selected ${value}`);
    

    Bước 3: Khai báo constructor với props, state:

     constructor(props) {
        super(props);
        this.state = {
          lastScrollPos: 0,
          loadingMore: false,
          options: children,
          min: 0,
          search: undefined
        };
      }
    

    Bước 4: Viết function để thực hiện infinity scroll:

    handleScroll = (event) => {
      event.stopPropagation();
      let delta;
      const { options, min, loadingMore } = this.state;
      let newMin = min;
      if (event.wheelDelta) {
        delta = event.wheelDelta;
      } else {
        delta = -1 * event.deltaY;
      }
    
      if (!loadingMore) {
        if (delta < 0) {
          newMin = min + 1;
          if (newMin + 10 >= Math.max(...options)) {
            // Fetch more items when the list is exhausted.
            this.handleFetchMore(Math.max(...options) + 1, 10, newMin);
          }
        } else if (delta > 0 && min >= 1) {
          newMin = min - 1;
        }
    
        return this.setState({ min: newMin });
      }
    };
    
    handleFetchMore = (offset, limit, min) => {
      this.setState(
        {
          loadingMore: true,
          options: [...this.state.options, ...range(offset, offset + limit, 1)],
        },
        () =>
          this.setState({
            loadingMore: false,
            min,
          })
      );
    };
    

    Bước 5: Render và Return:

    render() {
        const { loadingMore, min, options, search } = this.state;
        let currentOptions = options;
        const extraProps = {};
    
        if (search) {
          currentOptions = options.filter(v => v.toString().indexOf(search) >= 0);
          extraProps.open = true;
          extraProps.key = "searching";
        }
        return (
          <div className="App">
            <Select
              mode="multiple"
              style={{ width: "100%" }}
              onChange={handleChange}
              // dropdownRender, filterOption, defaultActiveFirstOption
              // are props for customize of ANTD
              dropdownRender={menu => <div onWheel={this.handleScroll}>{menu}</div>}
              loading={loadingMore}
              onSearch={search => this.setState({ search })}
              filterOption={false}
              defaultActiveFirstOption={false}
              {...extraProps}
            >
              {currentOptions.slice(min, min + 10).map(i => (
                <Option key={i} value={i}>
                  {i}
                </Option>
              ))}
            </Select>
          </div>
        );
      }
    

    => Có thể thấy các props dropdownRender, filterOption, defaultActiveFirstOption đã hỗ trợ cho chúng ta bắt sự kiện scroll khi tag Select xổ xuống các option để việc thực hiện tải thêm data khi người dùng cuộn xuống phần đáy của tag select (popup container).`

    Tổng kết

    Chúng ta đã có một bài đọc khá dài về ANT DESIGN. Hi vọng những gì mình chia sẻ có thể giúp bạn hiểu thêm về nó và có thể dễ dàng bắt đầu sử dụng hơn nha. Cảm ơn các bạn đã đọc.

  • How to build an end to end scalable visual search system with AI Computer Vision and AWS

    How to build an end to end scalable visual search system with AI Computer Vision and AWS

    With the rise of e-commerce, online retail, visual search is a rapid trend because they are largely driven by visual content. In this article, I will share with you guys the visual search project that was built in 2018 for my Japanese partner.

    What are the problems?

    My partner is one of the biggest retailers of toys, clothing, and baby product in Japan. They have lots of stores all over the world. On holiday, the long queues of customers wait to checkout happen in lots of stores. So to solve this problem, they decide to apply the new store like Amazon Go, no queues, no checkout, just walk out of the store. In short, this not only improves their customers’ buying experience but also maximizes revenue growth.

    Why do we need Visual Search?

    provider

    My partner has lots of providers. Each of them distributes different types of products. The products will be updated frequently by weekly, monthly, or yearly. So visual search system needs to be updated the same as the scale of products.

    What is the core technology here?

    provider

    By the time I started this project in 2018, Triplet loss had proved efficient in Face Recognition. With that starting point, we decide to apply Triplet Loss as our core visual search technology because our problem is quite similar to Face Recognition. To get the highest accuracy and make the system scalable, we classify products into different categories and subcategories because Triplet loss will have the best performance when all the products are in the same domain property. For example, when you do Face Recognition, all the images are facial, right? Then in our problem, we train all the toys that have a similar domain with one AI Model. For example, the Lego toys will be trained together, the Figures will be trained together, and so on. And not only that, one of the most advantages here is when new products need to be updated, our system don’t need to re-training the whole model, the whole process which can reduce the cost. Normally, it’s very costly and takes us lots of time for training an AI model.

    The architecture overview

    provider As you can see, we have two main components: Serving and Training. The training component is built to fit with Admin, Operator, Providers, and Developers with different purposes. For any Machine Learning production, one of the most challenging parts is how your system can run automatically with the minimum of human interference. The serving component will host all APIs needed for our web app and mobile app.

    Triplet Loss training strategy

    Our strategy here to get the best model is: Clustering the categories to group categories with similar type samples. For each anchor image, we will pick 1 hardest positive, 1 hardest negative among the image batch. We will keep multiple anchors and compute the centroid of anchors for each category. To reduce computation cost we will first match with anchor centroids. If the distance is lower than TL and higher than TH, we will give an immediate decision that the product exists and doesn’t exist respectively. We are using two thresholds. Lower threshold, TL, and higher threshold And in the end, our model has very good accuracy, for the trained data, the accuracy is over 99 percent and 97 percent for un-trained data respectively.

    Alt text

    Demo

    A Video Worth a Million words, so, please see this demo below on how we increase customer engagement with AR and AI.

    Alt text

    Conclusion

    This article is focused on sharing the overview flow, architecture, and an example use case when AI is applied in the real world. If you are curious more about the technology, the development, or the business side, please follow my next articles.

  • Software Architecture: Bắt đầu từ đâu? – Part 3 Soft Skills  – Continuous Delivery

    Software Architecture: Bắt đầu từ đâu? – Part 3 Soft Skills – Continuous Delivery

    Trong phần trước, mình đã nói về Soft Skill — Decision, trong phần này sẽ đề cập tới một loại khác mà sẽ gây nhiều tranh cãi: Continuous Delivery.

    Continuous Delivery, hãy nói về mặt khả năng, chính xác hơn là điểm khác biệt với Manual Delivery ở 3 yếu tố: an toàn, nhanh chóng và bền vững (hoặc dùng từ Việt một chút là ổn định).

    Trong bài viết này sẽ không đánh đồng Continuous Delivery với các kỹ thuật automate, mà mọi người hay khá nhầm lẫn với việc Automation Delivery (một trong những kỹ thuật của CD). Dù sao thì, mình chỉ muốn xem xét về mặt văn hóa trong dự án phần mềm.

    Tại sao cần Continuous Delivery?

    Thời gian — tất nhiên rồi, ai cũng muốn đưa những tính năng mới nhất cho người dùng một cách nhanh nhất, đưa hệ thống trở lại khi downtime nhanh nhất (Mean Time To Repair) đồng nghĩa với việc business được duy trì, tiền kiếm được không bị ngừng trệ.

    Hãy xem xét 2 loại thời gian:

    • Lead time: lượng thời gian từ khi bắt đầu và kết thúc của một công việc trong quy trình
    • Cycle time: khoảng thời gian mà giữa 2 công việc liên tiếp được kết thúc, hay còn có thể hiểu là Deployment Frequency cho dễ hiểu

    Continuous Delivery Pipeline sẽ được hình dung như này

    image

    Còn đây là Lead time image

    Đây là Cycle time nè image

    Vậy thời gian bao nhiêu là đủ?

    image

    Credit: Forsgren PhD, Nicole. Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organizations (Kindle Location 564). IT Revolution Press. Kindle Edition.

    Nhìn chung thì khi chúng ta cố gắng tăng tần suất deploy chúng ta sẽ có thể giảm MTTR, có nghĩa chúng ta sẽ không tạo ra một sản phẩm có tính bền vững cao (robustness — như cách tiếp cận truyền thống), khi đó khả năng tự phục hồi sau lỗi (resilience) của sản phẩm được tăng lên (một cách tự nhiên), cùng với đó là giảm khả năng xảy ra lỗi vì gần như khi tăng tần suất deploy đến hằng ngày hoặc nhiều lần một ngày sản phẩm sẽ gần như lúc nào cũng sẵn sàng để đưa lên môi trường production (production ready).

    Như vậy chúng ta sẽ có một mô hình:

    1. Continuous Integration:

      • Integration sớm và thường xuyên
      • Mọi người cần đồng bộ trunk (ý nói đến phiên bản được deploy) hằng ngày
    2. Continuous Deployment:

      • Điều này có để dễ dàng đạt được, khi source code ở trunk khá ổn định và Deploy chỉ là stage cuối cùng của Continuous Integration, như vậy việc phát hiện các lỗi và fix chúng cũng nhanh hơn, kể cả khi bạn có những thành viên không quá giỏi trong tay. Với các công cụ khác nhau như Sonarquebe hay chính Unit Test sẽ hỗ trợ developer tạo nên những sản phẩm tốt hơn.
    3. Continuous Delivery:

      • Sau 2 vấn đề bên trên source code ổn định, deploy thường xuyên, bản vá được xử lý nhanh chóng ít ảnh hưởng, cuối chùng chúng ta có một phần mềm luôn ở trạng thái sẵn sàng.

    Nhưng

    Có thể các bạn sẽ nghĩ hay có câu hỏi như này: Lỗi vẫn xảy ra thì sao?

    Ồ thì tất nhiên lỗi vẫn xảy ra, nhưng chúng ta sẽ có lỗi ở những thời điểm sớm hơn. Hầu hết mọi người sẽ gặp các vấn đề thường xảy ra khi chúng ta tích hợp (các thành phần trong phần mềm với nhau), điều này khá khó chịu, và mọi người sẽ có xu hướng trì hoãn. Tuy nhiên hãy nghĩ đến trường hợp này: trong ví dụ ở phần trước giả sử client cứ làm theo requirement hoặc UX/UI được cung cấp, backend thiết kế hoàn toàn khác tuy nhiên vẫn đầy đủ thông tin, client sẽ phải call nhiều API cho màn hình thay vì 1 API như trong suy nghĩ, điều đó dẫn đến việc một trong 2 cần thay đổi, việc này tốn khá nhiều công và tiềm ẩn rủi ro. Vậy nên khi tích hợp sớm chúng ta sẽ làm việc trơn tru trong quãng thời gian còn lại và sẵn sàng release thay vì dành vài tuần hoặc vài ngày cuối để thay đổi toàn bộ interface.

    Bring the pain forward

    Hay đầy đủ là if it hurts, do it more often, and bring the pain forward.

    image

    Quay lại vấn đề giữa mobile và backend, giả sử sẽ vẫn có những khác biệt về suy nghĩ xây dựng interface giữa 2 bên, tuy nhiên chúng ta đã làm nó sớm, và chia nhỏ nó ra và bằng cách backend thường xuyên release phiên bản API mới (chưa nói đến việc backward compatibility nhé), mobile sẽ tích hợp tốt hơn, nhanh hơn vì những thay đổi khá nhỏ và dễ dàng đáp ứng. Trong khi đó mobile team cũng build ra app thường xuyên hơn, tester có thể verify nhanh hơn, sản phẩm được ổn định hơn, ít tiềm ẩn lỗi hơn.

    Điều này khá giống trong lý thuyết phát triển phần mềm, chi phí sửa lỗi càng nhiều cho các lỗi ở giai đoạn muộn của dự án.

    Continuous Delivery bằng cách nào

    image

    Continuous Delivery cho chúng ta một cách tiếp cận khác về việc quản lý dự án, chúng ta có thể định nghĩa lại done không phải là code xong mà là được delivery thành công. Toàn bộ quá trình nên sử dụng đối đa các nền tảng tự động như Unit-test, Automation Test, điều đó làm tăng tốc độ feedback trên các bản vá của source code cũng như infrastructure. Điều này càng quan trọng hơn khi chi phí End-to-end testing càng ngày càng lớn, chúng nên được thay thế bằng các danh mục testing như dưới đây (multi-faceted testing portfolio), điều này càng quan trọng hơn trong thế giới hiện nay khi Devops là xu hướng, và các quyết định về release càng ngày càng gắn liên với tình huống về mặt nghiệp vụ thay vì sự quyết định của một đội quản lý về vận hành.

    Practice Quantity Frequency Duration Environment
    Unit Testing 100 to 1000+ Per build < 30s total Local and Build
    Acceptance Testing 10 to 100+ Per build < 10m total Local and Build
    Exploratory Testing 10 to 100+ Per build Timebox Local and 3rd Party
    Contract Testing ~20 Per 3rd party deploy < 1m 3rd Party
    Smoke Testing ~5 Per deploy < 5m All
    Monitoring 10 to 100+ Always < 10s All
    Anomaly detection 10 to 100+ < 1m < 10s All
    Adaptive architecture N/A Always N/A All

    Như vậy có thể thấy là việc xử lý Continuous Delivery gần như không mang tính kỹ thuật mà mang tính định hướng về văn hóa làm việc cho dự án nhiều hơn, chính vì thế tại sao mình lại đặt nó là Soft Skill.

  • Software Architecture: Bắt đầu từ đâu? – Part 2 Soft Skills – Decision

    Software Architecture: Bắt đầu từ đâu? – Part 2 Soft Skills – Decision

    Như ở phần trước mình đã nói về các Soft Skills mà mình cho là yếu tố khác biệt giữa Developer và Software Architecture.

    Decision

    Về cơ bản thì với vai trò là Software Architecture bạn sẽ cần quyết định nhiều thứ.

    Đầu tiên hãy kể đến chính Kiến trúc, thứ mà bạn đang xây dựng.

    Nếu bạn có vài trò là người quyết định kiến trúc, bạn gần như sẽ là người đảm bảo duy nhất cho sự toàn vẹn của hệ thống, về mặt khái niệm thôi nhé. Tức là bạn sẽ là người đầu tiên hình dung ra hình dáng của hệ thống và thông thường những quyết định kiểu này sẽ được đặt ra trong những phase đầu tiên của phần mềm.

    Nhiều người sẽ thắc mắc nếu quyết định đó là sai, thực tế thì những quyết định bởi những người có kinh nghiệm sẽ thường phù hợp với tình hình ở thời điểm đó.

    Một câu hỏi khác: tại sao chỉ một người đảm bảo duy nhất cho sự toàn vẹn? Thông thường ở một mức độ nào đó, trong một đội dự án, Architect sẽ có sự hiểu biết tốt nhất về hệ thống cũng như các hard skill khác, và họ sẽ có một cách hình dung khá chung với những người có trình độ tương đương. Tuy nhiên việc này sẽ dẫn tới việc nghẽn cổ chai ở Architect, vậy nên việc này sẽ dẫn tới một khái niệm khác là Architectural Knowledge Management hay Software Architecture Knowledge Management (điều này giải thích tại sao các team thường có wiki hay những bản tài liệu được chia sẻ về kiến thức) Read more

    Vậy thực sự có thể nói họ sẽ làm những việc như này

    • Thiết kế kiến trúc
    • Định ra các nguyên tắc để quyết định về mặt công nghệ.

    Ví dụ: Bạn sẽ cần đưa ra quyết định về việc sử dụng API Gateway để làm một endpoint duy nhất cho cả mobile và web hay sẽ sử dụng Backend for Frontend trong mô hình microservice.

    Ồ thì dẫn đến một điều bạn cứ trả lời 2 câu hỏi dưới đây bạn sẽ biết là bạn có đang đưa ra các quyết định về mặt kiến trúc hay không:

    • Mức độ ảnh hưởng có ở toàn hệ thống hay không? Độ khó để implement quyết định đó?
    • Quyết định đó có giúp team quyết định về mặt công nghệ hoặc chỉ định cho họ.

    Một công việc hằng ngày bạn có thể thấy mấy tên Architect hay làm đó là ngồi tìm hiểu thực sự bạn đang làm gì trong dự án, bạn có hiểu vấn đề chung của dự án hay không, tìm các vấn đề quan trọng và giải quyết trước khi mọi thứ trở nên tồi tệ (chỗ này định ghi là một bãi rác).

    Trong một dự án IoT gần đây mình có tham gia, Architect của dự án đã quyết định cho team backend dừng công việc để chỉnh trang lại kiến thực chung.

    Hoặc đơn giản hơn, Architect có thể ngồi với developer để tìm ra một số đoạn code gây lock hệ thống, buổi chiều có thể sharing với dự án về những thứ khá phi kỹ thuật như việc những đoạn code của họ sẽ gây ảnh hưởng đến chi phí AWS.

    Bạn có thể thấy rằng việc bạn không thể hình dung dự án đang làm ra sản phẩm như nào rất nguy hiểm, giả như rằng bạn khăng khăng bạn sẽ phải code lại toàn bộ luồng OAuth2.0 cho toàn bộ các microservice để dùng chung một endpoint, nhưng thực tế là hoàn toàn bạn có thể để chúng riêng rẽ, điều quan tâm duy nhất là dùng chung Identity Pool, việc làm đó có thể khiến những team khác trong dự án bị trễ lịch đến hàng tuần.

    Tính đúng đắn của quyết định — Justifying decisions

    Rõ ràng quyết định đã được đưa ra, điều đó là tất yếu trong hoàn cảnh đồng hồ của dự án bắt đầu tính giờ. Tuy nhiên thì không phải quyết định nào cũng được chấp nhận (chỉ là được chấp nhận nhé, chưa bàn đến tính đúng sai)

    Hãy quay trở lại ví dụ bên trên về API Gateway và Backend for Frontend, đây thực chất là kết quả sau khi Architect đã xem xét rõ ràng (đúng hoặc sai), còn quá trình thì sao.

    Để bất đầu hãy xem xét kịch bản tại sao lại có sự lựa chọn:

    Giả sử bạn đang xây dựng một cửa hàng trực tuyến sử dụng Microservice và bạn đang triển khai trang product detail. Bạn cần phát triển nhiều phiên bản của giao diện người dùng chi tiết sản phẩm: cho cả web browser dưới dạng HTML5 hoặc Rest API để phục vụ cho mobile.

    Giao diện này cần có nhiều thông tin: thông tin về sản phẩm, số lượng, lịch sử mua, các tùy chọn mua, các sản phẩm thường được mua cùng (một dang recommendation), review, rating của người bạn…

    Và chúng ta có các service sau:

    • Product Info Service
    • Pricing Service
    • Order service
    • Inventory service
    • Review service
    • Recommendation service Như vậy trang product detail cần tất cả các service trên

    Bài toán được đặt ra là:

    Làm cách nào để client của một ứng dụng Microservices truy cập vào các dịch vụ riêng lẻ?

    Quyết định

    Api Gateway

    Sử dụng API Gateway là entrypoint duy nhất cho tất cả các client. API Gateway xử lý các yêu cầu theo một trong hai cách.

    • Một số yêu cầu chỉ đơn giản là proxied/routed đến service thích hợp.
    • Hoặc thay vì cùng cấp API kiểu one-size-fits-all, API Gateway cung cấp các API khác nhau cho từng client. image

    Backend For Frontend

    BFF tạo ra các Gateway riêng rẽ cho từng loại Client. image

    Các điều kiện và ràng buộc (Conditions and Contraints)

    Có nhiều yếu tô cần tính tới trong trường hợp này, nhưng mình sẽ tạm thời bỏ qua những vấn đề mang tính chủ quan của một dự án phần mềm: Con người (mặt bằng chung của team, broken comb, T-Shaped, …), process, stakeholder (rất nhiều khách hàng can thiệp vào architecture), mặc dù trên thực tế Architect thường nắm vai trò Technical Lead luôn nên sẽ cần cân nhắc. Hãy đi vào vấn đề kỹ thuật thôi.

    • Thường thì API do microservices cung cấp thường khác với những gì Client cần, về chi tiết nhé. Microservices thường cung cấp các API chi tiết, có nghĩa là client sẽ cần tương tác với nhiều service. Ví dụ, như được mô tả ở trên, client cần thông tin chi tiết về sản phẩm và cần tới nhiều dịch vụ.
    • Các Client khác nhau sẽ cần dữ liệu khác nhau. Ví dụ phần Recommendation cho phiên bản web sẽ nhiều hơn và có nhiều hành động hơn phiên bản API cho Mobile.
    • Đường truyền điện thoại với 3G, 4G sẽ khác với các trình duyệt ở trên máy tính được kế nối qua cáp quang cả về băng thông lẫn tính ổn định, thậm chí là chi phí. Có nghĩa là chúng ta có thể tăng số lượng request từ phía trình duyệt mà không ảnh hưởng quá nhiều đến trải nghiệm của người dùng lẫn chi phí băng thông, ngược lại với ứng dụng mobile.
    • Số lượng phiên bản của service và thông tin (host:port) thay đổi động
    • Việc thay đổi các phiên bản của service (upgrade, canary) không nên transparent với client
    • Một số dịch vụ được integration và sử dụng gRPC, webservice hoặc SOAP không thân thiện lắm với các client hiện nay.

    Cân nhắc — Consideration

    Với API Gatway chúng ta sẽ có một API thân thiện với client với protocol tiêu chuẩn. Việc triển khai Client sẽ đơn giản hơn vì logic của việc xử lý nhiều service sẽ nằm ở Gateway thay vì client. Tuy nhiên dánh đổi bằng việc tăng độ phức tạp — API Gateway là một phần khác phải được phát triển, triển khai và quản lý, ngoài ra thời giản xử lý request cũng tăng lên vì thêm có bước xử lý network hop ở Gateway, tuy nhiên vân ngắn hơn thời gian xử lý cho BFF.

    Quyết định về kiến trúc — Architecture decision

    API Gateway

    Biện luận

    API Gatway với Spring có thể sử dụng Netflix Zuul, việc sử dụng Gateway sẽ đem đến trải nghiệm người dùng tốt hơn, vấn đề effort cho develop, deploy có thể giảm bằng cách đồng nhất cách thức xử lý cho các service sẽ đc xây dựng (dùng cùng một tech-stack)

    Tài liệu hóa và trao đổi về quyết định về kiến trúc

    Trao đổi về kiến trúc (giữa Architect và Developer)

    Trong dự án phần mềm của bạn có các kênh trao đổi nào?

    Email

    Email (đơn thuần là email) thực tế không thích hợp để trao đổi nhất là về mặt kỹ thuật, có quá nhiều vấn đề trong quá trình xây dựng kiến trúc và thông tin trong email khá khó để tổng hợp và truyền đạt lại, hãy nghĩ đến việc bạn sẽ cho một thành viên mới dành cả 2 tuần lễ để đọc lại thread mail.

    Hãy document quyết định về kiến trúc

    Sử dụng wiki là một biện pháp ổn, nhanh, giao diện đẹp, dễ viết với Markdown và quan trọng nhất là tập trung. Một vấn đề nữa, hãy chỉ rõ hoặc quyết định luôn chỗ mà quyết định được lưu trữ (hơi nhiều từ quyết định, tho)

    Với các vấn đề quan trọng và ảnh hưởng lớn, hãy đảm bảo tất cả mọi người cần biết được biết về nó. Bảng trắng luôn là một lựa chọn tốt để trao đổi, nếu trong thời buổi WFH có thể sử dụng các công cụ trong kênh giao tiếp.

    image

    P/S: hãy ra quyết định một cách khôn ngoan nhé.

    Happy Coding.

    to be continued sigange