thảo luận Vấn đề về separate Repository/Service/Controller

  • Người tạo chủ đề Người tạo chủ đề soledad86
  • Ngày bắt đầu Ngày bắt đầu
Các anh toàn đề xuất bỏ service, theo tôi bỏ repo là hợp ní, model service là quá đủ.
Ai phản bác cho xin lí do cái repo càn tồn tại là gì.

Với mình thằng sếp từng bộ phận (x-controller)...nó sẽ sai thằng đệ tử thân tín (x-service) tìm cho nó các đối tác kinh doanh ... Khi đó thằng đệ tử thân tín (x-service) sẽ sai thằng em (x-repo) tìm cho nó các đối tác nội địa (internal) và thằng em khác (x-3rd-service) tìm các đối tác nước ngoài. Do đó thằng x-repo cần tồn tại để làm nhiệm vụ cho thằng x-service...=> cơ cấu nhiệm vụ được cấu trúc trên xuống, thằng sếp chỉ quan tâm và yêu cầu từ thằng em gần nhất...khi đó suy xét tội cũng rõ ràng hơn.
 
Với mình thằng sếp từng bộ phận (x-controller)...nó sẽ sai thằng đệ tử thân tín (x-service) tìm cho nó các đối tác kinh doanh ... Khi đó thằng đệ tử thân tín (x-service) sẽ sai thằng em (x-repo) tìm cho nó các đối tác nội địa (internal) và thằng em khác (x-3rd-service) tìm các đối tác nước ngoài. Do đó thằng x-repo cần tồn tại để làm nhiệm vụ cho thằng x-service...=> cơ cấu nhiệm vụ được cấu trúc trên xuống, thằng sếp chỉ quan tâm và yêu cầu từ thằng em gần nhất...khi đó suy xét tội cũng rõ ràng hơn.
Thằng repo chả để làm gì chỉ rối thêm. Tôi gọi thẳng model luôn.
 
Thằng repo chả để làm gì chỉ rối thêm. Tôi gọi thẳng model luôn.

Mới v mà đã rối thì làm ăn gì nữa bác. Trong 3 layers, thằng repo như DAO..giao tiếp với DB. Thằng service như BUS...BUS thì ko được, ko nên giao tiếp với DB.
Vì nếu bác code như thế thì bác dường như là một anh thợ code không hơn không kém.
Mỗi ông mỗi nhiệm vụ...nếu một ông có từ 2 nhiệm vụ trở lên thì nên xem lại.
 
Mới v mà đã rối thì làm ăn gì nữa bác. Trong 3 layers, thằng repo như DAO..giao tiếp với DB. Thằng service như BUS...BUS thì ko được, ko nên giao tiếp với DB.
Vì nếu bác code như thế thì bác dường như là một anh thợ code không hơn không kém.
Mỗi ông mỗi nhiệm vụ...nếu một ông có từ 2 nhiệm vụ trở lên thì nên xem lại.
Tôi giao tiếp qua model mà. Repo cũng chỉ là wrap model lại thôi. Nhiều orm đã full chức năng rồi, thêm repo lại đi viết lại chả để làm gì.
Có Orm lại còn dùng Dao nữa rảnh thật.
Tôi đảm bảo bạn sẽ phải viết nhiều hàm giống nhau ở cả service và repo như 1 bác ở page 2 gọi là proxy function.
 
Sửa lần cuối:
^
Đây là vấn đề quản lý độ phức tạp của phần mềm. Không phải tự nhiên người ta nghĩ ra bao nhiêu kiến trúc, paradigms, design pattern, ddd... Nhiều kiến trúc đã lạc hậu, như mô hình ba lớp mà anh nói, nhiều design pattern đã bị coi là anti pattern. Nên ở đây cãi nhau cũng chả có gì lạ.

Tôi đọc source code cũng nhiều. Nhiều người đi code 20 năm mà code một dự án kiến trúc còn thay lên thay xuống. Thế mà có một cậu ở trên tự hào chỉ cần thay 1 config là đã có thể xyz...
 
Tôi giao tiếp qua model mà. Repo cũng chỉ là wrap model lại thôi. Nhiều orm đã full chức năng rồi, thêm repo lại đi viết lại chả để làm gì.
Có Orm lại còn dùng Dao nữa rảnh thật.
Tôi đảm bảo bạn sẽ phải viết nhiều hàm giống nhau ở cả service và repo như 1 bác ở page 2 gọi là proxy function.

Mỗi người mỗi quan điểm, nhưng mình quan điểm của mình đồng tình với lập luận của ông anh ngoại quốc dưới (nó khá đầy đủ)
refs hay:

