Bốn quy tắc thiết kế phần mềm đơn giản hơn của iOS

Vào cuối những năm 1990, khi đang phát triển Lập trình cực đoan, nhà phát triển phần mềm nổi tiếng Kent Beck đã đưa ra một danh sách các quy tắc cho thiết kế phần mềm đơn giản.

Theo Kent Beck, một thiết kế phần mềm tốt:

  • Chạy tất cả các bài kiểm tra
  • Không chứa sự trùng lặp
  • Thể hiện ý định của lập trình viên
  • Giảm thiểu số lượng các lớp và phương thức

Trong bài viết này, chúng tôi sẽ thảo luận về cách các quy tắc này có thể được áp dụng cho thế giới phát triển iOS bằng cách đưa ra các ví dụ thực tế về iOS và thảo luận về cách chúng tôi có thể hưởng lợi từ chúng.

Chạy tất cả các bài kiểm tra

Thiết kế phần mềm giúp chúng tôi tạo ra một hệ thống hoạt động như dự định. Nhưng làm thế nào chúng ta có thể xác minh rằng một hệ thống sẽ hoạt động như dự định ban đầu bởi thiết kế của nó? Câu trả lời là bằng cách tạo ra các bài kiểm tra xác nhận nó.

Thật không may, trong các thử nghiệm vũ trụ phát triển iOS hầu hết mọi lúc đều tránh né Nhưng để tạo ra một phần mềm được thiết kế tốt, chúng ta nên luôn luôn viết mã Swift với khả năng kiểm tra.

Hãy để chúng tôi thảo luận về hai nguyên tắc có thể làm cho bài kiểm tra viết và thiết kế hệ thống đơn giản hơn. Và họ là nguyên tắc trách nhiệm duy nhất và tiêm phụ thuộc.

Nguyên tắc trách nhiệm duy nhất (SRP)

SRP nói rằng một lớp nên có một, và chỉ có một lý do để thay đổi. SRP là một trong những nguyên tắc đơn giản nhất và là một trong những nguyên tắc khó nhất để có được quyền. Trộn lẫn trách nhiệm là điều mà chúng tôi làm một cách tự nhiên.

Hãy để cung cấp một ví dụ về một số mã mà thực sự khó kiểm tra và sau đó tái cấu trúc nó bằng cách sử dụng SRP. Sau đó thảo luận về cách nó làm cho mã có thể kiểm tra được.

Giả sử rằng chúng tôi hiện cần phải trình bày PaymentViewContaptor từ bộ điều khiển chế độ xem hiện tại của chúng tôi, PaymentViewContaptor sẽ định cấu hình chế độ xem của nó tùy thuộc vào giá sản phẩm thanh toán của chúng tôi. Trong trường hợp của chúng tôi, giá là thay đổi tùy thuộc vào một số sự kiện người dùng bên ngoài.

Mã cho việc thực hiện này hiện tại trông như sau:

Làm thế nào chúng ta có thể kiểm tra mã này? Chúng ta nên kiểm tra cái gì trước? Là giảm giá được tính chính xác? Làm thế nào chúng ta có thể chế giễu các sự kiện thanh toán để kiểm tra giảm giá?

Viết bài kiểm tra cho lớp này sẽ phức tạp, chúng ta nên tìm một cách tốt hơn để viết nó. Chà, trước tiên hãy để Lừa giải quyết vấn đề lớn. Chúng ta cần gỡ rối các phụ thuộc của chúng tôi.

Chúng tôi thấy rằng chúng tôi có logic để tải sản phẩm của chúng tôi. Chúng tôi có các sự kiện thanh toán khiến người dùng đủ điều kiện được giảm giá. Chúng tôi có Giảm giá, tính toán giảm giá và danh sách tiếp tục.

Vì vậy, hãy cố gắng dịch đơn giản những thứ này sang mã Swift.

Chúng tôi đã tạo một Trình quản lý thanh toán quản lý logic của chúng tôi liên quan đến thanh toán và tách riêng PriceCalculator mà nó có thể dễ dàng kiểm tra. Ngoài ra, một trình tải dữ liệu chịu trách nhiệm về tương tác mạng hoặc cơ sở dữ liệu để tải các sản phẩm của chúng tôi.

Chúng tôi cũng đề cập rằng chúng tôi cần một lớp chịu trách nhiệm quản lý giảm giá. Hãy gọi nó là CouponManager và để nó cũng quản lý các phiếu giảm giá của người dùng.

