kiến thức Chia sẻ kinh nghiệm về Repository pattern

hoctrokha

Member
Chào mọi người,
Hôm nay lượn lờ thấy có 1 topic nói về repository pattern anh em bàn tán sôi nổi quá:
https://voz.vn/t/thao-luan-repository-pattern-la-cai-bullsh-t-nhat-khi-da-co-orm-framework.490455/

Khổ cái mình không có nhiều thời gian nên không thể nào follow hết cả 10 trang comment được, nhưng nhìn chung mình thấy vấn đề mọi người đang tranh cãi là:
  • Repository pattern có phải là BS không?
  • Có nên abstract cái ORM không?

Thấy ỏm tỏi quá nên mình viết 1 bài chia sẻ kiến thức của mình về repository pattern, nếu có gì hơi lạc đề hoặc không đúng với những gì mọi người đang thảo luận trong bài kia thì cũng mong mọi người bỏ qua, cứ xem như đây là 1 bài chia sẻ kiến thức là được.

Một xíu về bản thân thì mình hiện đang làm technical architect cho một công ty ở việt nam thôi, không phải làm cho amazone hay google j hết.
Tất cả kiến thức mình có đều từ kinh nghiệm bản thân mà ra thôi.

Ok, trả lời luôn với mọi người là repository pattern vừa BS vừa không hề BS.

Nhưng đầu tiên, Repository pattern dùng để abstract cái ORM đúng là BS.

Vâng nó đúng là BS, lý do nó BS thì mình đoán mọi người cũng đã nói nhiều trong post kia. Mình chỉ muốn nói thêm về trải nghiệm của mình với nó thôi.
Hồi sinh viên chắc ai cũng được thầy cô hướng dẫn mô hình ba lớp, n lớp các thứ, theo lý thuyết thì nó abstract cách lấy data, sau này thay thế tầng đó thì chỉ cần viết lại là xong. Nghe đúng là tuyệt vời và mình vẫn thấy nhiều người làm theo kiểu này, cho dù họ chưa hề có kinh nghiệm về việc thay nguyên tầng DAL trong 1 project lâu năm (chính mình nhiều năm trước cũng đã làm y chang như vậy).
Tất nhiên dần dần những "củ khoai" của tầng DAL cũng lộ diện khiến ai cũng bực mình. Nào là code bị lặp lại, gần như phải cover toàn bộ các API của ORM, rồi về transaction, làm sao để giữ transaction giữa các repository mà vẫn đảm bảo được tính đóng gói, sự abstract của tầng DAL ...

Rồi tiếp đến nếu bạn viết test cho 1 controller thì sao?
Đến bước viết test thì không thể nào các bạn mock nguyên cả tầng DAL được, các bạn phải mock thằng DB bằng in-memory db chứ. Mà in-memory db lại được cung cấp bởi thằng ORM.
OH sh*t, vậy việc abstract ORM của các bạn còn ý nghĩa gì nữa khi test của các bạn bị couple với ORM?
Kinh nghiệm của mình là "Tránh tối đa việc mock thư viện bạn đang dùng". Ví dụ bạn dùng EF thì đừng bao giờ đi mock EF, ở dưới client side bạn dùng axios thì đừng bao giờ mock axios, bởi nó là một phần trong code của các bạn, là một phần của hệ thống.
Trên production bọn nó nói chuyện với nhau, tương tác với nhau, nhưng khi test các bạn quăng 1 thằng fake vào thì khả năng chạy thật bị lỗi là điều dễ hiểu.
Thay vào đó hãy mock các "edge", mock db để ORM nó query, mock các api để trả về data cho axios ...
OK, vậy nếu theo cách tiếp cận đó thì việc thay tầng DAL hoặc thay ORM đúng là thảm cmn họa.
Các bạn sẽ phải viết lại tất cả các test ... coi như toang luôn dự án chứ còn j nữa.

Có thể các bạn sẽ hỏi: "chứ mình muốn đổi DB từ NoSQL qua SQL bởi hiện có những hạn chế, theo chủ thớt nói thì chịu ah?"
Ừ thì đập lại code build lại thôi, đó cũng là lý do microservice ra đời, :D
Cố gắng làm theo microservice để tránh những rủi do kiểu đó nhé, cố gắng đập đi build lại trong vòng 2 tuần.