mở đầu:
"
The repository pattern is an abstraction. It's purpose is to reduce complexity and make the rest of the code persistant ignorant. As a bonus it allows you to write unit tests instead of integration tests.

The problem is that many developers fail to understand the patterns purpose and create repositories which leak persistance specific information up to the caller (typically by exposing IQueryable<T>). By doing so they get no benefit over using the OR/M directly.

Update to address another answer​

Coding for the exception

Using repositories is not about being able to switch persistence technology (i.e. changing database or using a webservice etc instead). It's about separating business logic from persistence to reduce complexity and coupling.

Unit tests vs integration tests

You do not write unit tests for repositories. period.

But by introducing repositories (or any other abstraction layer between persistance and business) you are able to write unit tests for the business logic. i.e. you do not have to worry about your tests failing due to an incorrectly configured database.

As for the queries. If you use LINQ you also have to make sure that your queries work, just as you have to do with repositories. and that is done using integration tests.

The difference is that if you have not mixed your business with LINQ statements you can be 100% sure that it's your persistence code that are failing and not something else.

If you analyze your tests you will also see that they are much cleaner if you have not mixed concerns (i.e. LINQ + Business logic)

Repository examples

Most examples are bullshit. that is very true. However, if you google any design pattern you will find a lot of crappy examples. That is no reason to avoid using a pattern.

Building a correct repository implementation is very easy. In fact, you only have to follow a single rule:

Do not add anything into the repository class until the very moment that you need it

A lot of coders are lazy and tries to make a generic repository and use a base class with a lot of methods that they might need. YAGNI. You write the repository class once and keep it as long as the application lives (can be years). Why **** it up by being lazy. Keep it clean without any base class inheritance. It will make it much easier to read and maintain.

(The above statement is a guideline and not a law. A base class can very well be motivated. Just think before you add it, so that you add it for the right reasons)
"
...
"
the repository pattern is used to create an abstraction between your domain and data layer. that is, when you use the repository you should not have to have any knowledge about the underlying data source or the data layer (i.e. entity framework, nhibernate or similar).
"
 
Sửa lần cuối:
Rách việc, dự án nó code thế nào thì cứ để vậy đi. Thằng dev thì cứ làm theo những gì thằng lead bảo, hết giờ thì về. Bao giờ mày lên lead thì mày sẽ hiểu cảm giác mấy nói mà mấy thằng dev đéo nghe nó cay thế nào.

Code thế nào cũng được, miễn là nó chạy đúng. Refactor lại là 1 câu chuyện khác.

Mã nguồn chỉ là phù du, chạy đúng mới là vĩnh cửu.
 
Rách việc, dự án nó code thế nào thì cứ để vậy đi. Thằng dev thì cứ làm theo những gì thằng lead bảo, hết giờ thì về. Bao giờ mày lên lead thì mày sẽ hiểu cảm giác mấy nói mà mấy thằng dev đéo nghe nó cay thế nào.

Code thế nào cũng được, miễn là nó chạy đúng. Refactor lại là 1 câu chuyện khác.

Mã nguồn chỉ là phù du, chạy đúng mới là vĩnh cửu.
công ty phần mềm
mã nguồn là thứ quan trọng nhất
mà nói thế này thì tội nghiệp cho công ty đó thật
 
Cứ ngồi mà nắn với chả nót, refactor cho lắm vào tới lúc chạy lỗi tùm lum cả.
 
Rách việc, dự án nó code thế nào thì cứ để vậy đi. Thằng dev thì cứ làm theo những gì thằng lead bảo, hết giờ thì về. Bao giờ mày lên lead thì mày sẽ hiểu cảm giác mấy nói mà mấy thằng dev đéo nghe nó cay thế nào.

Code thế nào cũng được, miễn là nó chạy đúng. Refactor lại là 1 câu chuyện khác.

