thảo luận [Thảo luận] Repository Pattern là cái bullsh*t nhất khi đã có ORM framework?

Có nên sử dụng repository pattern khi đã có ORM framework rồi ko?

  • Có - có lợi nhiều lắm để tôi cmt bên dưới

    Votes: 29 19.3%
  • Có - thấy người ta hay xài thì mình xài thôi (chắc là cũng có lợi gì đó nhưng dek biết)

    Votes: 25 16.7%
  • Không - tốn công vô ích, đẽ ra cho thêm việc phức tạp chứ ko lợi lộc gì đáng kể

    Votes: 19 12.7%
  • Không - code nhiều mệt vãi, xài trực tiếp ORM cho nhanh (cũng ko biết là có lợi hay ko)

    Votes: 20 13.3%
  • Tuỳ - tuỳ dự án, tuỳ yêu cầu

    Votes: 57 38.0%

  • Total voters
    150
Share các thím 1 study case apply repository. Tôi có tình huống thế này:

Trong hệ thống e-commerce, model SalesOrder của tôi gồm những property sau:

SalesOrder
-> Customer information
-> Shipping/Billing address
-> Item list

Tôi có các lớp Services xử lý business logic, nhận input đầu vào là 1 object SalesOrder. (Gồm các nghiệp vụ trừ tồn, pick hàng, đóng gói, vận chuyển logistic v.v..)

Một ngày đẹp trời, công ty tôi ký hợp đồng với 1 đối tác bên ngoài, vận hành khâu xử lý đơn hàng. Trong hợp đồng ghi rõ là công ty tôi không được phép lưu dữ liệu khách hàng, thông tin khách hàng buộc phải gọi API về xử lý.

————————

Tôi xử dụng pattern repository từ đầu, trong repository, tôi viết các logic để build 1 model SalesOrder hoàn chỉnh (bao gồm collect thông tin các property customer, address, items) với SalesOrderRepository.get(order_code) trả về 1 model SalesOrder.

Với tình huống trên, tôi có 2 trường hợp:
  • Đơn hàng thường, thông tin khách hàng tôi query trực tiếp trong DB của công ty
  • Đơn hàng đối tác, thông tin khách hàng tôi gọi API để fetch về

Khi apply, tôi chỉ cần update ở phần repository, các lớp service business logic không update gì.

(*) Thông tin khách hàng là dữ liệu input để xử lý, không thay đổi trong suốt quá trình vận hành.

Case của thím tôi cũng từng làm rồi, nhưng dùng API của bên thứ 3 nó lại phát sinh nhiều vấn đề như bên đó đổi schema không giống db của mình, response time chậm hoặc timeout, khó làm transaction cho nhiều api create/update... Thế nên bên tôi chốt làm riêng cái service mới chứ không phải repository.

Tôi không chê repository pattern dở, chỉ là thấy giờ ít nơi xài thôi.

Sent from Samsung SM-G973F using vozFApp
 
Share các thím 1 study case apply repository. Tôi có tình huống thế này:

Trong hệ thống e-commerce, model SalesOrder của tôi gồm những property sau:

SalesOrder
-> Customer information
-> Shipping/Billing address
-> Item list

Tôi có các lớp Services xử lý business logic, nhận input đầu vào là 1 object SalesOrder. (Gồm các nghiệp vụ trừ tồn, pick hàng, đóng gói, vận chuyển logistic v.v..)

Một ngày đẹp trời, công ty tôi ký hợp đồng với 1 đối tác bên ngoài, vận hành khâu xử lý đơn hàng. Trong hợp đồng ghi rõ là công ty tôi không được phép lưu dữ liệu khách hàng, thông tin khách hàng buộc phải gọi API về xử lý.

————————

Tôi xử dụng pattern repository từ đầu, trong repository, tôi viết các logic để build 1 model SalesOrder hoàn chỉnh (bao gồm collect thông tin các property customer, address, items) với SalesOrderRepository.get(order_code) trả về 1 model SalesOrder.

