Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Chuyển đổi Rails Controller rối rắm thành code sạch, có thể test

Đến lúc nào đó trong sự nghiệp Rails, bạn sẽ gặp controller khiến bạn muốn bỏ lập trình mãi mãi. Nó có thể chứa mọi dòng code cho toàn bộ tính năng. Nó có thể có 15 before_filters giao tiếp qua instance variable và phải gọi theo thứ tự cụ thể nếu không mọi thứ sẽ nổ. Và tất nhiên, test của nó trông như này:

test "index" do get :index assert_response :success end 

Tuyệt. 100% test coverage, phải không?

Dù thật tuyệt nếu chỉ cần nhắm mắt làm ngơ, nhưng một ngày nào đó bạn sẽ phải sửa bug trong controller này. Và, là dev tốt, bạn muốn để code tốt hơn bạn tìm thấy nó.

Nhưng làm sao refactor, đặc biệt khi không có test tốt để dựa vào?

Làm cho nó có test (bất kỳ cách nào)

Bạn cần test tốt để an tâm refactor, nhưng bạn không thể viết test tốt cho code này cho đến khi bạn refactor. Vậy làm sao?

Thực tế, không quan trọng controller viết tệ đến đâu, bạn vẫn có thể viết integration test gửi data đến controller và mong đợi response. Hiện tại, bạn nên viết test đảm bảo hành vi hiện tại của controller không thay đổi khi bạn refactor.

Những test này không focused như unit test. Nhưng test high-level này giúp bạn tự tin refactor sắp tới không phá vỡ mọi thứ. Và quá trình viết chúng giúp bạn hiểu code tốt hơn, giúp quyết định cách refactor.

Phá vỡ dependency

Điều gì làm code controller xấu? Hầu hết thời gian, là dependency ngầm định giữa before_filters, helper method, hoặc phần khác nhau của function 200 dòng. Nó cũng có thể là refactor quá sớm. Để làm code tốt hơn, bạn cần phá vỡ dependency này.

Với Rails controller, có cách dễ dàng phá vỡ dependency. Chỉ cần copy code từ before_filters, helper method, superclass, và nơi khác code controller-ish có thể đang ẩn. Sau đó, thay thế gọi method đó bằng code bạn copy.

Bạn đang tạm thời un-DRY code, để sau refactor nó cách dễ hiểu hơn. Nó xấu, nhưng bây giờ tất cả code ở ngoài mặt. Bạn có thể thấy piece nào tương tác như thế nào và mọi thứ flow ra sao.

(Trong quá trình này, bạn nên chạy test sau mỗi thay đổi để đảm bảo inlining không làm hỏng gì.)

Refactor hướng tới code có thể test

Bây giờ, bạn sẵn sàng re-refactor code. Bạn có thể sẽ dùng các refactoring cơ bản extract method, extract object, pull up method. Thử refactor code vài cách khác nhau và xem cái nào cảm thấy tốt nhất.

Trong vài pass đầu, bạn có thể dựa vào integration test high-level như lưới an toàn. Nhưng sớm muộn bạn sẽ muốn thứ tốt hơn.

Khi refactor, hãy tìm cơ hội làm code dễ test hơn. Thường nghĩa là tạo nơi inject test double, giảm dependency giữa object, và làm controller dựa vào object dễ tạo và unit test. Bằng cách chuyển code vào object có thể test, controller sẽ nhỏ hơn, dễ hiểu, và dễ test hơn.

Có thể lấy dạng danh sách số không?

Một lần nữa, đây là các bước phân rã controller lớn:

  1. Chạy integration test high-level cho controller.
  2. Chạy test, đảm bảo pass.
  3. Inline before_filters, method superclass, và abstraction ẩn code khác.
  4. Chạy test, đảm bảo vẫn pass.
  5. Thực hiện refactoring (extract method, extract service object, replace instance variable with local, v.v.). Xem code cảm thấy tốt hơn.
  6. Chạy test, đảm bảo vẫn pass.
  7. Nếu bạn vừa extract code, viết unit test cho object hoặc method bạn extract.
  8. Chạy test, đảm bảo vẫn pass.
  9. Nếu controller vẫn cần việc, quay lại bước 5.

Tiếp theo là gì?

Nếu muốn học thêm, Working Effectively with Legacy Code là kinh thánh biến code unmaintainable không test thành thứ bạn có thể làm việc. Tôi cực kỳ khuyến khích, nếu bạn thường gặp controller khổng lồ đơn khối (và nếu refactor vui đối với bạn như对我).

Bây giờ, hãy nghe câu chuyện kinh dị của bạn! Code controller tồi tệ nhất bạn từng làm trông như thế nào?