Mã nguồn chỉ là phù du, chạy đúng mới là vĩnh cửu.
Xin lỗi anh đây (ko bàn đến thâm niên, kinh nghiệm làm leader bn năm), cho em xin phản biện một số ý sau đây:
1. "dự án nó code thế nào thì cứ để vậy đi"
- Em không đồng tình với ý kiến trên. Anh nói vậy là anh quá bảo thủ, structure anh đưa ra anh phải bảo vệ được trước ae dev, lí do nguyên nhân cái gì cũng phải logic. Ae học hỏi, người ta có quyền đặt câu hỏi. Nếu anh là 1 lead giỏi, anh sẽ giải thích thích đáng... Em lấy ví dụ với em: "structure này mặc dù không phải best practice nhưng nó đảm bảo được tiến độ nhanh, đúng tiến độ dự án. Mặc dù a biết còn các structure khác hay hơn nhưng a nghĩ thời điểm khác thích hợp hơn chúng ta nên họp team và cùng nhau nghiên cứu, lựa chọn một structure tốt nhất cho các dự án tiếp theo..bla bla"
2. "Thằng dev thì cứ làm theo những gì thằng lead bảo, hết giờ thì về."
-
Đây là thằng culi chứ không phải thằng dev. Mấy ae dev như tụi em thường rất thông minh và chịu khó học hỏi.
3. "Bao giờ mày lên lead thì mày sẽ hiểu cảm giác mấy nói mà mấy thằng dev đéo nghe nó cay thế nào."
- Đấy là anh phải xem lại cách quản lí, dẫn dắt team của anh. Người leader yếu kém mới cay cú với ae. Anh phải hỏi tại sao ae không nghe lời mình mà nghe lời leader khác.
4. Code thế nào cũng được, miễn là nó chạy đúng. Refactor lại là 1 câu chuyện khác.
-
Vấn đề em đưa ra không phải là code đã chạy rồi và refactor lại. Anh có thể đọc lại.
5. Mã nguồn chỉ là phù du, chạy đúng mới là vĩnh cửu.
-
Bản vẽ, kĩ thuật là phù du. nhà ở được, chui ra chui vào được là được.

Thay mặt một số ae dev cảm ơn anh
 
Xin lỗi anh đây (ko bàn đến thâm niên, kinh nghiệm làm leader bn năm), cho em xin phản biện một số ý sau đây:
1. "dự án nó code thế nào thì cứ để vậy đi"
- Em không đồng tình với ý kiến trên. Anh nói vậy là anh quá bảo thủ, structure anh đưa ra anh phải bảo vệ được trước ae dev, lí do nguyên nhân cái gì cũng phải logic. Ae học hỏi, người ta có quyền đặt câu hỏi. Nếu anh là 1 lead giỏi, anh sẽ giải thích thích đáng... Em lấy ví dụ với em: "structure này mặc dù không phải best practice nhưng nó đảm bảo được tiến độ nhanh, đúng tiến độ dự án. Mặc dù a biết còn các structure khác hay hơn nhưng a nghĩ thời điểm khác thích hợp hơn chúng ta nên họp team và cùng nhau nghiên cứu, lựa chọn một structure tốt nhất cho các dự án tiếp theo..bla bla"
2. "Thằng dev thì cứ làm theo những gì thằng lead bảo, hết giờ thì về."
-
Đây là thằng culi chứ không phải thằng dev. Mấy ae dev như tụi em thường rất thông minh và chịu khó học hỏi.
3. "Bao giờ mày lên lead thì mày sẽ hiểu cảm giác mấy nói mà mấy thằng dev đéo nghe nó cay thế nào."
- Đấy là anh phải xem lại cách quản lí, dẫn dắt team của anh. Người leader yếu kém mới cay cú với ae. Anh phải hỏi tại sao ae không nghe lời mình mà nghe lời leader khác.
4. Code thế nào cũng được, miễn là nó chạy đúng. Refactor lại là 1 câu chuyện khác.
-
Vấn đề em đưa ra không phải là code đã chạy rồi và refactor lại. Anh có thể đọc lại.
5. Mã nguồn chỉ là phù du, chạy đúng mới là vĩnh cửu.
-
Bản vẽ, kĩ thuật là phù du. nhà ở được, chui ra chui vào được là được.

Thay mặt một số ae dev cảm ơn anh

hồi mới ra trường vô gameloft vietnam
không biết build android là gì
vô làm nửa năm mới biết công việc nó chỉ liên quan tới fix bug
code C++ và java
làm đúng nghĩa cái máy vô chỗ đúng giờ hết giờ về
phần core engine tụi nước ngoài làm hết mẹ rồi
bên việt nam chỉ sửa mấy cái nhỏ nhặt
làm đúng 1 năm nghỉ
qua công ty khác 1 mình làm android ios
tối ngày mò architect performance trên medium

tư duy mà làm hết giờ về thì khác gì thằng công nhân ở khu công nghiệp
cty mới cũng nhiều ông làm 10 năm 1 vị trí chờ người khác nghỉ rồi lên cao
hỏi công nghệ mới, kiến trúc code, ... thì không có
toàn singleton thẳng tiến không biết IoC, unit test

ai mà tư duy như ông này
thì thay đổi nhanh
đừng để rác lại cho người khác hốt
dù là làm công ăn lương nhưng cũng phải có trách nhiệm với cái mình làm ra
cái mình làm ra nó là thứ để người khác đánh giá con người mình