Với tình huống trên, tôi có 2 trường hợp:
  • Đơn hàng thường, thông tin khách hàng tôi query trực tiếp trong DB của công ty
  • Đơn hàng đối tác, thông tin khách hàng tôi gọi API để fetch về

Khi apply, tôi chỉ cần update ở phần repository, các lớp service business logic không update gì.

(*) Thông tin khách hàng là dữ liệu input để xử lý, không thay đổi trong suốt quá trình vận hành.

@tdat00 thím này trả lời 1 ý rồi đấy.

Còn cái nữa là trường hợp của thím có thể custom DbSet<SalesOrder>. Cái DbSet<SalesOrder> của Entity Framework chính là cái SalesOrderRepository đấy.

Thấy đang phát minh lại cái bánh xe chưa?
0FFPAjM.png
 
Case của thím tôi cũng từng làm rồi, nhưng dùng API của bên thứ 3 nó lại phát sinh nhiều vấn đề như bên đó đổi schema không giống db của mình, response time chậm hoặc timeout, khó làm transaction cho nhiều api create/update... Thế nên bên tôi chốt làm riêng cái service mới chứ không phải repository.

Tôi không chê repository pattern dở, chỉ là thấy giờ ít nơi xài thôi.

Sent from Samsung SM-G973F using vozFApp

Vấn đề là cần thêm 1 cái services trong khi nó chỉ là adapter pattern thôi. :beat_brick:
 
Nếu xài dapper thì thằng dapper này coi như là extensioncủa Ado.net thôi, cái repository pattern chính là data access layer nên tôi ko tranh cãi, vẫn nên có 1 data access layer.





2 anh này... vấn đề tôi muốn nói là thậm chí cái thằng build repository nó "khôn" thì cũng là thừa vì ORM như Entity Framework/Hibernate nó làm hết rồi. Các anh build lại là phát minh lại cái banh xe nên tôi mới nói bullshit!

Giả sử ORM chỉ là miếng thịt bò, miếng cà chua trên 1 cái pizza thôi.

Còn Repo nó là cái bánh pizza. trong đó anh có thể có thêm hải sản ( ado) hoặc phô mai ( dapper) chạy trong đó cũng đc.

Anh ăn cái bánh có mỗi thịt bò + cà chua vẫn oke. Nhưng nếu tôi cần 1 service chạy pipeline qua nhiều cái services có cả ado, dapper thì dùng repo là right case rồi.

Cái tôi và anh kia nói là cái thằng build repo ngu có ý của nó đấy. Do anh dùng dao mổ bò đi thịt gà rồi thấy nó thừa thôi.
 
Giả sử ORM chỉ là miếng thịt bò, miếng cà chua trên 1 cái pizza thôi.

Còn Repo nó là cái bánh pizza. trong đó anh có thể có thêm hải sản ( ado) hoặc phô mai ( dapper) chạy trong đó cũng đc.

Anh ăn cái bánh có mỗi thịt bò + cà chua vẫn oke. Nhưng nếu tôi cần 1 service chạy pipeline qua nhiều cái services có cả ado, dapper thì dùng repo là right case rồi.

Cái tôi và anh kia nói là cái thằng build repo ngu có ý của nó đấy. Do anh dùng dao mổ bò đi thịt gà rồi thấy nó thừa thôi.

A nói sai rồi. ORM là cái miếng pizza luôn.

Repository là cái phiên bản Pizza quái thai, khuyết tật mà các anh cố build để phát minh lại ORM. Cái ví dụ anh nói:
" Nhưng nếu tôi cần 1 service chạy pipeline qua nhiều cái services có cả ado, dapper thì dùng repo là right case rồi."

Trường hợp này là service riêng chứ chả liên quan repository hay ORM cả.

