Về Github view_component gem (Ở đây em không nhắc chung tới kiến trúc component nữa mà nói trực tiếp tới view_component gem vì đối với mỗi thư viện, kiến trúc component sẽ được thực hiện khác nhau ở 1 số điểm)
Ưu điểm: (Xem thêm ở đây: https://github.com/github/view_component#why-should-i-use-components)
(1) Tách biệt logic ra khỏi views và nằm trong 1 ruby class riêng biệt
(2) Loại bỏ khả năng sử dụng 1 biến instance (@) ở trong nhiều partials như trước đây (bắt buộc phải truyền biến từ ngoài vào component) => Việc tìm nguồn gốc của biến sử dụng dễ dàng hơn
(3) view_component nhanh hơn partials ~10 lần (https://github.com/github/view_component/blob/master/performance/benchmark.rb)
(4) Dễ dàng tái sử dụng view_component template bằng cách inherit từ component khác
(5) Unit-test view_component nhanh + dễ dàng hơn partial
(6) view_component khuyến khích việc cấu trúc CSS & JS đi theo component
Tuy là ưu điểm nhưng nếu phân tích kỹ ra thì cũng không ưu lắm:
- Đối (1) và (2), mặc dù có cản trở được nhược điểm của helpers & partials tuy nhiên không phải là không có cách để vẫn mắc lại những lỗi cũ này. Ví dụ:
# controllers/posts_controller.rb
class PostsController < ApplicationController
attr_accessor :var_1
def show
@post = Post.find(params[:id])
render(PostShowComponent.new(post: @post))
end
def index
@posts = Post.all
render(PostIndexComponent.new(post: @post))
end
end
# component/base_component.rb
class BaseComponent < ViewComponent::Base
delegate :var_1, to: :controller
end
# components/post_index_component.rb
class PostIndexComponent < BaseComponent
end
# components/post_index_component.html.slim
= var_1 = "haha, I changed it even if others might need it not to be changed"
= "I'm trying to reuse #{var_1.to_s} even if it's might be out of its original context"
- Trong ví dụ trên ta thấy do chúng ta có thể truy cập
controller
khi subclass ViewComponent::Base cho nên chúng ta hoàn toàn có thể truy cậpvar_1
- được tạo ra bởi controller. Vì vậy nếu trong controller đang gặp vấn đề về việc có quá nhiều nơi đang thay đổi var_1 thì cũng vẫn sẽ dẫn tới có bug khó debug khi render post_index_component ở view khác với view ban đầu nó được sử dụng (tương tự như với partial). Để xử lý bad practice này thì cần convention cho source code chứ view_component không thể giúp mình được. Với convention thì ta có thể xử lý được bad practice này với cả partial và view_component, ví dụ:
Đối với partials:
- Chỉ nê sử dụng biến từ local_assigns để render giao diện
- Không xài ruby để set biến ra ngoài phạm vi của partial
Đối với view_component:
- Chỉ được sử dụng biến truyền vào initialize để render giao diện
- Không set biến ra ngoài phạm vi của component
Nói tóm lại, theo quan điểm của em thì (1) và (2) - ưu điểm về data flow được nhắc tới trong https://github.com/github/view_component#data-flow không nên được coi là ưu điểm của view_component so với partials
-
Đối với (5), việc unit test cho view_component không hẳn mang lại lợi ích lớn. Xem https://dhh.dk/2014/test-induced-design-damage.html và https://signalvnoise.com/posts/3159-testing-like-the-tsa, 2 bài viết từ creator của RoR. Trừ khi chúng ta muốn sử dụng Unit-Test để bảo vệ các component base của design system của mình.
-
Đối với (3), (4), (6) thì là chính xác
Còn nữa, kiến trúc component khuyến khích việc chia nhỏ view thành nhiều component để có thể sử dụng lại, mở rộng + áp dụng design system. Vậy nên, nếu chỉ đơn giản chuyển đổi partial thành component có tên tương ứng thì em nghĩ là mình đã bỏ qua 1 phần rất quan trọng của kiến trúc component. Tham khảo cách GitHub xây dựng view_component (https://github.com/primer/view_components) cho Primer Design System của họ tương tự Primer React (https://github.com/primer/components)