Rách việc, dự án nó code thế nào thì cứ để vậy đi. Thằng dev thì cứ làm theo những gì thằng lead bảo, hết giờ thì về. Bao giờ mày lên lead thì mày sẽ hiểu cảm giác mấy nói mà mấy thằng dev đéo nghe nó cay thế nào.

Code thế nào cũng được, miễn là nó chạy đúng. Refactor lại là 1 câu chuyện khác.

Mã nguồn chỉ là phù du, chạy đúng mới là vĩnh cửu.
 
Hic, bạn thực sự có vấn đề trong việc tư duy logic.

Ngay từ đầu bạn chủ thớt đã cố gắng đưa vấn đề về việc đơn giản hoá, tránh việc 1 Service sẽ sinh ra nhiều repo. Giờ mới chỉ có 1 câu query join mà bạn sinh ra tới 3 repo class để handle. Thử tưởng tượng với business logic phức tạp thì vục mặt vào đống repo kia có mà chết à?
Tôi nghĩ anh đọc nhầm chứ chủ thớt có bảo như thế (bôi đen 1) đâu nhỉ. Cái chủ thớt đang hướng tới đây là làm design sao cho nó sáng sủa rõ ràng rành mạch mà?
Với cả cái (bôi đen 2) là sao nhỉ? Sao lại service sinh ra repo?
Còn việc đẻ ra 3 class để handle (bôi đen 3) thì nó quá nà điều bình thường nuôn, nếu nó là bắt buộc để đảm bảo single responsibility thì đẻ ra 10 class anh cũng phải đẻ nhé. Anh không thể vì "tiết kiệm" class mà chỉ tạo 1 repo handle cả bảng user cả bảng order được, đúng không?

Lót dép hóng các bạn trẻ cãi nhau... mô hình 3 lớp từ old school với chuyện quản lý source version mà cũng chém tới page thứ 6 à. :doubt:
Nếu anh có lập luận hay ho để "bớt page" thì nói ra cho ae học hỏi. Còn anh chỉ tỏ vẻ thượng đẳng mà không lập luận được gì nên hồn người ta lại cười cho đấy. hihi

^
Đây là vấn đề quản lý độ phức tạp của phần mềm. Không phải tự nhiên người ta nghĩ ra bao nhiêu kiến trúc, paradigms, design pattern, ddd... Nhiều kiến trúc đã lạc hậu, như mô hình ba lớp mà anh nói, nhiều design pattern đã bị coi là anti pattern. Nên ở đây cãi nhau cũng chả có gì lạ.

Tôi đọc source code cũng nhiều. Nhiều người đi code 20 năm mà code một dự án kiến trúc còn thay lên thay xuống. Thế mà có một cậu ở trên tự hào chỉ cần thay 1 config là đã có thể xyz...
Cái mà anh bảo không được là cái mà SOLID nó hướng đến đấy anh. Và tôi thấy cái đấy hoàn toàn khả thi nhé. Cái mindset của cậu kia quá là ổn luôn.
//Với cả tôi thấy anh không nên lôi năm kinh nghiệm code ra để khẳng định một điều gì đấy. Vì thế giới nó luôn vận động và phát triển. Nhất là trong môi trường IT nữa, lý thuyết ngày hôm nay đúng mai có thể đã sai rồi. Với cả chắc gì mấy ông nhiều kinh nghiệm hơn đã ngon hơn mấy ông ít kinh nghiệm hơn. "Trường giang sóng sau xô sóng trước" anh ơi :D
 
ko hẳn là rối việc, với việc migrate từ DB này qua DB khác (Mysql, mongo, MSSQL,... ) thì chia repository xử lý rất nhanh
Lý thuyết này tôi nghe nhiều rồi, nhưng thực tế tôi chưa gặp dự án nào mà đổi db cả. Mà dù đổi db nếu dùng orm thì có repo hay k cũng thế. Kể cả dùng repo inject interface vào thì cũng phải viết lại hết phần query, có chăng chỉ là k phải sửa controller thôi.
 
Cái mà anh bảo không được là cái mà SOLID nó hướng đến đấy anh. Và tôi thấy cái đấy hoàn toàn khả thi nhé. Cái mindset của cậu kia quá là ổn luôn.
//Với cả tôi thấy anh không nên lôi năm kinh nghiệm code ra để khẳng định một điều gì đấy. Vì thế giới nó luôn vận động và phát triển. Nhất là trong môi trường IT nữa, lý thuyết ngày hôm nay đúng mai có thể đã sai rồi. Với cả chắc gì mấy ông nhiều kinh nghiệm hơn đã ngon hơn mấy ông ít kinh nghiệm hơn. "Trường giang sóng sau xô sóng trước" anh ơi :D
Nếu có 1 module mà anh chỉ cần thay đổi config là có thể thay đổi được cách hoạt động của nó, thì module đó là blackbox và anh là end user. Anh không thể extend được cái module đó. Như vậy mà gọi là SOLID?
https://www.brandonsmith.ninja/blog/libraries-not-frameworks
 