Nhưng nếu a vẫn nhất quyết xài Repository để anh tuỳ chỉnh thì khi dùng ORM a vẫn có thể custom DbSet<>, dbContext để anh gọi ef, ado, dapper... nên cũng chả cần Repositories.

Bản thân thằng DbSet<> nó là cái repository rồi, chỉ việc custom IQueryable là có thể access data từ database hay gọi API khác y như cách anh custom ở Repository của a.
 
Last edited:
Vấn đề là cần thêm 1 cái services trong khi nó chỉ là adapter pattern thôi. :beat_brick:
Case của tôi ban đầu cũng nghĩ là adapter thôi, nhưng tụi 3rd kia nó hầm bà lằng quá, thậm chí bên đó còn tắt luôn dev server vào cuối tuần nên tụi tôi muốn OT cũng không được. Thế là phải đẻ thêm 1 cái dummy mock server dể giả lập mớ API đó. Thấy vui hem
lBAzaFs.png
 
Cái hàm đó anh viết trực tiếp ở service. Lúc này sẽ inject dbContext vào service. dbContext sẽ THAY THẾ cho repository của anh.
Ví du: IProductManagementSerivce.Save(Product product);

Còn trường hợp muốn sử dụng hàm đó ở nhiều service thì anh viết extension methods cho dbContext, để gom cái logic đó vào 1 chổ.

....

Cũng như trên, anh tạo extension methods cho dbContext hoặc DbSet<Product>, hoặc helper class để gom cái logic đó lại thôi. Cái hàm này sẽ đứng ngang hàng với các hàm save, update của ORM. Nó ko phải là 1 layer cao hơn như Repository để wrap cái logic này lại.

Ở đầu topic tui có nêu 2 ví dụ cần repository pattern mà anh em ko ai để ý. Chủ thớt thì trả lời như trên.

Tui có ý vầy thôi.

Ông thớt @Pepe.The.Frog ơi, cái cách giải quyết của ông chỉ là ông cố tình bỏ đi cái lớp Repository rồi đưa logic của nó lên lớp service hoặc static class hoặc extension methods. Rồi ông nhấn mạnh ko cần Repo Pattern. Ông bỏ Repository Pattern để đưa vào 1 đống anti pattern khác mà vẫn cho là đúng thì thôi.

Rồi DbContext rồi extension method nó là của Microsoft.net. thế giới lập trình nó ko chỉ có .net. Nó còn có Java,Python, Php,... nên cái Repository Pattern nó là cái abstract chung cho mọi ngôn ngữ. Nó giải quyết vấn đề chung.

Ông còn nói đũa với chén là một thì thôi tui đi. Nói gì nữa giờ. 🤗
 
Case của tôi ban đầu cũng nghĩ là adapter thôi, nhưng tụi 3rd kia nó hầm bà lằng quá, thậm chí bên đó còn tắt luôn dev server vào cuối tuần nên tụi tôi muốn OT cũng không được. Thế là phải đẻ thêm 1 cái dummy mock server dể giả lập mớ API đó. Thấy vui hem
lBAzaFs.png
if (today = saturay or sunday) return mock data :feel_good:
 
Ơ quote nhầm
Ở đầu topic tui có nêu 2 ví dụ cần repository pattern mà anh em ko ai để ý. Chủ thớt thì trả lời như trên.

Tui có ý vầy thôi.

Ông thớt @Pepe.The.Frog ơi, cái cách giải quyết của ông chỉ là ông cố tình bỏ đi cái lớp Repository rồi đưa logic của nó lên lớp service hoặc static class hoặc extension methods. Rồi ông nhấn mạnh ko cần Repo Pattern. Ông bỏ Repository Pattern để đưa vào 1 đống anti pattern khác mà vẫn cho là đúng thì thôi.

Rồi DbContext rồi extension method nó là của Microsoft.net. thế giới lập trình nó ko chỉ có .net. Nó còn có Java,Python, Php,... nên cái Repository Pattern nó là cái abstract chung cho mọi ngôn ngữ. Nó giải quyết vấn đề chung.