Bộ điều khiển xem thanh toán của chúng tôi sau đó có thể trông giống như sau:

Bây giờ chúng ta có thể viết các bài kiểm tra như

  • testCalculatingFinalpriceWithoutCoupon
  • testCalculatingFinalpriceWithCoupon
  • testCouponExists

và nhiều người khác! Bằng cách tạo các đối tượng riêng biệt bây giờ, chúng tôi tránh được sự trùng lặp không cần thiết và cũng tạo ra một mã mà nó dễ viết các bài kiểm tra.

Phụ thuộc tiêm

Nguyên tắc thứ hai là Dependency Injection. Và chúng tôi đã thấy từ các ví dụ ở trên rằng chúng tôi đã sử dụng phép nội xạ phụ thuộc vào các trình khởi tạo đối tượng của chúng tôi.

Có hai lợi ích chính của việc tiêm phụ thuộc của chúng tôi như trên. Nó cho thấy rõ các loại phụ thuộc của chúng ta dựa vào điều gì và nó cho phép chúng ta chèn các đối tượng giả khi chúng ta muốn kiểm tra thay vì các đối tượng thực.

Một kỹ thuật tốt là tạo các giao thức cho các đối tượng của chúng tôi và cung cấp triển khai cụ thể bởi đối tượng thực và giả như sau:

Bây giờ chúng ta có thể dễ dàng quyết định lớp nào chúng ta muốn tiêm như một phụ thuộc.

Khớp nối chặt chẽ gây khó khăn cho việc viết bài kiểm tra. Vì vậy, tương tự, chúng ta viết càng nhiều bài kiểm tra, chúng ta càng sử dụng các nguyên tắc như DIP và các công cụ như tiêm phụ thuộc, giao diện và trừu tượng hóa để giảm thiểu khớp nối.

Làm cho mã dễ kiểm tra hơn không chỉ giúp chúng ta loại bỏ nỗi sợ phá vỡ nó (vì chúng ta sẽ viết bài kiểm tra sẽ sao lưu chúng ta) mà còn góp phần viết mã sạch hơn.

Phần này của bài viết quan tâm nhiều hơn đến cách viết mã sẽ có thể kiểm tra được hơn là viết bài kiểm tra đơn vị thực tế. Nếu bạn muốn tìm hiểu thêm về cách viết bài kiểm tra đơn vị, bạn có thể xem bài viết này nơi tôi tạo trò chơi cuộc sống bằng cách sử dụng phát triển dựa trên thử nghiệm.

Không chứa sự trùng lặp

Sao chép là kẻ thù chính của một hệ thống được thiết kế tốt. Nó đại diện cho công việc bổ sung, rủi ro bổ sung, thêm sự phức tạp không cần thiết.

Trong phần này, chúng tôi sẽ thảo luận về cách chúng tôi có thể sử dụng mẫu thiết kế Mẫu để loại bỏ trùng lặp phổ biến trong iOS. Để dễ hiểu hơn, chúng tôi sẽ cấu trúc lại việc thực hiện một cuộc trò chuyện thực tế.

Giả sử rằng chúng tôi hiện có trong ứng dụng của mình một phần trò chuyện tiêu chuẩn. Một yêu cầu mới xuất hiện và bây giờ chúng tôi muốn thực hiện một loại trò chuyện mới - trò chuyện trực tiếp. Một cuộc trò chuyện nên chứa các tin nhắn có tối đa 20 ký tự và cuộc trò chuyện này sẽ biến mất khi chúng tôi loại bỏ chế độ xem trò chuyện.

Trò chuyện này sẽ có cùng lượt xem với trò chuyện hiện tại của chúng tôi nhưng sẽ có một vài quy tắc khác nhau:

  1. Yêu cầu mạng để gửi tin nhắn trò chuyện sẽ khác nhau.

2. Tin nhắn trò chuyện phải ngắn, không quá 20 ký tự cho tin nhắn.

3. Tin nhắn trò chuyện không nên được duy trì trong cơ sở dữ liệu địa phương của chúng tôi.

Giả sử rằng chúng tôi đang sử dụng kiến ​​trúc MVP và chúng tôi hiện đang xử lý logic để gửi tin nhắn trò chuyện trong người trình bày của chúng tôi. Hãy thử thêm quy tắc mới cho loại trò chuyện mới của chúng tôi có tên là trò chuyện trực tiếp.