Vậy khi nào repository pattern không phải BS?
Tất nhiên là khi mới tốt nghiệp repository là thần thánh rồi, :beauty: Đùa thôi.

Trường hợp 1: CQRS

Khi mình bắt đầu thử làm với CQRS thì tự nhiên repository là một thứ được áp dụng vào khá tự nhiên.
Các repository giờ không còn là proxy để các bạn truy vấn các bảng dưới db nữa, nó sẽ thành repository cho các "Aggregate root".
Mục đích của việc dùng repository trong hoàn cảnh này không phải để thay ORM hay là thay tất cả Aggregate root, mà chỉ đơn giản là nó phù hợp thôi.
Nhưng chỉ nên dùng repository cho bên write thôi, còn bên read thì mình dùng thẳng ORM luôn, việc dùng repository để lấy cả Aggregate root ra là điều không cần thiết.
Mình không nghĩ mình cần giải thích thêm vì nếu bạn đã biết CQRS, bạn có lẽ đã hiểu, nếu bạn chưa biết, khả năng cao giải thích cũng vậy.


Trường hợp 2: ORM không hỗ trợ in-memory db

nếu ORM các bạn dùng đủ ngon, có hỗ trợ In-Memory db thì khỏi nói, cứ thế mà viết test thôi. Nhưng nếu ORM của các bạn ko hỗ trợ thì khi test các bạn có 2 option:
  • dùng docker tạo 1 db lên dùng chung cho tất cả các test: cái này tù chày, chậm và dễ sinh ra các flaky test do các test chạy song song
  • dùng repository pattern và mock tất cả các method khi test => max tù chày và độ confident cực thấp

Nếu bạn làm theo TDD thì dùng docker là điều ko thể, ko ai ngồi đợi 1 phút để có kết quả test cho 1 unit test cả.
Bởi vậy bắt buộc phải dùng repository pattern trong trường hợp này, nhưng tốt nhất bạn nên chọn ORM cẩn thận, không bao giờ chọn mấy thằng ko hỗ trợ in-memory db nhé.

Kết luận
Cũng chả có kết luận nào mang tính đao to búa lớn đâu, các bạn nếu không làm CQRS thì mình nghĩ nên dẹp repository pattern đi, chọn ORM cho chuẩn và tập trung viết test cho đàng hoàng.
Code thì lỗi nhoe mà ngồi đó pattern này với chả pattern nọ.
 
Cuối cùng cũng có người hiểu tôi. Cái bullshit nó mang lại là đánh đổi quá lớn, phát sinh nhiều vấn đề tốn effort ko cần thiết.

Tôi vẫn ủng hộ 3 layers mà dùng Repository trong DDD để abstract tầng pesistance, nhưng viết kiểu Generic Repostory thì phải xem lại. Một số dự án nhỏ thì làm 2 layers luôn, xài trực tiếp ORM trong services.

Đó là kinh nghiệm qua nhiều dự án thực tế của tôi. Lúc setup thì làm cho hoành tráng, tính rất nhiều thứ nhưng lúc chạy thật thì nhiều khi effort bỏ ra đập đi xây lại còn đỡ hơn đi maintance cái đống ấy.

Mấy anh trẻ đâu có hiểu, thấy 2 layers + tight couple thì giãy nãy lên là phải generic, abstract này nọ cho hoành tráng. Cuối cùng người mệt là các a thôi.
FY7e6U1.png
 
ủa a viết bài cho đọc mà còn viết tắt, chúng tôi phải google cái đống lười biếng của a à.
Lười google thì đừng theo nghề này.
Nghề này đi đâu chả có viết tắt, nhiều chữ viết tắt lên google search còn ko ra nữa kìa.
BS nó ko phải từ hay, ai lại viết ra làm gì.
Bớt cằn nhằn lại.
 
Ngôn từ không phù hợp
Lười google thì đừng theo nghề này.
Nghề này đi đâu chả có viết tắt, nhiều chữ viết tắt lên google search còn ko ra nữa kìa.
BS nó ko phải từ hay, ai lại viết ra làm gì.
Bớt cằn nhằn lại.
thôi đi. viết bài cho ng khác k chỉnh chu. góp ý thì nhảy dựng loz lên à
 
Trước code java android thì thằng réponse là cái thằng đứng sau usecase chịu trách nhiệm data sẽ lấy từ nguồn nào memory sqlite hay gọi lai api. Chắc cũng giống backend nhỉ
 