Ông còn nói đũa với chén là một thì thôi tui đi. Nói gì nữa giờ. 🤗

Chuẩn rồi, ORM extension :LOL:
Trong khi ORM và dapper cơ chế chạy khác nhau, chính ra việc này mới là chế tạo lại cái bánh xe
 
Last edited:
Ở đầu topic tui có nêu 2 ví dụ cần repository pattern mà anh em ko ai để ý. Chủ thớt thì trả lời như trên.

Tui có ý vầy thôi.

Ông thớt @Pepe.The.Frog ơi, cái cách giải quyết của ông chỉ là ông cố tình bỏ đi cái lớp Repository rồi đưa logic của nó lên lớp service hoặc static class hoặc extension methods. Rồi ông nhấn mạnh ko cần Repo Pattern. Ông bỏ Repository Pattern để đưa vào 1 đống anti pattern khác mà vẫn cho là đúng thì thôi.

=> Anh nói những cái tôi đưa vào là anti pattern?? WTF, mới anh chứng minh nó có bất cập gì đi

Rồi DbContext rồi extension method nó là của Microsoft.net. thế giới lập trình nó ko chỉ có .net. Nó còn có Java,Python, Php,... nên cái Repository Pattern nó là cái abstract chung cho mọi ngôn ngữ. Nó giải quyết vấn đề chung.

Ông còn nói đũa với chén là một thì thôi tui đi. Nói gì nữa giờ. 🤗

Đúng, nó ko chỉ có .Net nhưng tech stack khác đều có những cái tương đương mà. Và tôi tin mổi stack khác đều có 1 ORM tương ứng support đầy đủ rồi.

Ví dụ Java thì anh xài Hibernate thôi. Hay anh định build repository on top of hibernate?

qZV215Z.png
 
Ở đầu topic tui có nêu 2 ví dụ cần repository pattern mà anh em ko ai để ý. Chủ thớt thì trả lời như trên.

Tui có ý vầy thôi.

Ông thớt @Pepe.The.Frog ơi, cái cách giải quyết của ông chỉ là ông cố tình bỏ đi cái lớp Repository rồi đưa logic của nó lên lớp service hoặc static class hoặc extension methods. Rồi ông nhấn mạnh ko cần Repo Pattern. Ông bỏ Repository Pattern để đưa vào 1 đống anti pattern khác mà vẫn cho là đúng thì thôi.

Rồi DbContext rồi extension method nó là của Microsoft.net. thế giới lập trình nó ko chỉ có .net. Nó còn có Java,Python, Php,... nên cái Repository Pattern nó là cái abstract chung cho mọi ngôn ngữ. Nó giải quyết vấn đề chung.

Ông còn nói đũa với chén là một thì thôi tui đi. Nói gì nữa giờ. 🤗

Đồng ý với câu nói này nè. Bản chất công việc là nên tách việc get/set data vào 1 layer khác với layer business, tên gọi của layer đó có thể là repository nếu nó đơn giản, hoặc nếu phức tạp thì gọi là service cũng được. Còn việc extend class có sẵn hay làm lại từ đầu bằng thủ công mỹ nghệ, mỗi cái có ưu nhược điểm khác nhau, tùy case mà dùng.

if (today = saturay or sunday) return mock data :feel_good:

chúng tôi dùng env variable cho nó chuyên nghiệp nhé, dùng if cùi bép lắm
0kGF6mz.png
 
@Pepe.The.Frog Tui xài NHibernate hơn 6 năm. Từ 2010 đến 2016. Và vâng, tui xài Repository Pattern. Tui cũng ko hiểu với mô hình session như NHibernate thì anh ko xài Repository Pattern anh xài kiểu gì chia sẻ tôi biết.

Còn Helper Class aka Static class , Extension method là anti-pattern. Anh wtf tôi làm gì khi ai cũng biết điều đó? Còn tui chán lên chém gió vậy thôi. Chứng minh với anh có mang tui đồng nào nuôi con đâu. Thôi nhé.
 