Một triển khai ngây thơ sẽ như sau:

Nhưng điều gì xảy ra nếu trong tương lai chúng ta sẽ có nhiều kiểu trò chuyện hơn?
Nếu chúng tôi tiếp tục thêm nếu kiểm tra trạng thái trò chuyện của chúng tôi trong mọi chức năng, mã sẽ trở nên lộn xộn khó đọc và duy trì. Ngoài ra, nó khó có thể kiểm tra và kiểm tra trạng thái sẽ được sao chép trên toàn phạm vi của người trình bày.

Đây là nơi Mẫu Mẫu được sử dụng. Mẫu Mẫu được sử dụng khi chúng ta cần nhiều triển khai thuật toán. Mẫu được xác định và sau đó được xây dựng với các biến thể hơn nữa. Sử dụng phương pháp này khi hầu hết các lớp con cần thực hiện cùng một hành vi.

Chúng tôi có thể tạo một giao thức cho Người thuyết trình trò chuyện và chúng tôi tách các phương thức sẽ được triển khai khác nhau bởi các đối tượng cụ thể trong Giai đoạn của Người thuyết trình trò chuyện.

Bây giờ chúng tôi có thể làm cho người trình bày của chúng tôi tuân thủ IChatPresenter

Người thuyết trình của chúng tôi hiện xử lý việc gửi tin nhắn bằng cách gọi các chức năng phổ biến bên trong chính nó và ủy thác các chức năng có thể được thực hiện khác nhau.

Bây giờ chúng tôi có thể cung cấp Tạo các đối tượng phù hợp với các giai đoạn của người trình bày dựa trên và định cấu hình các chức năng này dựa trên nhu cầu của họ.

Nếu chúng ta sử dụng phép nội xạ phụ thuộc trong trình điều khiển khung nhìn thì bây giờ chúng ta có thể sử dụng lại trình điều khiển khung nhìn giống nhau trong hai trường hợp khác nhau.

Bằng cách sử dụng Mẫu thiết kế, chúng tôi thực sự có thể đơn giản hóa mã iOS của mình. Nếu bạn muốn biết thêm về điều đó, bài viết sau đây cung cấp giải thích thêm.

Biểu cảm

Phần lớn chi phí của một dự án phần mềm là trong bảo trì dài hạn. Viết dễ đọc và duy trì mã là điều bắt buộc đối với các nhà phát triển phần mềm.

Chúng tôi có thể cung cấp nhiều mã biểu cảm hơn bằng cách sử dụng Kiểm tra đặt tên, Sử dụng SRP và Viết tốt.

Đặt tên

Số một điều làm cho mã biểu cảm hơn - và đó là đặt tên. Nó rất quan trọng để viết tên rằng:

  • Tiết lộ ý định
  • Tránh thông tin sai lệch
  • Dễ dàng tìm kiếm

Khi nói đến việc đặt tên lớp và hàm, một mẹo hay là sử dụng danh từ hoặc cụm danh từ cho lớp và động từ người dùng hoặc tên cụm động từ cho phương thức.

Ngoài ra, khi sử dụng các Mẫu thiết kế khác nhau, đôi khi cũng tốt để thêm các tên mẫu như Lệnh hoặc Khách truy cập vào tên lớp. Vì vậy, người đọc sẽ biết ngay mẫu nào được sử dụng ở đó mà không cần phải đọc tất cả các mã để tìm hiểu về điều đó.

Sử dụng SRP

Một điều nữa làm cho mã biểu cảm là sử dụng Nguyên tắc Trách nhiệm duy nhất được đề cập từ trên. Bạn có thể thể hiện bản thân bằng cách giữ cho các chức năng và lớp học của bạn nhỏ và cho một mục đích duy nhất. Các lớp và hàm nhỏ thường dễ đặt tên, dễ viết và dễ hiểu. Một chức năng chỉ nên phục vụ cho một mục đích.

Bài kiểm tra viết

Kiểm tra viết cũng mang lại rất nhiều sự rõ ràng, đặc biệt là khi làm việc với mã kế thừa. Bài kiểm tra đơn vị được viết tốt cũng có tính biểu cảm. Một mục tiêu chính của các bài kiểm tra là làm ví dụ như tài liệu. Ai đó đọc các bài kiểm tra của chúng tôi sẽ có thể hiểu nhanh về nội dung của một lớp học.