Thời buổi giờ microservice và docker lên ngôi, và nó là trend tốt, làm dự án mới thì nên chia nhỏ ra cho dễ control, tất nhiên phân mảnh quá nhỏ thì lại khó control. Tất cả các components node đều phải được thống nhất về cách viết, thư viện sử dụng common

Còn làm nhồi nhét nhiều layer trong 1 project, thì có pattern kiểu lol gì thì cũng phát sinh nhiều vấn đề khi đập sửa, viết test, scale v.v... Nhưng vì đặc thù có rất nhiều project cũ cần tiếp tục maintain và develop thêm thì cũng phải chịu thôi.

Tư tưởng develop nên có 1 cái gọi là "balance" architect, chứ ko phải cứ đi chọn những cái nhất nhất, thì khi đụng chuyện đặc biệt là ngay lập tức nó thành nhất cư ngay
 
Thời buổi giờ microservice và docker lên ngôi, và nó là trend tốt, làm dự án mới thì nên chia nhỏ ra cho dễ control, tất nhiên phân mảnh quá nhỏ thì lại khó control. Tất cả các components node đều phải được thống nhất về cách viết, thư viện sử dụng common

Còn làm nhồi nhét nhiều layer trong 1 project, thì có pattern kiểu lol gì thì cũng phát sinh nhiều vấn đề khi đập sửa, viết test, scale v.v... Nhưng vì đặc thù có rất nhiều project cũ cần tiếp tục maintain và develop thêm thì cũng phải chịu thôi.

Tư tưởng develop nên có 1 cái gọi là "balance" architect, chứ ko phải cứ đi chọn những cái nhất nhất, thì khi đụng chuyện đặc biệt là ngay lập tức nó thành nhất cư ngay
Chia nhỏ theo kiểu micro services thì ok, còn chia nhỏ theo kiểu business, dal..theo layer thành các project nhỏ. Có nghĩa ko!?
 
Last edited:
Ông nên chú thích BS là gì, tôi làm culi web 5 năm nay rồi, đọc BS cứ ngỡ tech hay khái niệm nào mới, search google phọt shjt mà ko ra
KKvIDPX.png


https://www.google.com/search?q=rep...i57j33i21l2.1521j0j1&sourceid=chrome&ie=UTF-8

Mà cũng có thể tư duy của tech lít nó khác với culi như mình nên mình ko hiểu được. Haizz.
 
Cuối cùng cũng có người hiểu tôi. Cái bullshit nó mang lại là đánh đổi quá lớn, phát sinh nhiều vấn đề tốn effort ko cần thiết.

Tôi vẫn ủng hộ 3 layers mà dùng Repository trong DDD để abstract tầng pesistance, nhưng viết kiểu Generic Repostory thì phải xem lại. Một số dự án nhỏ thì làm 2 layers luôn, xài trực tiếp ORM trong services.

Đó là kinh nghiệm qua nhiều dự án thực tế của tôi. Lúc setup thì làm cho hoành tráng, tính rất nhiều thứ nhưng lúc chạy thật thì nhiều khi effort bỏ ra đập đi xây lại còn đỡ hơn đi maintance cái đống ấy.

Mấy anh trẻ đâu có hiểu, thấy 2 layers + tight couple thì giãy nãy lên là phải generic, abstract này nọ cho hoành tráng. Cuối cùng người mệt là các a thôi.
FY7e6U1.png
Tại anh bay vài chửi bới bảo nó vô dụng trước thôi. Chứ có nói repo là thần thánh bắt buộc sử dụng đâu.
 
Mọi người đang bị hyped microservices quá rồi. Nó chả phải cái gì thần thần thánh đâu, làm việc với nó từ 2017 đến giờ thì quan điểm của mình luôn là chọn modular monolithic hơn là microservices.
Hãy cố gắng giải quyết vấn đề bằng monolithic, khi nào thấy pros nghiêng hẳn về microservices thì mới nên sử dụng.
 
Mọi người đang bị hyped microservices quá rồi. Nó chả phải cái gì thần thần thánh đâu, làm việc với nó từ 2017 đến giờ thì quan điểm của mình luôn là chọn modular monolithic hơn là microservices.
Hãy cố gắng giải quyết vấn đề bằng monolithic, khi nào thấy pros nghiêng hẳn về microservices thì mới nên sử dụng.
Chuẩn rồi a. Lúc nào thấy chắc chắn phải chuyển thì chuyển
 
