12/08/2018, 14:49

Tìm hiểu kỹ hơn về mô hình phát triển ứng dụng IOS

Hiện tại có rất nhiều mô hình để phát triển một ứng dụng IOS như MVC, MVP, MVVM, VIPER và chắc hăn có rất nhiều lập trình viên đã quá quen thuộc với MVC. Mình cũng không phải là một ngoại lệ. Thế nhưng hiểu sâu hơn về nó thì chưa mấy ai làm việc này, đơn giản là sử dụng và thấy nó ổn. Vậy với bài ...

Hiện tại có rất nhiều mô hình để phát triển một ứng dụng IOS như MVC, MVP, MVVM, VIPER và chắc hăn có rất nhiều lập trình viên đã quá quen thuộc với MVC. Mình cũng không phải là một ngoại lệ. Thế nhưng hiểu sâu hơn về nó thì chưa mấy ai làm việc này, đơn giản là sử dụng và thấy nó ổn. Vậy với bài viết này mình muốn có một cái nhìn sâu hơn về MVC theo quan điểm cá nhân của mình( có tham khảo một số bài viết trên mạng khác). Hy vọng nó sẽ giúp ích ít nhiều cho các bạn

Hiểu rõ về Archtecture Pattern

Bạn là một lập trình viên IOS, bạn đã quá quen với MVC, nhưng thế giới lập trình vẫn luôn thay đổi từng ngày và giờ đây có rất nhiều Architecture Pattern để ta lựa chọn khi xây dựng một ứng dụng IOS. Bạn đã từng làm rất nhiều dự án, mõi thứ đều trôi chảy với MVC, nhưng rồi bạn biết đến MVVM và muốn chuyển sang nó, tiếp đến là cả về VIPER. Có quá nhiều thứ bạn chưa biết về chúng. Và chưa biết chúng mang lại những gì cho những ứng dụng của mình. Cá nhân mình thì đang muốn chuyển sang MVVM. Vậy bây giờ hay cũng tìm hiểu kỹ hơn về Architecture Pattern

Việc nắm vững về các design pattern có thể khiến bạn bối rồi, và có những xung đột khi bạn đọc hết bài viết này. Rồi trong đầu bạn sẽ nảy sinh những câu hỏi kiểu như thế này: Cái gì sẽ đc gọi đến khi 1 request từ user được gửi đến server: Model hay Controller? Làm sao để chuyển dữ liệu là 1 Model vào trong 1 View Model của 1 View mới? Cái gì tạo ra 1 VIPER mới: Router hay Presenter? Đến đây câu chuyện mới chính thức bắt đầu!

Vậy tại sao cần chọn Architecture?

Vì nếu không thì sẽ đến một ngày nào đó bạn sẽ nhận thấy debug ứng dụng của mình gặp phải vô vàn khó khắn, cùng với hàng tá thứ cần tìm hiểu. Và rồi bạn sẽ nhận ra rằng mình khổng thể nào tìm và sửa hết chúng được. Mọi chuyện xảy ra, class của bạn không thể bao quát được hết các thực thể khiến bạn bị thiết những chi tiết quan trọng. Nếu bạn đã từng ở vào hoàn cảnh như vậy, thì rất có thể nó sẽ như thế này:

  • Lớp này là lớp con của UIViewController.
  • Dữ liệu của bạn đều để ở UIViewController.
  • UIView chả làm cái quái gì cả
  • Model là một kiến trúc dữ liệu không linh hoat.
  • Unit Test của bạn trở nên vông dụng.

Và chuyện gì đã xảy ra, ngay cả khi bạn đang đi theo đúng hướng của Apple và triển khai thực hiện mô hình MVC của Apple Hãy xác định những đặc điểm của một kiến trúc tốt:

  1. Phân bố vai trò chính xác cho từng thực thể
  2. Có thể test được từ ngay những tính năng đầu tiên.
  3. Dễ sử dụng và chi phí bảo trì thấp

Tại sao có thể phân bổ?