Giảm thiểu số lượng lớp và phương thức

Các chức năng của một lớp phải duy trì ngắn, một chức năng sẽ luôn luôn chỉ thực hiện một điều. Nếu một chức năng có quá nhiều dòng có thể là trường hợp mà nó thực hiện các hành động có thể được tách thành hai hoặc nhiều chức năng riêng biệt.

Một cách tiếp cận tốt là đếm các dòng vật lý và cố gắng nhắm tới tối đa bốn đến sáu dòng chức năng, trong hầu hết các trường hợp, bất cứ thứ gì vượt quá số dòng đó đều có thể trở nên khó đọc và duy trì.

Một ý tưởng hay trong iOS là cắt các cuộc gọi cấu hình mà chúng ta thường làm trên các hàm viewDidLoad hoặc viewDidAppear.

Theo cách này, mỗi hàm sẽ nhỏ và có thể bảo trì thay vì một hàm viewDidLoad lộn xộn. Tương tự cũng nên áp dụng cho đại biểu ứng dụng. Chúng ta nên tránh ném mọi phương thức ondidFinishLaunchingWithOptions và các chức năng cấu hình riêng biệt hoặc các lớp cấu hình tốt hơn.

Với các chức năng, nó có thể dễ dàng hơn một chút để đo xem chúng ta giữ nó dài hay ngắn, hầu hết chúng ta có thể chỉ dựa vào việc đếm các dòng vật lý. Với các lớp học, chúng tôi sử dụng một biện pháp khác nhau. Chúng tôi tính trách nhiệm. Nếu một lớp chỉ có năm phương thức, điều đó không có nghĩa là lớp đó nhỏ, có thể là nó có quá nhiều trách nhiệm chỉ với các phương thức đó.

Một vấn đề được biết đến trong iOS là kích thước lớn của UIViewControllers. Đúng là theo thiết kế bộ điều khiển apple view, thật khó để giữ các đối tượng này phục vụ một mục đích duy nhất nhưng chúng ta nên cố gắng hết sức.

Có nhiều cách để làm cho UIViewControllers trở thành sở thích nhỏ của tôi là sử dụng một kiến ​​trúc phân tách mối quan tâm tốt hơn như VIPER hoặc MVP nhưng điều đó không có nghĩa là chúng ta cũng có thể làm cho nó tốt hơn trong apple MVC.

Bằng cách cố gắng phân tách càng nhiều mối quan tâm, chúng ta có thể đạt được mã khá tốt với bất kỳ kiến ​​trúc nào. Ý tưởng là tạo ra các lớp đơn mục đích có thể đóng vai trò là người trợ giúp cho các bộ điều khiển xem và làm cho mã dễ đọc và dễ kiểm tra hơn.

Một số điều có thể tránh được đơn giản mà không có lý do nào trong các bộ điều khiển xem là:

  • Thay vì viết mã mạng trực tiếp, nên có một Trình quản lý mạng, một lớp chịu trách nhiệm cho các cuộc gọi mạng
  • Thay vì thao tác dữ liệu trong các bộ điều khiển xem, chúng ta có thể chỉ cần tạo DataManager một lớp chịu trách nhiệm cho việc đó.
  • Thay vì chơi với các chuỗi UserDefaults trong UIViewControll, chúng ta có thể tạo một mặt tiền trên đó.

Cuối cùng

Tôi tin rằng chúng ta nên soạn phần mềm từ các thành phần được đặt tên chính xác, đơn giản, nhỏ, chịu trách nhiệm cho một thứ và có thể tái sử dụng.

Trong bài viết này, chúng tôi đã thảo luận bốn quy tắc cho thiết kế đơn giản của Kent Beck và đưa ra các ví dụ thực tế về cách chúng tôi có thể triển khai chúng trong môi trường Phát triển iOS.

Nếu bạn thích bài viết này, hãy đảm bảo vỗ tay để thể hiện sự hỗ trợ của bạn. Theo dõi tôi để xem nhiều bài viết khác có thể đưa kỹ năng Nhà phát triển iOS của bạn lên một tầm cao mới.

Nếu bạn có bất kỳ câu hỏi hoặc nhận xét nào, vui lòng để lại một ghi chú ở đây hoặc gửi email cho tôi tại arlindaliu.dev @ gmail.