Về vấn đề của chủ thớt: chủ thớt đề xuất setup project theo mô hình 3 lớp như vậy xét về mặt kỹ thuật là hợp lý. Team leader và những người trong team chủ thớt phản đối mà ko nêu được lý do chính đáng (ví dụ scope project nhỏ, ko cần mở rộng và reuse, deadline hạn hẹp, team members thiếu kinh nghiệm..v..v..) thì rất đáng trách và làm nhiều người ko phục. Cái này có thể ko phải những người đó dốt (mặc dù có thể dốt thật) mà do cố chấp, ko muốn bị 1 thằng nhóc 9x dạy đời.

Lời khuyên cho chủ thớt: mình chỉ gợi ý, quyền quyết định là của thằng tech lead. Nó ko nghe thì thôi, vì chung quy người chịu trách nhiệm là nó, là PM, Team Leader. Nếu cái đề xuất của mình nó ko nghe theo mà ko ảnh hưởng gì lớn tới công việc của mình, như trường hợp này design dở nhưng lại code khoẻ hơn, kiểu mì ăn liền thì thôi chấp nhận làm theo. Lâu dài ko học hỏi đc gì hay thì kiếm cty khác.

Về vụ kiến trúc dự án nên là 3 lớp hay 2 lớp:
Một dự án bất kỳ Web, Windows, Mobile thường sẽ như vầy:
UI (Web, Win, Mobile) hoặc REST API -> Business Service -> Data Access Service (persistence layer).

Business Service là phần core nên 90% các dự án là sẽ có. Còn Data Access Service là để CRUD vào database, XML file, cloud storage... hay cái quái gì khác ko cần biết. Mục đích của nó là tách phần logic đọc ghi data với phần business service để có thể Unit Test business service bằng cách mock thằng Data Access Service, hoặc thay đổi database (ví dụ thay thế implementation của layer này từ MySQL sang cloud storage, hoặc XML...). Data Access Service có thể có hoặc không thì tuỳ vào scope dự án.

Dự án nhỏ, chỉ đơn thuần CRUD, ko có nhu cầu đổi database (thực tế khá hiếm) như dự án của chủ thớt thì nên đi theo cái này: UI -> Business Service. Lý do: các dự án CRUD thì phần core business logic rất ít, nếu đẻ ra Data Access Service thì đa số phần logic thật sự nằm ở tầng này vì làm CRUD và phải đảm bảo tính Unit of Work của nó (update 2 tables cùng 1 transaction) như vậy business service chỉ có nhiệm vụ pass qua lại DAS và UI thì chi bằng implement thẳng nó vào business service luôn, chấp nhận fix thằng database vì nó hiếm thay đổi mà. Tất nhiên làm vậy thì chỉ có thể Unit Test thằng UI (controller), còn business service thì integration test nhưng cũng nên như vậy vì CRUD nên làm integration test.

Về Repository và ORM:
Tôi ko gọi thằng này là Repository mà gọi là Data Access Service như bên trên. Hiện tại có ORM nên tôi sẽ ko tạo ra Repository tương ứng cho từng table mà sử dụng trực tiếp hibernate session, dbContext, dapper... trong phần implementation của Data Access Service luôn. Làm như vậy tận dụng được hết khả năng của ORM framework vì nó support tận răng rồi (CRUD, mapping, transaction) . Trường hợp duy nhất cần Repository là khi có ý định thay đổi luôn cả ORM framework như vậy phải abstract luôn cả thằng này (cực hiếm) trong khi hiện tại các ORM framework đã support thay đổi nhiều database luôn rồi.

Về vụ conflict source:
Nguyên tắc rất đơn giản: 1 người chỉ được code trên 1 file, phân chia làm sao để tránh xài chung thì thì ko có conflict: Ví dụ phân front end/back end thì từ controller, html, css, js là anh front end làm, code business service, data access service, SQL script là anh backend làm. Còn ko thì phân theo Use Case, module.

@phongkyanh: được chưa thím :shame:
 

Thống kê chủ đề

Ngày tạo
soledad86,
Người trả lời cuối
freedom.9,
Trả lời
217
Lượt xem
33.245
Quay lại
Lên đầu trang