=> Anh nói những cái tôi đưa vào là anti pattern?? WTF, mới anh chứng minh nó có bất cập gì đi



Đúng, nó ko chỉ có .Net nhưng tech stack khác đều có những cái tương đương mà. Và tôi tin mổi stack khác đều có 1 ORM tương ứng support đầy đủ rồi.

Ví dụ Java thì anh xài Hibernate thôi. Hay anh định build repository on top of hibernate?

qZV215Z.png
Ủa thế static method thì ông test kiểu gì? à à, quên mẹ mất, có cái thread ông ngồi chửi cái UN chết mẹ kìa nữa :(.
Thôi zí zái vào pattern gì cho mệt, cứ tống mẹ vào vài cái static class. Đấy, thỏa lòng anh chưa :ROFLMAO::ROFLMAO::ROFLMAO:
 
@Pepe.The.Frog Tui xài NHibernate hơn 6 năm. Từ 2010 đến 2016. Và vâng, tui xài Repository Pattern. Tui cũng ko hiểu với mô hình session như NHibernate thì anh ko xài Repository Pattern anh xài kiểu gì chia sẻ tôi biết.

Còn Helper Class aka Static class , Extension method là anti-pattern. Anh wtf tôi làm gì khi ai cũng biết điều đó? Còn tui chán lên chém gió vậy thôi. Chứng minh với ảnh có mang tui đồng nào nuôi con đâu. Thôi nhé.
Thôi bạn ah, chiều t6 rảnh rỗi vào đọc mấy cái thread trong này, tôi cay đến mức phải reg nick để phát biểu ý kiến, nhưng anh ếch kia vẫn ngồi trong cái giếng của ảnh, có nghe ai đâu :amazed:
 
Định comment mấy câu mà thấy chủ thớt cứ đòi "có code" nên đành đi ra vậy. Mấy năm rồi tôi có code nữa đâu :canny:
Ps: Topic có vẻ hơi căng nên cũng rén
 
Case của thím tôi cũng từng làm rồi, nhưng dùng API của bên thứ 3 nó lại phát sinh nhiều vấn đề như bên đó đổi schema không giống db của mình, response time chậm hoặc timeout, khó làm transaction cho nhiều api create/update... Thế nên bên tôi chốt làm riêng cái service mới chứ không phải repository.

Tôi không chê repository pattern dở, chỉ là thấy giờ ít nơi xài thôi.

Sent from Samsung SM-G973F using vozFApp
Các sếp họp với nhau, cam kết 2 tuần sau delivery, viết service mới sao thím! Người thì méo có, mà legacy logic thì đầy ai mà dám implement lại.

Với lại cái đoạn fetch thông tin khách hàng thì chỉ thuần read thôi chứ đâu có write gì đâu mà cần transaction. Logic repository đơn giản, fetch thông tin khách hàng không được thì quăng cái exception không query được đơn hàng, để retry lại thôi.

thím này trả lời 1 ý rồi đấy.

Còn cái nữa là trường hợp của thím có thể custom DbSet<SalesOrder>. Cái DbSet<SalesOrder> của Entity Framework chính là cái SalesOrderRepository đấy.

Thấy đang phát minh lại cái bánh xe chưa?
0FFPAjM.png
Nói là model SalesOrder vậy thôi, chứ các thông tin nó vẫn ở nằm các bảng con như (sales_orders, sales_order_customer, sales_order_address, sales_order_items)

Tôi đoán thím kiểu xài lazy load của ORM không biết đúng không, nhưng trong ngữ cảnh của tôi thì không xài lazyload. Fetch full object SalesOrder xong rồi mới process, và cái repository nó đảm bảo tính toàn vẹn của object SalesOrder

P/s các thím đừng cực đoan quá cái chuyện đúng sai, ăn thua cái ngữ cảnh mấy thím áp dụng thôi :). Khi các thím plan thì cũng nên xét thêm mấy yếu tố non-technical như resource hoặc policy nữa

