Category: Common Knowledge

  • Thiết kế hệ thống

    Thiết kế hệ thống

    Một số suy nghĩ cá nhân về thiết kế hệ thống. Bài viết này chỉ muốn tạo ra một cái nhìn High-level về thiết kế hệ thống, để người đọc có thể cảm nhận được rằng: À, thực ra các hệ thống lớn cũng… chỉ có thế thôi, ez game.

    Đầu tiên, mọi hệ thống phức tạp đều được build từ những hệ thống nhỏ hơn, còn được gọi là các hệ thống con (sub-systems). Như vậy để thiết kế được hệ thống phức tạp thì cần hiểu những hệ thống con. Để hiểu được những hệ thống con thì không cách nào khác ngoài việc tự build những hệ thống con.

    Làm cách nào để ghép các hệ thống con lại với nhau thành một hệ thống phức tạp hơn !? Để làm được điều đó, trước hết cần hiểu các giao thức mạng (Protocols), sau đó là các mô hình truyền thông điệp/giao tiếp giữa các máy chủ ứng dụng.

    Có một số mô hình giao tiếp phổ biến, hầu hết chúng ta đều tiếp cận với mô hình Synchronous trước, hay còn gọi là mô hình Request-Response. Phần lớn sinh viên đại học dừng ở mức này, nhưng như thế là đủ, bởi sinh viên cần quan tâm hơn đến các kiến thức nền tảng.

    Tuy nhiên, các hệ thống hiện nay quá phức tạp, phần lớn workloads là Asynchronous thay vì Synchronous. Chính vì vậy, việc học các mô hình giao tiếp Asynchronous là cần thiết, một số mô hình phổ biến như: Push model, Polling model,… Messgages Broker và Event-bus là hai khái niệm phổ biến trong các hệ thống xử lý Asynchronous workloads. Chúng về bản chất chỉ là 1 layer trung gian giúp de-coupling các hệ thống con với nhau.

    Sau khi nắm được sơ sơ về các building blocks rồi thì chúng ta có xu hướng thiết kế theo “khuôn mẫu” –> Architecture Patterns ra đời. Việc học Architecture Patterns có 2 ý nghĩa: (i) thứ nhất giúp chúng ta build các hệ thống phức tạp nhanh hơn bởi những mẫu sẵn có, và (ii) giúp chúng ta hiểu nhanh hơn về cách giao tiếp giữa các hệ thống con với nhau, bởi con người có xu hướng thích làm theo mẫu (có thằng khác chứng minh rồi)

    Tóm lại, nếu nắm được các building blocks kể trên thì kể ra trên đời này không có hệ thống phức tạp nào là không làm được :)))

    p/s: Bốc phét vậy thôi chứ mình vẫn đang tiếp cận ở High-level, cần nghiên cứu nhiều hơn về networking protocols ? Viết bài là một cách học của mình :))) 

  • Code sướng tay: Bước 2

    Code sướng tay: Bước 2

    Hi, hôm nay mình lại tiếp tục xàm xí đâyyy. Hôm nay sẽ lại tiếp tục về chuyện đặt tên và thêm về cách viết hàm. Hãy bắt đầu với 1 câu nói sến súa nào :3

    Programs must be written for people to read, and only incidentally for machines to execute.

    (Đại khái là code viết cho người đọc, chỉ là vô tình máy chạy được thôi)

    Abelson and Sussman

    Và để người đọc được thì sao không viết code một cách có-thể-đọc-được nhỉ?

    // Kiểu như này
    // "If errors is empty..."
    if (errors.isEmpty) ...
    
    // "Hey, subscription, cancel!"
    subscription.cancel();
    
    // "Get the monsters where the monster has claws."
    monsters.where((monster) => monster.hasClaws);
    // Thay vì như này
    // Telling errors to empty itself, or asking if it is?
    if (errors.empty) ...
    
    // Toggle what? To what?
    subscription.toggle();
    
    // Filter the monsters with claws *out* or include *only* those?
    monsters.filter((monster) => monster.hasClaws);

    Tuy nhiên đừng cố gắng để nó quá dễ đọc đến mức như đang nói, điều này làm code rườm rà và trở nên khó đọc hơn bao giờ hết!

    // has gone too far
    if (theCollectionOfErrors.isEmpty) ...
    
    monsters.producesANewSequenceWhereEach((monster) => monster.hasClaws);

    Cách đặt tên cho câu hỏi yes/no

    Tên trả lời cho câu hỏi yes/no thường được dùng làm các điều kiện rẽ nhánh, so sánh 2 cách viết sau:

    if (window.closeable) ...  // Adjective.
    if (window.canClose) ...   // Verb.

    Chúng ta có thể đặt tên như sau:

    • Bắt đầu với “to be”isEnabledwasShownwillFire. Đây là cách phổ biến nhất (window.closeable cũng có thể được đặt là window.isCloseable)
    • Sử dụng trợ động từhasElementscanCloseshouldConsumemustSave.
    • Các động từ thông thường không hay được dùng trong TH này

    Chúng ta có thể đặt tên bắt đầu với những động từ này mà không bị nhầm lẫn với các hàm do nó không phải là các động từ mệnh lệnh.

    // Nên đặt như này
    // Tuy nhiên, trong một số trường hợp
    // bỏ qua các tiền tố yes/ no này mà nghĩa vẫn rõ ràng thì nên bỏ đi
    isEmpty
    hasElements
    canClose
    closesWindow
    canShowPopup
    hasShownPopup
    // Chứ không phải là như này
    empty         // Adjective or verb?
    withElements  // Sounds like it might hold elements.
    closeable     // Sounds like an interface.
                  // "canClose" reads better as a sentence.
    closingWindow // Returns a bool or a window?
    showPopup     // Sounds like it shows the popup.

    Tiếp theo là về việc lùi dòng và độ phức tạp của code trong phạm vi hàm. Mỗi lần bạn lùi vào 1 tab, vậy là code của bạn đã phức tạp và tốn công sức để đọc thêm 1 bậc. Mình rất thích đọc và xử lí hết lỗi trong tab Problems này cho đến khi nó hiện lên dòng chữ như vầy:

    Không còn lỗi nữa~

    Và khi mình code js, đã có rất nhiều cảnh báo bắn ra pằng pằng khi mình code của mình quá dài, nó sẽ yêu cầu mình tách hàm ra (tính ra IDE giúp được rất nhiều, nó còn có thể detect các đoạn code giống nhau mà mình copy paste sau đó bảo mình tách hàm đi bạn ơi~). IDE sẽ cảnh báo khi bạn lùi vào quá nhiều và yêu cầu bạn refactor code. IDE làm vậy không phải vì nó không đọc được code của bạn, mà vì nó sợ sau này bạn sẽ không đọc được code của bạn đấy :P. Vậy tại sao trong 1 hàm lại cần tab vào nhiều đến thế? Đó là vì hàm đó đang cố gắng làm quá nhiều việc.

    Có một nguyên lí rất nổi tiếng trong giới lập trình viên, gọi là Single Responsibility Principle (nguyên lí đơn nhiệm). Nguyên lí này khi áp dụng cho một hàm thì có nghĩa là: 1 hàm chỉ nên làm 1 việc. Đôi khi 1 việc này sẽ hơi tốn code, nhưng trong hầu hết các trường hợp (nếu không phải bạn đang thực thi một thuật toán gì đó phức tạp) thì nó sẽ có thể viết trong chiều dài màn hình của bạn, và không quá 3 lần tab vào (theo ý kiến của mình, hoặc số lần tab vào này có thể phụ thuộc vào trí nhớ của bạn nhưng với mình 4 là quá nhiều để nhớ, nếu mỗi lần tab vào đi kèm 1 điều kiện thì đã có 16 trường hợp nhỏ nhất đang chờ được mình duyệt qua T_T). Có 1 tip nhỏ để giảm bớt độ phức tạp lùi dòng, đó là sử dụng early return (1 lần duy nhất) trong hàm của bạn. Điều này sẽ giảm tab complexity xuống 1 level rồi đó :3

    Early Return (thoát sớm)

    Tuy nhiên, không phải lúc nào chúng ta cũng nên chia ra quá nhiều hàm với 1 đống param đi kèm, điều này sẽ tạo ra rất nhiều các hàm ăn bám (hàm chỉ dùng được duy nhất 1 lần cho 1 hàm khác) và thừa thãi. Hãy tách hàm sao cho hợp lí để dễ dàng đọc (và đôi khi là dùng) chúng nhé :3

    Chúc mọi người sẽ code sướng cái tay và đọc code sướng con mắt hehe. À với Tết rồi nên chúc ai đọc bài viết này sẽ đẹp trai/xinh gái, nhiều tiền, nhiều sức khoẻ, vui vẻ, hạnh phúc và không bị đồng nghiệp (hoặc sếp) chửi vì code lởm ạ.

    Tham khảo:

    https://dart.dev/guides/language/effective-dart/design

    https://stackoverflow.com/questions/475675/when-is-a-function-too-long

  • Nghiên cứu

    Nghiên cứu

    Nghiên cứu

    Thi thoảng mình nhận được một số câu hỏi của bạn bè, trong đó có câu: Mày làm Nghiên cứu hay Ứng dụng ??

    Mình trộm nghĩ, nếu nói tao làm nghiên cứu thì chỉ đúng một phần mà nói tao làm ứng dụng thì cũng chỉ đúng được một phần. Nên tấu hài rằng: “Tao làm nghiên cứu ứng dụng”. Kể ra cũng… hợp lý ?

    Mình luôn tự coi bản thân là (hoặc cố gắng để trở thành) một Kỹ sư phần mềm, bấy lâu nay mình vẫn luôn nghĩ vậy. Và khi gặp một vấn đề kỹ thuật khó, thì một Kỹ sư bắt buộc (hoặc cần) phải có năng lực nghiên cứu giải pháp. Lấy ví dụ, mình đang cần phát triển và triển khai 1 mô hình Machine Learning (nhẹ, không cần GPU) và 1 mô hình Deep Learning (nặng, có thể cần GPU) trên môi trường AWS; yêu cầu Kỹ thuật đặt ra là tối thiểu việc vận hành hạ tầng cũng như việc Update mô hình khi cần thiết –> có rất nhiều solutions khác nhau –> cần Re-search. Một vài phân tích đơn giản như; do business mà các hệ thống này ít được sử dụng thường xuyên –> chúng ta nên dùng Serverless để tối ưu chi phí (hoặc Spot instance); với hệ thống Machine Learning, do đặc điểm nhẹ, suy diễn nhanh –> có thể sử dụng AWS Lambda –> đến đây cần nghiên cứu cách sử dụng Aws Lambda sao cho hiệu quả (bởi một số giới hạn Package size) –> cần thực nghiệm các giải pháp khác nhau: Lambda layers, Elastic File System, Docker Image,… Một ví dụ khác là thằng bạn mình loay hoay tìm cách Crawl hết sản phẩm của các trang thương mại điện tử, rồi tìm cách lưu trữ và sử dụng sao cho hiệu quả,… cũng phải mất khá nhiều thì giờ để Re-search (search đi search lại).

    Tóm lại, mình nghĩ đơn giản Nghiên cứu (hay Research) tức là “search đi search lại”. Không cứ phải phát minh ra một cái vĩ đại, chưa ai làm mới là Nghiên cứu, mà đơn giản chỉ cần giải quyết đúng bài toán mà mình gặp phải… đó cũng có thể gọi là nghiên cứu được chứ nhỉ ? Nghiên cứu thường đi kèm với năng lực phân tích vấn đề, bởi chỉ có phân tích thì chúng ta mới chỉ ra được ưu nhược điểm của giải pháp, tại sao nó lại phù hợp với bài toán của mình. Chính nhờ sự nghiên cứu mà năng lực, kỹ năng của Kỹ sư tăng lên –> qua đó sẽ có khả năng phán đoán, quyết định giải pháp tốt hơn, nhạy bén hơn –> Thu nhập cao hơn ?

    Technologies come and technologies go, but insight is forever.

  • Code sướng tay: Bước 1

    Có một vấn đề mà ai code cũng cần làm, đó là đặt tên (cho lớp, hàm, biến…).

    Ai cũng có thể viết code máy hiểu được, nhưng chỉ số ít viết code mà người hiểu được.

    “I’m not a great programmer, I’m just a good programmer with great habits.”

    Martin Fowler (tác giả sách Refactoring)

    Hồi còn đi học, chúng ta hay làm toán và đặt tên các biến là x,y,z,t… các hằng là a,b,c,…m,n…. Chúng ta hay giải lí với các biến là U, I, g, … Tương tự với các môn cần đến toán như hóa, sinh… Và tin học cũng là một môn dùng đến toán như vậy. Chúng ta tiếp tục lặp lại những gì mình từng biết:

    int a, b, c;

    float x, y, z;

    double aa, bb, xx, yy;

    Đặt những cái tên mà chúng ta thấy là đúng đắn, nhưng trông thật vô nghĩa. Trước mình cũng code rất nhiều những thuật toán, mà giờ đọc lại, không còn hiểu được ngày xưa mình code gì thế này, hàm này để làm gì, giải quyết bài toàn gì? Đừng đặt cho biến của bạn những cái tên quá ngắn như thế, vì nó chẳng thể hiện được tí ý nghĩa nào của biến đó hết.

    Đố ai hiểu code đang nghĩ gì :v

    Sau một chút thì mình học được cách thêm comment vào code để dễ hiểu hơn, như thế này:

    code cùng một chút comment (l=left, r=right)

    Tuy nhiên, sau này mấy anh khóa trên đi làm xong đến lớp bảo: “Ở công ty code giờ về lớp code nhìn cứ ngứa mắt. Đi làm code là tên biến nó cứ dài dài cơ. Càng dài càng tốt ae nhề, dài nhìn mới thuận mắt (nói với mấy anh cùng đi làm).” Lúc đấy mình cũng cười trừ thôi, vì thấy code của mình đọc dễ hiểu lắm rồi, đặt tên dài làm gì đâu. Hồi đó mình còn học các cách để rút gọn/ viết tắt tên biến như là lấy chữ cái đầu, bỏ đi nguyên âm, lấy 3 kí tự đầu… Mãi sau mới thấy, IDE gợi ý đến tận răng, tiếc gì mấy phím gõ mà phải học viết tắt quá mức như vậy nhỉ (thật ra học cái này cũng hữu ích khi mà đọc code người khác họ viết lst còn biết là list chả hạn .-.) Đừng cố gắng viết tắt tên biến, trừ khi là những từ viết tắt mà ai cũng biết và hiểu rõ.

    Hóa ra là, hàng tốt thì không cần quảng cáo, code tốt thì không cần comment, tự những cái tên trong code cần phải làm việc của nó khiến đoạn code dễ đọc, dễ hiểu (trừ những logic phức tạp và khó hiểu). Khi tên một hàm thể hiện nó làm gì, người ta sẽ không cần đọc đến đoạn code bên trong nó nữa. Trong cuộc đời 1 coder, thời gian đọc code luôn nhiều hơn thời gian viết ra nó (vì code thường sẽ cần được sửa), nên nếu đặt một cái tên tốt, sau này đọc lại bạn sẽ đỡ áp lực hơn khi đọc lại code của chính mình (và đỡ muốn đấm bản thân hơn, đỡ mất thời gian đọc comment, đỡ phải vò đầu bứt tai suy nghĩ ôi cái đoạn code này dùng để làm gì thế nhỉ).

    Nếu biến của bạn có đơn vị, hãy cố gắng thêm đơn vị vào tên của nó. Ví dụ thay vì hàm startAnimation(int delayTime) hãy đặt là startAnimation(int delayTimeInSeconds) hoặc nếu tốt hơn nữa, hãy thay kiểu của nó thành một kiểu mà sẽ khó bị nhầm lẫn, ví dụ như Duration trong Dart, bạn sẽ không cần quan tâm đến đơn vị của nó nữa. Khi code, nếu bạn phát hiện ra một cái tên khó hiểu hoặc dễ hiểu lầm và bạn có thể đặt cho nó cái tên tốt hơn, hãy đổi nó ngay khi bạn có thể (miễn là nó không ảnh hưởng tới đồng nghiệp của bạn, nếu có ảnh hưởng, bạn có thể hỏi ý kiến họ trước hoặc thêm một chút comment để sau này không tốn thời gian quá nhiều để hiểu nó nữa). Nhỏ thôi nhưng sẽ khiến bạn của sau này phải cảm ơn bạn đấy :3

    Một số cách đặt tên mà bạn nên tham khảo:

    • Nên dùng tiếng anh để đặt tên vì hầu hết các kí hiệu trong code đều là tiếng anh và tiếng anh không dễ bị nhầm lẫn như tiếng việt không dấu
    • Tuân thủ nguyên tắc đặt tên của ngôn ngữ/ dự án mà bạn làm
    • Đặt tên cho hàm bằng các động từ, cho các lớp bằng danh từ
    • Chỉ sử dụng biến bắt đầu bằng is/ are/ has… để đặt cho các biến/ thuộc tính/ hàm trả lời cho câu hỏi yes/no
    • Khi bạn không nghĩ ra được một cái tên cho biến/hàm/lớp bạn cần vì nó dễ bị nhầm lẫn với những biến/hàm/lớp khác, đây là lúc nên đặt lại tên cho cả những biến/hàm/lớp khác kia (chứ đừng thay bằng một từ đồng nghĩa, điều này sẽ khiến mọi người bối rối vì không biết chúng khác nhau ở đâu .-.)

    Tóm tắt các nguyên tắc:

    1. Tuân thủ convention đặt tên của ngôn ngữ/dự án đang làm
    2. Tên biến nên thể hiện ý nghĩa của nó, đừng cố gắng viết tắt nó
    3. Tham khảo một số nguyên tắc chung

    Lần đầu viết bài, mong là sẽ có lần sau hehe~

  • Hướng dẫn cách Gen Document Design bằng code Python

    Hướng dẫn cách Gen Document Design bằng code Python

    Hi các bạn, có bao giờ các bạn gặp phải tình huống khi kết thúc dự án thì phải làm Document design cho dự án của mình? Yêu cầu phải liệt kê hết các func trong project ra file excel và giải thích nó làm gì. Nếu câu trả lời là có thì các bạn có thể đọc tiếp bài viết này để xem cách thực hiện nó như thế nào nhé.

    Yêu cầu

    • Cần liệt kê hết tất cả các func trong souce code và giải thích func đó dùng để làm gì
    • Định dạng yêu cầu theo file excel

    Chuẩn bị

    Do tool được code trên nền tảng python nên mọi người cần cài đặt Python3 trước để có thể thực hiện gen document. Để cài đặt thì mọi người có thể làm theo hướng dẫn sau:

    1. Homebrew

    Link tham khảo: https://brew.sh v/bin/bash -c “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)”

    2. Install Python 3 on Mac – Brew Install

    Link tham khảo: https://www.freecodecamp.org/news/python-version-on-mac-update/ vbrew install pyenv // Install vpyenv install 3.9.2 // Update version

    3. Install pip: pip la một package của Python

    Link tham khảo: https://pip.pypa.io/en/stable/

    Download get-pip.py provided by https://pip.pypa.io hoặc sử dung terminal: vcurl https://bootstrap.pypa.io/get-pip.py -o get-pip.py vsudo python3 get-pip.py

    4. Openpyxl install: Cài đặt openpyxl sử dụng pip.

    Link tham khảo: https://openpyxl.readthedocs.io/en/stable/ vsudo pip install openpyxl

    5. Tải sẵn file template ở đây:

    File design là file excel template
    File DocC+.py là file code python nhằm mục đích gen gen souce và update file excel.

    NOTE: Đây là code dùng để gen dự án sử dụng ngôn ngữ lập trình swift, nếu các bạn cần gen trên ngôn ngữ khác chúng ta sẽ cần thực hiện chỉnh sửa file DocC+.py cho phù hợp với ngôn ngữ mà bạn sử dụng.

    Hướng dẫn sử dụng

    Bước 1: Copy file DocC+.py và design.xlsx vào trong thư mục cần gen.

    Bước 2: Bật Terminal -> navigate đến project folders chữa file DocC+.py

    Bước 3: Chạy câu lệnh dưới đây: python3 DocC+.py

    Vậy là chúng ta đã gen xong file liệt kê tất cả các func có trong thư mục mà các bạn chọn. Rất nhanh gọn và tiện lợi đúng không?

    Ưu điểm

    • Tiết kiệm rất nhiều thời gian thực hiện, thay vì phải copy bằng tay mất rất nhiều thời gian và khiến người thực hiện khá stress thì tool giúp chúng ta làm nó trong vài phút
    • Có thể sử dụng cho tất cả các ngôn ngữ lập trình
    • Quá dễ sử dụng

    Tổng kết

    Vậy là bài viết trên mình đã giới thiệu, chia sẻ và hướng dẫn các bạn sử dụng một tool cực kì hữu dụng và dễ sử dụng. Mình hi vọng nó sẽ giúp các bạn giải quyết bài toán mà bạn gặp phải. Chúc các bạn thành công!

  • Lottie Animation: Biến hình màn hình Login của bạn

    Lottie Animation: Biến hình màn hình Login của bạn

    Hi mọi người, ở bài viết trước mình đã hướng dẫn các bạn cách làm sao để thêm và ứng dụng Lottie vào ứng dụng của bạn. Có thể khi đọc bài viết trước các bạn sẽ chưa hình dung được sức mạnh của Lottie Animation. Để chứng minh sức mạnh của Lottie Animation hôm nay mình sẽ hướng dẫn các bạn ứng dụng nó vào màn hình Login và biến nó trở thành 1 màn hình thú vị hơn. Để hiểu rõ hơn về cách cài đặt Lottie animation bạn có thể xem lại bài viết Hướng dẫn cách sử dụng Lottie Animation trong Swift

    Chuẩn bị

    Để có thể bắt đầu dễ dàng và nhanh chóng hơn thì chúng ta cần chuẩn bị sẵn những thứ sau:

    1. Kiến thức về Lottie, tham khảo tại đây
    2. Project demo các bạn tải tại đây

    Bắt đầu

    Đầu tiên chúng ta sẽ kéo UI vào để thực hiện thay đổi màn hình Login như sau:

    Trong màn hình Login của chúng ta sẽ có các thành phần sau:

    1. ImageView làm background cho ứng dụng
    2. 2 Lottie Animation View, 1 cái làm thành phần chính nằm trên nửa màn hình và một cái nằm ở góc nhằm trang trí thêm cho màn hình
    3. 2 UITextField để cho người dùng nhập user name và password
    4. 1 button Login

    Sau khi sử dụng interface builder thực hiện kéo các view vào màn hình thì các bạn kéo reference cho các item vào view controller để thực hiện code.

    Mở ViewController lên và import Lottie

    import UIKit
    import Lottie

    Viết thêm một số func để cài đặt lottie và cài đặt view như sau

    extension ViewController {
        func setupUI() {
            tfAccount.layer.borderWidth = 1
            tfAccount.layer.borderColor = UIColor.orange.cgColor
            tfAccount.backgroundColor = UIColor.orange.withAlphaComponent(0.2)
            tfAccount.layer.cornerRadius = 5
            tfAccount.attributedPlaceholder = NSAttributedString(string: "  Account",
                                                                 attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
            tfAccount.placeholderRect(forBounds: CGRect(x: 5, y: 5, width: 100, height: 44))
            tfPassword.layer.borderWidth = 1
            tfPassword.layer.borderColor = UIColor.orange.cgColor
            tfPassword.backgroundColor = UIColor.orange.withAlphaComponent(0.2)
            tfPassword.layer.cornerRadius = 5
            tfPassword.attributedPlaceholder = NSAttributedString(string: "  Password",
                                                                 attributes: [NSAttributedString.Key.foregroundColor: UIColor.white])
            btnLogin.layer.cornerRadius = 5
            loadingView.backgroundColor = UIColor.black.withAlphaComponent(0.4)
        }
        
        func setupLottie() {
            // 1. Set animation content mode
            animationLottieView.contentMode = .scaleAspectFit
            animationLottieView2.contentMode = .scaleAspectFit
    
            // 2. Set animation loop mode
    
            animationLottieView.loopMode = .loop
            animationLottieView2.loopMode = .loop
    
            // 3. Adjust animation speed
    
            animationLottieView.animationSpeed = 0.5
            animationLottieView2.animationSpeed = 0.5
    
            // 4. Play animation
            animationLottieView.play()
            animationLottieView2.play()
        }
        
        private func showLoading() {
            // 1. Create lottie animation view
            let lottieView: LottieAnimationView = LottieAnimationView(name: "loading_crypto")
            lottieView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
            
            // 2. Set animation content mode
            lottieView.contentMode = .scaleAspectFit
            
            // 3. Set animation loop mode
            lottieView.loopMode = .loop
            
            // 4. Adjust animation speed
            lottieView.animationSpeed = 0.5
            
            loadingView.addSubview(lottieView)
            lottieView.center = CGPoint(x: UIScreen.main.bounds.width / 2, y:  UIScreen.main.bounds.height / 2)
            view.addSubview(loadingView)
            // 5. Play animation
            lottieView.play()
            
        }
        
        @objc private func hideLoading() {
            loadingView.subviews.forEach { $0.removeFromSuperview() }
            loadingView.removeFromSuperview()
        }
    }

    Thêm loading view để thực hiện màn hình loading như sau

    class ViewController: UIViewController {
        @IBOutlet weak var tfAccount: UITextField!
        @IBOutlet weak var tfPassword: UITextField!
        @IBOutlet weak var animationLottieView: LottieAnimationView!
        @IBOutlet weak var btnLogin: UIButton!
        @IBOutlet weak var animationLottieView2: LottieAnimationView!
        
        private var loadingView: UIView = UIView.init(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            setupUI()
            setupLottie()
        }
        
        @IBAction func login(_ sender: Any) {
            showLoading()
            perform(#selector(hideLoading), with: nil, afterDelay: 5)
        }
    }

    ở viewDidLoad chúng ta sẽ thực hiện setUpUI và setup lottie, tại func login chúng ta sẽ thực hiện showLoading và để nó ẩn đi sau 5 giây.

    Bây giờ chúng ta thực hiện cmd + R để chạy ứng dụng, kết quả thu được sẽ như sau:

    Kết quả thật tuyệt vời đúng không? Đối với các màn hình có animation phức tạp như vậy để code sử dụng animation gần như ta quá phức tạp và tốn quá nhiều effort để thực hiện, tuy nhiên nếu dùng lottie các bạn chỉ mất một chút thời gian để căn chỉnh layout.

    Vậy là chúng ta đã hoàn thành việc ứng dụng Lottie vào màn hình Login để tăng trải nghiệm của người dùng. Ngoài ra chúng ta còn có thể ứng dụng Lottie vào rất nhiều các tính năng khác để ứng dụng trở nên thú vị hơn. Ví dụ như: Màn hình launch screen với animation logo, animation trên notification, animation Tabbar icon, v.v.

    Cách sử dụng Lottie phụ thuộc rất lớn vào trí tưởng tượng và óc sáng tạo của người dùng, nếu bạn chỉ nắm vai trò là front end developer nhiều khi bạn sẽ không có quyền quyết định ứng dụng sẽ như nào, nhưng nếu bạn có ý tưởng hay ho bạn có thể đưa ý kiến lên Team leader, designer, BA, và PM của dự án để cải thiện trải nghiệm của người dùng.

    Chúc các bạn thành công với các dự án sắp tới.

  • Hướng dẫn cách sử dụng Lottie Animation trong Swift

    Hướng dẫn cách sử dụng Lottie Animation trong Swift

    Có lẽ tất cả mọi người trên thế giới đều yêu thích cái đẹp và mình cũng không ngoại lệ. Việc xây dựng những ứng dụng có UI đẹp mắt, animation mượt mà và thú vị khiến hàng triệu người dùng trầm trồ là mong muốn của rất nhiều những Developer trên toàn thế giới. Là một developer nếu bạn có tìm thấy bài viết này của mình thì chắc hẳn bạn cũng có khát khao làm những điều thú vị cho ứng dụng của mình có đúng không? Vậy chúng ta cùng đi tiếp vào bài viết này để làm cách nào để có thể làm ứng dụng của các bạn trở nên thú vị hơn nhé.

    Trong một dịp mình có cơ hội làm việc trong một dự án có sử dụng rất nhiều Animation để làm cho ứng dụng trở nên đẹp và thú vị hơn với người dùng. Lúc mới vào dự án khi sử dụng một số tính năng có sử dụng animation làm mình thấy rất hứng thú, thật khó để cưỡng lại sự đẹp đẽ và hoa mỹ của nó. Trong khi làm việc trong dự án thì mình cũng đã phát hiện ra một thư viện hỗ trợ cho việc thực hiện animation rất hay đó chính là Lottie. Vì vậy ngày hôm nay mình muốn chia sẻ với các bạn về thư viện này và cách thêm nó vào ứng dụng của các bạn.

    Lottie là gì?

    Lottie là định dạng tệp hoạt hình dựa trên JSON cho phép các nhà thiết kế gửi animation trên bất kỳ nền tảng nào dễ dàng như vận chuyển nội dung tĩnh. Bạn có thể đọc thêm về nó ở đây.

    Lottie được sử dụng khi nào?

    Lottie khá là linh hoạt và nó có thể sử dụng được trên nhiều nền tảng khác nhau từ iOS, Android, Web …. Vì vậy nó giúp đồng bộ animation trên tất cả các nền tảng mà không xảy ra sai sót nào.

    Lottie hỗ trợ làm animation rất tốt, nó có thể làm được những animation rất phức tạp mà việc code animation không thể làm được hoặc làm đơn giản hoá việc thêm animation vào trong ứng dụng.

    Hiện nay nó đang được sử dụng khá phổ biến trên các ứng dụng.

    Làm sao để sử dụng Lottie cho ứng dụng của bạn?

    Bước 1: Tạo dự án mới

    Nếu bạn muốn thêm vào dự án có sẵn của mình thì bỏ qua bước này nhé.

    Đầu tiên chúng ta mở Xcode lên và tạo một ứng dụng demo để có thể test Lottie chạy trên ứng dụng một cách dễ dàng hơn.

    Tạo ứng dụng mới

    Bước 2: Thêm thư viện Lottie vào ứng dụng

    Để thêm thư viện Lottie vào ứng dụng chúng ta có thể sử dụng bằng nhiều cách khác nhau như Cocoa Pods, Carthage hoặc Swift Package Manager. Nếu bạn chưa biết cách thêm thư viện Lottie vào dự án thì bạn có thể tham khảo hướng dẫn tại đây.

    Ở bài viết này mình sẽ hướng dẫn các bạn sử dụng Swift Package Manager để thêm vào ứng dụng như sau:

    Bạn mở dự án của bạn trên Xcode, chọn File -> Add Packages… Trên đầu bên phải của popup hiện ra có công cụ tìm kiếm các bạn đánh link: https://github.com/airbnb/lottie-ios.git để tìm thư viện. Sau đó bấm vào Add Package và chờ một lúc để Xcode tải thư viện bạn, sau khi tải xong bạn bấm Add để hoàn tất

    Bước 3: Thêm Lottie vào dự án

    Đầu tiên chúng ta cần chuẩn bị file Lottie JSON, nếu bạn chưa có thì bạn có thể download nó tại đây. Bạn nhớ tải file JSON nhé.

    Bạn cũng có thể sử dụng ứng dụng Adobe After Effect để tạo file Lottie của riêng mình.

    Khi đã có file lottie JSON rồi chúng ta sẽ thực hiện thêm file vào trong dự án bằng cách kéo thả nó trực tiếp vào thư mục trong Xcode của bạn, tại nơi mà bạn muốn lưu nó. Thông thường chúng ta tạo mới thư mục Resouces/LottieJSON và lưu nó trong đó.

    Add file lottie vào dự án

    Hãy nhớ bạn tích Copy Items if needed và các mục như trên hình nhé.

    Thêm Lottie bằng cách sử dụng code

    Đầu tiên để sử dụng được thư viện Lottie hãy nhớ import thư viện Lottie vào màn hình mà bạn sử dụng

    import Lottie

    Tiếp theo chúng ta tạo func addLottieAnimation() để thực hiện nhiệm vụ add lottie vào view hiện tại. Bạn cũng có thể custom một func riêng để handle xử lí triệt để các logic của Lottie animation. Trong bài này mình chỉ hướng dẫn cơ bản để các bạn có thể thêm Lottie vào ứng dụng của mình.

        func addLottieAnimation() {
            // 1. Create lottie animation view
            let lottieView: LottieAnimationView = LottieAnimationView(name: "404-Notfound")
            lottieView.frame = view.bounds
            
            // 2. Set animation content mode
            lottieView.contentMode = .scaleAspectFit
            
            // 3. Set animation loop mode
            lottieView.loopMode = .loop
            
            // 4. Adjust animation speed
            lottieView.animationSpeed = 0.5
            
            view.addSubview(lottieView)
            
            // 5. Play animation
            lottieView.play()
        }

    Sau đó bạn call func này ở viewDidLoad thì sẽ nhận được kết quả như sau:

    Thêm Lottie bằng cách sử dụng Builder Interface

    Đầu tiên bạn mở file giao diện của bạn lên băng Interface Builder, kéo một UIView và thực hiện constraint cho nó.

    Thêm UIview vào để sử dụng Lottie

    Sau đó ở trên cùng của tab bên phải bạn chọn Identity Inspector và thay đổi giá trị như hình dưới

    Thay đổi class sang LottieAnimationView

    Tiếp tục chuyển sang tab Attributes Inspector để điền tên file Lottie mà bạn muốn

    Tạo một liên kết giữa view của bạn với file controller để sử dụng, sau đó bạn thực hiện code như dưới đây để Lottie có thể hoạn động.

    import UIKit
    import Lottie
    
    class ViewController: UIViewController {
        @IBOutlet weak var animationLottieView: LottieAnimationView!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            // 1. Set animation content mode
            animationLottieView.contentMode = .scaleAspectFit
    
            // 2. Set animation loop mode
    
            animationLottieView.loopMode = .loop
    
            // 3. Adjust animation speed
    
            animationLottieView.animationSpeed = 0.5
    
            // 4. Play animation
            animationLottieView.play()
        }
    }

    Chạy ứng dụng và bạn sẽ nhận được kết quả như mong đợi!

    Vậy là mình đã giới thiệu và hướng dẫn cho các bạn một thư viện khá hiệu quả cho các bạn sử dụng để bổ trợ cho các bạn việc thực hiện animation tốt hơn, dễ dàng hơn, và nhanh hơn so với cách code truyền thống. Từ giờ các bạn có thể tha hồ sáng tạo trên những ứng dụng sắp tới của bản thân và khiến mọi người sử dụng thích thú.

    Mình hi vọng nó sẽ giúp các bạn làm ra những ứng dụng có trải nghiệm tuyệt vời, giúp những người sử dụng ứng dụng của các bạn phải trầm trồ khi sử dụng nó. Chúc các bạn thành công với những dự án sắp tới của mình.

  • Architecture Pattern: VIPER trong iOS

    Architecture Pattern: VIPER trong iOS

    Xin chào các bạn, lại là DaoNM2 đây! Để tiếp tục series về Architecture patterns thì hôm nay mình xin giới thiệu cho các bạn một mẫu kiến trúc được sử dụng khá nhiều khi phát triển các ứng dụng di động đó là VIPER.

    VIPER là gì?

    VIPER là một mẫu kiến trúc để phát triền phần mềm, nó được sử dụng khá nhiều khi xây dựng các ứng dụng di động trên ngôn ngữ lập trình Swift. Nó được xây dựng dựa trên Clean Design Architecture. Các Modules trong VIPER được định hướng theo Protocol và mỗi chức năng, các thuộc tính input và output được thực hiện bằng các bộ quy tắc giao tiếp cụ thể.

    Các thành phần chính của VIPER architecture pattern

    VIPER là viết tắt của các chứ cái đầu trong các thành phần của nó, nó bao gồm View, Interactor, Presenter, Entity và Router. Các thành phần này sẽ tương tác với nhau như sơ đồ dưới đây:

    View

    Bao gồm các thành phần trong UIKit và ViewController, nó là nơi để hiển thị nội dung cho người dùng và nhận các tương tác từ người dùng sau đó gửi cho presenter để xử lí tiếp logic hiển thị. Trong mẫu kiến trúc này Presenter là tầng duy nhất có liên kết với View.

    Interactor

    Là nơi xử lý business logic của ứng dụng, nó sẽ thao tác với Entity, model, API fetcher và datastore. Khi nhận được request từ Presenter lúc này Interactor sẽ thực hiện logic để lấy dữ liệu tương ứng và trả về cho presenter.

    Trong VIPER mỗi một Interactor sẽ tương ứng với một Use case, nó tách biệt hoàn toàn với View vì vậy khả năng kiểm thử độc lập trên Interactor khá dễ dàng.

    Presenter

    Là nơi xử lý logic hiển thị của ứng dụng, khi nhận được request thay đổi hoặc hiển thị thông tin từ View nó sẽ thực hiện logic tương ứng để yêu cầu Interactor trả về data. Sau khi nhận được data nó sẽ format lại dữ liệu và trả về cho View để hiển thị chúng lên màn hình. Khi nhận được yêu cầu di chuyển màn hình Presenter sẽ thực hiện call Router để nó làm nốt nhiệm vụ điều hướng

    Entity

    Đây là các Data model, nó có nhiệm vụ tương tác với Interactor để trả dữ liệu về cho Presenter.

    Router

    Là nơi xử lí luồng của ứng dụng, nó làm nhiệm vụ điều hướng ứng dụng đến nơi mà người dùng cần. Khi Presenter nhận yêu cầu chuyển màn hình từ View, nó sẽ thực hiện logic hiển thị và thực hiện tương tác với Router để xử lí di chuyển luồng đúng với yêu cầu của View.

    Ưu điểm

    VIPER được chia nhỏ thành nhiều phần, các phần đảm nhiệm các vai trò và nhiệm vụ cố định, các thành phần tương tác với nhau dựa trên các quy định cụ thể vì vậy nó có khá nhiều ưu điểm

    • Các nhiệm vụ được chia đều ra cho các thành phần vì vậy việc maintain không còn quá rắc rối.
    • Việc kiểm thử (Unit test) cũng trở nên dễ dàng hơn vì giờ đây các thành phần đã được chia nhỏ và không liên kết chặt chẽ với View
    • Cấu trúc source trở nên dễ hiểu và rõ ràng hơn vì nó được chia theo từng use case và các phần được chia nhiệm vụ và trách nhiệm rõ ràng
    • Không gặp phải trường hợp một file có nội dung quá dài, vì vậy việc đọc source code của người cũng trở nên dễ hiểu hơn
    • Khá là hữu dụng với các ứng dụng lớn với team size lớn
    • Dễ dàng để mở rộng và bảo trì, các developer có thể đồng thời làm việc trên nó một cách trơn tru
    • Giảm số lượng conflict khi merge source code

    Nhược điểm

    • Do có nhiều thành phần và tương tác với nhau nên số file quản lý sẽ nhiều hơn so với các mẫu kiến trúc khác
    • Không dễ sử dụng cho người mới vì có nhiều ràng buộc và quy tắc cho từng phần, vì vậy cần thời gian để các member có thể tìm hiểu và thích nghi với mẫu kiến trúc này.
    • Một số thư viện bên thứ 3 không hỗ trợ kiến trúc này, vì vậy nếu không có lựa chọn nào khác lúc này nếu áp dụng thư viện vào ứng dụng nó sẽ phá vỡ kiến trúc ở các tính năng mà sử dụng thư viện này.

    Tổng kết

    Như mình đã phân tích ở trên VIPER có rất nhiều ưu điểm vì vậy nó rất đáng để các bạn tìm hiểu và sử dụng cho các dự án sắp tới. Tuy nhiên theo mình thì mẫu kiến trúc VIPER chỉ nên sử dụng cho những ứng dụng có kích thước vừa và lớn thì nó mới phát huy được tối đa sự hiệu quả. Đối với các dự án nhỏ nếu sử dụng VIPER architecture pattern thì nó lại trở nên quá cồng kềnh và không cần thiết.

    Mình hi vọng bài viết mình chia sẻ sẽ giúp các bạn có thêm lựa chọn khi bắt đầu một dự án mới!

    Chúc các bạn thành công!

  • Architecture Pattern: MVVM trong iOS

    Architecture Pattern: MVVM trong iOS

    Chào các bạn, để tiếp tục series về Architecture pattern thì hôm nay mìn sẽ giới thiệu đến một mô hình có thể giải quyết được một số nhược điểm của các mô hình cũ như MVC, MVP.

    Nếu các bạn chưa tiếp cận hoặc chưa tìm hiều về các Architecture Pattern bao giờ thì có thể xem lại các bài viết của mình về MVC hoặc MVP tại đây:
    iOS Architecture Patterns: Cocoa MVC
    MVP Architecture Pattern và biến thể MVP-C
    Để khi đi vào bài viết này chúng ta sẽ dễ dàng hiểu được nội dung bài viết truyền tải.

    Lịch sử hình thành và phát triển

    MVVM được viết đầy đủ là Model View ViewModel, MVVM là một biến thể của mẫu thiết kế Presentation Model của Martin Fowler. Nó được sáng lập ra bởi các kiến trúc sư của Microsoft tên là Ken Cooper và Ted Peters, nó đặc biệt được sinh ra để làm đơn giản việc lập trình hướng sự kiện (event-driven programming). MVVM được tích hợp vào Windows Presentation Foundation (WPF) (hệ thống đồ họa .NET của Microsoft) và Silverlight, dẫn xuất ứng dụng Internet của WPF. John Gossman, một kiến ​​trúc sư Microsoft WPF và Silverlight, đã công bố MVVM trên blog của mình vào năm 2005.

    MVVC là gì?

    MVVC là một mẫu kiến trúc giúp tách biệt source code của bạn ra thành nhiều thành phần khác nhau. Nó giúp code của bạn có các thành phần độc lập, giúp cho quá trình phát triển và kiểm thử ứng dụng trở nên rõ dàng và dễ dàng hơn.

    Cấu tạo của MVVM

    MVVM gồm 3 phần chính là Model, View và ViewModel.

    MVVM

    Model

    Là nơi chứa dữ liệu và xử lí business logic, model sẽ thực hiện các công việc như lưu trữ các data được lấy về từ API, local storage, v.v. Nó độc lập so với View và tương tác với View thông qua ViewModel.

    View

    Là nơi hiển thị giao diện cho người dùng, nhận các sự kiện từ người dùng, xử lí và gửi các yêu cầu của người dùng cho ViewModel xử lí. View trong iOS thì thông thường là các thành phần của UIKit, storyboard, xib …, ở MVVM trong iOS thì View bao gồm cả các View Controller, nó sẽ là thành phần cài đặt cho View và gửi và nhận thông tin từ ViewModel.

    ViewModel

    Là nơi xử lí các logic hiển thị(presentation logic), nó là cầu nối giữa View và Model. ViewModel sẽ nhận yêu cầu từ View và lấy dữ liệu từ model về xử lí sau đó trả lại cho View thứ mà nó cần để hiển thị lên màn hình cho người dùng.

    Trong khi MVC thì Controller, MVP thì có Presenter làm trung gian giữa View và Model. Ở MVVM thì ViewModel cũng tương tự, nó là thành phần trung gian giúp kết nối View với Model.

    Ưu điểm của MVVM

    • Vì MVVM là mô hình nâng cấp của MVC, cho nên nó giúp app vẫn duy trì cấu trúc của mô hình MVC và bao gồm các ưu điểm của MVC
    • Giảm tải lượng code chứa trong View và View Controller.
    • Khi đó View và View Controller trở nên đơn giản hơn khi những logic.
      Ví dụ như logic về quy định cách hiển thị của dữ liệu, được chuyển hết sang ViewModel. Điều này khiến cho code trở nên dễ hiểu và dễ maintain hơn.
    • Sự liên lạc giữa các thành phần trong mô hình rõ ràng, khiến nó hoạt động tốt hơn với cơ chế binding dữ liệu.
    • Có thể thực hiện UnitTest lên tầng ViewModel.
    • Nhiệm vụ được chia đều cho các tầng

    Nhược điểm của MVVM

    • Nhiều file nên source code lại nhiều thêm
    • Tương tác giữa các thành phần phức tạp hơn các mẫu kiến trúc khác như MVC, MVP vì vậy người mới khó tiếp cận và thực hiện hơn.
    • Rắc rối trong việc phản hồi lại yêu cầu hơn so với các mẫu kiến trúc khác
    • Đối với nhưng dự án nhỏ thì nó lại quá cồng kềnh để thực hiện

    Tổng kết

    MVVM là một mẫu kiến trúc rất tốt khi bạn triển khai những ứng dụng có kích thước vừa và lớn, nó hỗ trợ UnitTest khá hiệu quả. Trong MVVM thì nhiệm vụ được chia đều cho các tầng vì vậy sẽ không quá khó để quản lý source code. Mình hi vọng bài viết giúp các bạn có thể dễ dàng hơn khi chon mẫu kiến trúc cho các dự án mới. Chúc các bạn thành công!

  • MVP Architecture Pattern và biến thể MVP-C

    MVP Architecture Pattern và biến thể MVP-C

    Là một Developer, chắc hẳn các bạn đã trải qua nhiều dự án khác nhau. Thông thường khi bạn càng làm nhiều dự án bạn càng có nhiều cơ hội tiếp cận đến các loại Architecture pattern khác nhau như MVC, MVP, MVVM, VIPPER, … 

    Sau khi chinh chiến ở các dự án lớn nhỏ khác nhau mình cũng tích luỹ được một chút kiến thức về MVP Architecture pattern, vì vậy mình muốn viết một bài để chia sẻ một số kiến thức nho nhỏ mà mình đã học được về MVP cho những bạn chưa có cơ hội làm việc với MVP Architecture pattern.

    Lịch sử hình thành và phát triển

    MVP là viết tắt của Model View Presenter, nó bắt nguồn từ đầu những năm 1990 tại Talligent, một liên doanh của Apple, IBM và Hewlett-Packard. MVP là mô hình lập trình cơ bản để phát triển ứng dụng trong môi trường CommonPoint dựa trên C++ của Taligent. Sau này nó đã được Taligent chuyển sang Java.

    Đến năm 1998 thì Taligent giải thể, Andy Bower và Blair McFlashan của Dolphin Samlltalk đã điều chỉnh MVP để tạo cơ sở cho Smalltalk của họ.

    Đến năm 2006 thì Microsoft cũng bắt đầu kết hợp MVP vào tài liệu và ví dụ về lập trình giao diện người dùng trong .NET Framework.

    Đến nay thì MVP được sử dụng khá là rộng rãi vì những lợi ích mà nó đem lại cho các lập trình viên. Ngoài ra MVP cũng có rất nhiều biến thể để cải thiện những nhược điểm của nó.

    MVP là gì?

    MVP là một mẫu kiến trúc giao diện người dùng(user interface architecture pattern) được thiết kế để tạo điều kiện thuận lợi cho Automated Unit Testing(Chạy Unit Test tự động) và cải thiện việc phân tách các thành phần trong trình bày logic(presentation logic).

    MVP sinh ra dựa trên kiến trúc MVC, nó hướng tới mục tiêu cải thiện kiến trúc MVC.

    MVP được thể hiện băng hình ảnh sau:

    Model: là một interface xác định dữ liệu được hiển thị hoặc dữ liệu này được thực hiện trong giao diện người dùng.

    View: là một interface thụ động dùng để hiện thị dữ liệu của Model và định hướng các lệnh người dùng (events) tới Presenter để Presenter hành động dựa trên các dữ liệu đó.

    Presenter: hành động theo Model và View. Presenter lấy dữ liệu từ kho lưu trữ (Model), sau đó định dạng dữ liệu và hiển thị lên View.

    Ưu điểm của MVP

    Như đã nói ở trên do MVP được xây dựng dựa trên kiến trúc MVC nên nó sẽ có các ưu điểm tương tự như MVC. Các bạn có thể xem thêm về MVC ở bài viết sau: iOS Architecture Patterns: Cocoa MVC

    Mục đích cao cả của MVP sinh ra là để cải thiện những nhược điểm của kiến trúc MVC vì vậy nó giúp giảm tải lượng lớn logic nằm ở tầng Model so với mô hình MVC

    Kiến trúc MVP có tầng Presenter chuyên để xử lý các logic hiển thị, nó là thành phần trung gian tương tác với View và Model qua interface nên nó có thể viết Unit testing một cách dễ dàng.

    Nhược điểm của MVP

    Cũng như MVC, kiến trúc MVP cũng có những nhược điểm. Nhược điểm lớn nhất của MVP là càng về sau Presenter của MVP sẽ càng phình to nếu logic được thêm mới. Khí đó bạn sẽ rất khó để chia nhỏ khi presenter quá lớn.

    Biến thể MVP-C trong iOS

    Khái niệm Coordinator lần đầu tiên được đưa ra bởi Khanlou vào năm 2015, nó là một giải pháp để xử logic luồng cho View Controller.

    Dựa trên điều này kiến trúc MVP-C được ra đời với C là Coordinator làm nhiệm vụ xử lý luồng cho ứng dụng và các tầng cũ là Model, View và Presenter vẫn giống như MVP được mô tả ở trên.

    Ưu điểm của MVP-C

    View controller có thể tập trung vào mục tiêu chính của chúng. Giúp phân chia rõ ràng vai trò của View.

    Giúp giảm tải các logic trên các tầng khác, ta có thể đưa một số logic như phân luồng di chuyển màn hình từ presenter vào coordinator để giúp presenter đỡ trở nên cồng kềnh khi có quá nhiều logic. Nó đã cải thiện được nhược điểm của kiến trúc MVP truyền thống.

    Ngoài ra Coordinator cũng được ứng dụng vào các kiến trúc khác như MVC để tạo ra MVC-C và MVVM tạo ra MVVM-C.

    Tổng kết

    Đó là những kiến thức mà mình đã tích luỹ được khi làm việc với các dự án được thực hiện theo kiến trúc MVP. Mình hi vọng nó sẽ giúp ích cho các bạn khi cần thiết.