Sự phân bố này giữ cho mọi thứ luôn đúng theo nhưng gì chúng ta đã hình dung về cách chúng làm việc. Nếu bạn nghĩ mình có thể tăng thêm khả năng của bản thân để hiểu hết được sự phức tạp đó thì bạn có thể đúng. Nhưng nó không có khả năng mở rộng và đạt đến giới hạn rất nhanh. Vì vậy cách dễ nhất để hiểu hết sự phức tạp của nó làlà chia nhỏ vai trò của từng thực thể ra theo Single responsibility principle

Tại sao có thể test?

Đây không phải là câu hỏi thường được đặt ra cho những người, hay sử dụng unit test, nhưng việc thất bại khi thêm 1 tính năng mới hay refactoring lại code. Điều đó có nghĩa là việc test trước sẽ giúp lập trình viên tìm ra những vẫn đề khi thực thi mã lệnh. Mà nó có thể xảy ra trên thiết bị của người dùng và việc sửa chúng sẽ mất cả tuần.

Tại sao lại dễ sử dụng?

Điều này không đòi hỏi câu trả lời, tuy nhiên có một điều tôi muốn nói đến, code tốt nhất là code không bao giờ được viết ra. Điều đó là tôi muốn càng ít code càng tốt, càng ít code thì càng ít bugs. Đương nhiên là không code thì chả có chương trình nào chạy cả, và điều đó có nghĩa là mong muốn viết code ít hơn sẽ không bao giờ thực hiện được từ những lập trình viên lười biếng

##MV(X) nhưng kiến trúc cơ bản: Hiện tại chúng ta có rất nhiều tuỳ chọn với những architecture desgn pattern cho dự án của mình:

  • MVC
  • MVP
  • MVVM
  • VIPER

Đầu tiên 3 trong số chúng cho rằng việc đưa các thực thể của ứng dụng vào 1 trong 3 loại:

  • Models -- Là nơi lưu trữ hay là cấp data access layer , kiểu như class "Person" và "PersonDataProvider"
  • Views -- Là giao diện mà ngừoi dùng thấy (GUI), trong IOS nó là những class có tiền tố "UI"
  • Controller/Presenter/ViewModel-- Ở giữa trung gian với Model và View, nhiệm vụ chính là phản ứng lại những tương tác của người dùng ở View, cập nhật View rồi sau đó sẽ thay đổi lại Model phù hợp với từng tình huống sử dụng của người dùng

Vậy có những những thực thể đc phân chia vai trò cụ thể sẽ cho phép chúng ta:

  • Hiểu chúng tốt hơn (như chúng ta đã biết)
  • Sử dụng lại chúng (chủ yếu áp dụng cho View và Model)
  • Test chúng một cách độc lập

Bây giờ hãy bắt đầu với MV(X) rồi quay lại với VIPER

MVC : Model - View - Controller

Trước khi nói về mô hình MVC của Apple hãy cùng nhìn lại mô hình MVC truyền thống:

hehe

trong trường hợp này ViewView hoàn toàn không năm giữ vai trò gì cả. Nó chỉ đơn gian là được tạo ra bởi Controller khi một Models thay đổi. Ví dụ như khi reload một website hoàn toàn mới khi bạn ấn vào một liên kết bất kỳ. Mặc dù nó có thể được thực hiện mô hình MVC truyền thống trong ứng dụng IOS, nhưng nó không mang nhiều ý nghĩa về mặt kiến trúc - cả 3 thực thể đều có mối quan hệ chặt chẽ, mỗi thực thể đều hiểu rất rõ về 2 thứ còn lại. Điều này làm giảm đáng kể khả năng tái sử dụng của chúng- đó không phải là thứ bạn muốn có trong ứng dụng IOS của mình.

Mô hình MVC truyền thống có vẻ không được phát triển cho ứng dụng IOS hiện đại

Mô hình MVC của Apple

Lý thuyết