Chuẩn rồi a. Lúc nào thấy chắc chắn phải chuyển thì chuyển
Có chuyển cũng chỉ chuyển từng phần nào đó cần thiết.

Ở đây có bạn nào “may mắn” được/bị làm việc với các hệ thống “có vẻ” là microservices sẽ hiểu cảm giác khổ sở vê lờ khi biz nó đòi hỏi một cái feature gì đó mà cái “microservices “ hiện tại nó không đáp ứng được.

Khi đó lại phải ngồi nghĩ cách cheating, hacking, adhoc… blabla để workaround được cái yêu cầu. Lúc này chỉ muốn đập cmn hết đi làm monolith.

Cái này là hệ quả của việc triển khai “microservices” theo ý chí của tech mà không xét đến biz.
 
Mọi người đang bị hyped microservices quá rồi. Nó chả phải cái gì thần thần thánh đâu, làm việc với nó từ 2017 đến giờ thì quan điểm của mình luôn là chọn modular monolithic hơn là microservices.
Hãy cố gắng giải quyết vấn đề bằng monolithic, khi nào thấy pros nghiêng hẳn về microservices thì mới nên sử dụng.
Microservice là phải cân bằng. Không phải cứ bẻ nhỏ ra thành microservice, như thế làm mấy cái nghiệp vụ có luồng dài thì auto chết.
Mặt khác 1 project có cấu trúc monolithic chuẩn thì sẽ dễ maintain và nâng cấp rất nhiều.
Nên thực tế phải là xây dựng nhiều project monolithic chuẩn xong tìm cách kết nối nó với nhau thì hợp lý hơn. (cái này phụ thuộc lớn với biz mà không phải là tech)
 
Không có gì sai với monolith nếu bạn chưa rõ mình cần làm gì, nghiệp vụ như thế nào ...
Thường thì nên build monolith trước, khi mọi thứ đã rõ ràng rồi thì mới tách ra micro service.
Vấn đề của monolith thì nhiều, search google là ra ngay thôi, micro-service cũng có vấn đề riêng của nó.
Tuy nhiên chày cối giải quyết vấn đề bằng monolith trước khi move qua microservice không phải là ý hay. Bạn phải nhìn thấy tương lai của dự án, mức tăng trưởng thế nào, tương lai sẽ có bao nhiêu dev ...
Bỏ qua tất cả các vấn đề về kỹ thuật, microservice sẽ giải quyết được vấn đề của tổ chức khi nó grow, vấn đề fail fast ... những điều mà monolith ko thể giải quyết đc.
Còn nghiệp vụ luồng dài mình vẫn k hiểu tại sao lại auto chết đc, mình tưởng đây là lợi thế của micro service khi kết hợp với một eventbus kiểu kafka chứ nhỉ. Tất nhiên bạn vẫn có thể dùng kafka với monolith, nhưng ý mình là bạn ko thể nói nó auto chết đc.
 
Không có gì sai với monolith nếu bạn chưa rõ mình cần làm gì, nghiệp vụ như thế nào ...
Thường thì nên build monolith trước, khi mọi thứ đã rõ ràng rồi thì mới tách ra micro service.
Vấn đề của monolith thì nhiều, search google là ra ngay thôi, micro-service cũng có vấn đề riêng của nó.
Tuy nhiên chày cối giải quyết vấn đề bằng monolith trước khi move qua microservice không phải là ý hay. Bạn phải nhìn thấy tương lai của dự án, mức tăng trưởng thế nào, tương lai sẽ có bao nhiêu dev ...
Bỏ qua tất cả các vấn đề về kỹ thuật, microservice sẽ giải quyết được vấn đề của tổ chức khi nó grow, vấn đề fail fast ... những điều mà monolith ko thể giải quyết đc.
Còn nghiệp vụ luồng dài mình vẫn k hiểu tại sao lại auto chết đc, mình tưởng đây là lợi thế của micro service khi kết hợp với một eventbus kiểu kafka chứ nhỉ. Tất nhiên bạn vẫn có thể dùng kafka với monolith, nhưng ý mình là bạn ko thể nói nó auto chết đc.

Luồn dài chắc là transaction trên nhiều service ấy. Làm sao rollback được. Mặc dù có partern như saga hay 2phase commit. Nhưng nó khó hơn mono nhiều.

Sent using vozFApp
 
Back
Top