Peace
 
cái này tuy vào định nghĩa orm là gì thôi, như trong bọn laravel, ruby on rails, thấy nó sài model, active, như là repo rồi, nên tạo ra repo nữa là sự rối rắm, còn trong java thì ko nó ko gom lại 1 chỗ, hoặc build sẳn như mấy framework kia , thì bắt buộc phải tạo ra 1 layer nữa
 
Đồng ý với câu nói này nè. Bản chất công việc là nên tách việc get/set data vào 1 layer khác với layer business, tên gọi của layer đó có thể là repository nếu nó đơn giản, hoặc nếu phức tạp thì gọi là service cũng được. Còn việc extend class có sẵn hay làm lại từ đầu bằng thủ công mỹ nghệ, mỗi cái có ưu nhược điểm khác nhau, tùy case mà dùng.

Cái "layer khác" đó chính là cái Interface IQueryable của bất kỳ ORM nào nó build cho các anh rồi đó. Chỉ là các anh ko thấy nên mới đi implement thêm cái Repository thôi.

IQueryable là abstraction để query data bất kể nó ở database/cloud/xml/nosql... Có y như cái Repository của các a chưa? :look_down:

@Pepe.The.Frog Tui xài NHibernate hơn 6 năm. Từ 2010 đến 2016. Và vâng, tui xài Repository Pattern. Tui cũng ko hiểu với mô hình session như NHibernate thì anh ko xài Repository Pattern anh xài kiểu gì chia sẻ tôi biết.

Còn Helper Class aka Static class , Extension method là anti-pattern. Anh wtf tôi làm gì khi ai cũng biết điều đó? Còn tui chán lên chém gió vậy thôi. Chứng minh với anh có mang tui đồng nào nuôi con đâu. Thôi nhé.

Ủa thế static method thì ông test kiểu gì? à à, quên mẹ mất, có cái thread ông ngồi chửi cái UN chết mẹ kìa nữa :(.
Thôi zí zái vào pattern gì cho mệt, cứ tống mẹ vào vài cái static class. Đấy, thỏa lòng anh chưa :ROFLMAO::ROFLMAO::ROFLMAO:

Tôi ví dụ extension method là ví dụ 1 cách thôi, nếu cần test thì lại xài inheritance, overriding... vẫn đáp ứng đc việc test. OK chưa?

Thôi bạn ah, chiều t6 rảnh rỗi vào đọc mấy cái thread trong này, tôi cay đến mức phải reg nick để phát biểu ý kiến, nhưng anh ếch kia vẫn ngồi trong cái giếng của ảnh, có nghe ai đâu :amazed:

Tôi cố tình kích cho các anh nhảy vào đấy. Anh nhảy vào là tôi thành công rồi. :misdoubt:
 
Các sếp họp với nhau, cam kết 2 tuần sau delivery, viết service mới sao thím! Người thì méo có, mà legacy logic thì đầy ai mà dám implement lại.

Với lại cái đoạn fetch thông tin khách hàng thì chỉ thuần read thôi chứ đâu có write gì đâu mà cần transaction. Logic repository đơn giản, fetch thông tin khách hàng không được thì quăng cái exception không query được đơn hàng, để retry lại thôi.
Oh thì anh em share những vụ mình đã từng gặp để học hỏi lẫn nhau thôi, chứ có cách nào là phù hợp cho mọi hoàn cảnh đâu thím. Case của tôi chắc dính đến create/edit nên nó phưc tạp hơn.

Nhắc lại cái mớ API kia tôi vẫn còn cay ấy chứ, trong sprint dev test ngon lành, qua đầu tuần sau demo cho sếp nó tạch mịa đi, lý do là bên 3rd kia mới deploy cái breaking change vào T6
jA4zSIh.png
 
Back
Top