Controller vẫn ở giữa để giao tiếp với View và Model nhưng sẽ không ViewModel tương tác với nhau nữa. Việc tái sử dụng dễ dang hơn, ít nhất là với Controller và điều này là tốt cho chúng ta, vì chúng ta cần phải có nơi cho tất cả phần xử lí logic mà không hề phù hợp với Model Trên lý thuyết nó có vẻ đơn giản, nhưng bạn cảm thấy có điều gì đó sai đúng không nào? Bạn thậm chí thấy người ta không viết tắt MVC là Massive View controller. Hơn nữa view controller offloading trở thành một chủ đề quan trọng với các lập trình viên IOS. Tại sao điều này xáy ra nếu như Apple chỉ dùngdùng MVC truyền thống và cải tiến chúng Thực tế Cocoa MVC khuyến khích bạn viết Massive View Controller, bởi vì chúng liên quan đến life cycle của View, và thật khó để nói rằng chúng tách biệt với nhau. Măc dù vẫn có thể giảm tải bớt một số logic và dữ liệu chuyển từ Model, bạn không có nhiều sự lựa chọn chocho việc giảm công việc cho View, trong phần lớn thời gian View sẽ gửi các hành động đến Controller. Và view controller sẽ kết thúc bằng cách gửi lại những phản ứng thích hợp

Có phải đã nhiều lần bạn đã thấy đoạn code này:

var userCell = tableView.dequeueReusableCellWithIdentifier("identifier") as UserCell
userCell.configureWithUser(user)

Các cell được View cấu hình trực tiếp từ Model, vì vậy mà mô hình MVC không được đảm bảo. Những điều này luôn luôn xảy ra trong quá trình chạy ứng dụng, và thường không ai cho đó là sai cả. Nếu bạn nghiêm túc thực hiện theo mô hình MVC thì bạn phải cấu hình các cell từ ViewController chứ không được truyền từ Model sang View, và nó sẽ làm tăng kích thước Controller của bạn

Vậy Cocoa MVC không viết tắt là Massive View Controller

Hãy xem đoạn code playground đơn giản này:

import UIKit

struct Person { // Model
    let firstName: String
    let lastName: String
}

class GreetingViewController : UIViewController { // View + Controller
    var person: Person!
    let showGreetingButton = UIButton()
    let greetingLabel = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.showGreetingButton.addTarget(self, action: "didTapButton:", forControlEvents: .TouchUpInside)
    }
    
    func didTapButton(button: UIButton) {
        let greeting = "Hello" + " " + self.person.firstName + " " + self.person.lastName
        self.greetingLabel.text = greeting
        
    }
    // layout code goes here
}
// Assembling of MVC
let model = Person(firstName: "David", lastName: "Blaine")
let view = GreetingViewController()
view.person = model;

MVC đơn giản có thể được thực hiện bởi View controller

Điều này không phải là để kiểm chứng phải không? Có thể di chuyển class Greeting đến class mới GreetinModel mà không cần test lại, nhưng không thể kiểm tra hết các logic của chúng (Mặc dù không có nhiều logic như ở ví dụ trên). Bên trong class GreetingViewController không gọi đến UIView trực tiếp (ViewDidLoad, didTapButton..) mà điều này có thế gây ra những răc rối cho unit test Với những điều đã kể trên ta có thể thấy Cocoa MVC có vẻ là mô hình khá xấu để lựa chọn. Nhưng để đánh giá về tính năng ta có thể xác định được những điều sau:

  • Khả năng phân phối: View và Model là những thực thể tách biệt, nhưng View và Controller lại có quan hệ rất chặt chẽ
  • Khả năng kiểm tra: Từ sự phân bổ đó bạn sẽ chỉ kiểm tra được Model của bạn
  • Dễ sử dụng: chi phí phải trả ít hơn so với các mô hình khác. Ngoài ra tất cả các lập trình viên đều quen thuộc với nó. Vì vậy nó dễ dàng đươc bảo trì ngay cả với người chưa có kinh nghiệm phát triển Bạn có thể lựa chọn Cocoa MVC nếu như không muốn đầu tư quá nhiều thời gian hơn trong kiến trúc của mình, và nó cũng phù hợp với những dự án nho nhỏ của bạn

Cocoa MVC là mô hình kiến trúc tốt nhất về tốc độ phát triển

Hy vọng đọc đến đây các bạn có thể hiểu rõ hơn về mô hình mà mình vẫn luôn áp dụng hàng ngày. Và tiếp sau bài này chúng ta sẽ cùng tìm hiểu về MVVM và nhưng điều tuyệt vời mà chúng mang lại

0