"Clean Architecture" and indirection. No thanks.

Sdílet
Vložit
  • čas přidán 14. 06. 2023
  • Entity Framework Core on the Query Side of CQRS... Or Something Else? Well, a video was posted on this topic, and a member of my channel asked me my thoughts. I started watching it, and I realized I was talking out loud. So instead, I decided to record my thoughts and provide feedback. So here we go.
    🔗 EventStoreDB
    eventsto.re/codeopinion
    🔔 Subscribe: / @codeopinion
    💥 Join this channel to get access to a private Discord Server and any source code in my videos.
    🔥 Join via Patreon
    / codeopinion
    ✔️ Join via CZcams
    / @codeopinion
    📝 Blog: codeopinion.com
    👋 Twitter: / codeopinion
    ✨ LinkedIn: / dcomartin
    📧 Weekly Updates: mailchi.mp/63c7a0b3ff38/codeo...
    Original Video by Milan: • EF Core In The CQRS Qu...
    Follow Up: • Why You Don't Need To ...
  • Věda a technologie

Komentáře • 250

  • @MilanJovanovicTech
    @MilanJovanovicTech Před rokem +136

    I appreciate your commentary and review Derek! I think there's much to learn from it - mainly how "silly" the whole idea is.
    CA purists will still advocate for this approach, so that's why I decided to show it. But as I said, it's not my preferred way of doing things.

    • @adrian_franczak
      @adrian_franczak Před rokem +39

      So why you create content on something you don’t recommend? Maybe changing the title to “how it shouldn’t be done” will be enough - idk

    • @adambickford8720
      @adambickford8720 Před rokem +18

      @@adrian_franczak Even if you don't like a tech/paradigm/etc you should understand it and what the tradeoffs are. You might decide you like parts, but not to the extent they take it, or it may just solidify you opinion that the tradeoffs of your tech stack make more sense for you.

    • @adrian_franczak
      @adrian_franczak Před rokem +3

      @@adambickford8720 I know that that’s why I’m reading a lot of stuff from different points of view but I wouldn’t promote topic where I don’t agree with something

    • @MilanJovanovicTech
      @MilanJovanovicTech Před rokem +54

      @@adrian_franczak I don't see anything wrong with discussing implementations. For someone else, this is a great approach.
      It's my freedom to talk about anything on the channel - even things I don't agree with.

    • @adambickford8720
      @adambickford8720 Před rokem +5

      @@adrian_franczak It would make you a better engineer. One of the best ways to make sure you *actually* understand something is to teach it in good faith. Use Cunningham's Law to your advantage.

  • @pillmuncher67
    @pillmuncher67 Před rokem +140

    I'm regularly astounded by the amount of ceremony that is present in enterprise programming.

    • @CodeOpinion
      @CodeOpinion  Před rokem +62

      I think the trap developers fall into is applying patterns/principles without context and understanding why those patterns/practices exist. And the not using their context in that decision. eg, I can't have data access here because it can't live in this layer.

    • @marna_li
      @marna_li Před rokem +2

      @@CodeOpinionExactly. That is my opinion as well. I’m currently in a project that has a service layer with classes just to group stuff.

    • @KyleSavant
      @KyleSavant Před rokem +3

      @@marna_li like a facade pattern or for some other reason?

    • @marna_li
      @marna_li Před rokem +10

      @@KyleSavant It is where business logic is supposed to be put. To separate it from the presentation logic. Controller calling the services.
      Putting stuff in services is quite arbitrary. It is not like the services really have any meaning. They are more like modules, in something resembling feature folders.
      I wouldn't structure my project that way. Services, if they should exist, should have purpose. I'd rather have commands and handlers.

    • @KyleSavant
      @KyleSavant Před rokem +6

      @@marna_li I’m in a similar situation. I misunderstood your first comment.
      The organization I work for has massive classes called “Managers”. It is just a dumping ground for methods that vaguely do work around some conceptual noun (ex. - PersonManager). There could be many methods in this manager, many with different dependencies.
      Imagine how big this constructor is and how coupled it becomes to unneeded classes. It just makes my skin crawl every time I need to work with it.

  • @leonardomangano6861
    @leonardomangano6861 Před rokem +42

    The main issue here is that a lot of developers bought the idea that you can decouple things that are naturally (or semantically) coupled.

    • @vincentcifello4435
      @vincentcifello4435 Před rokem +6

      Exactly!.
      Worse still is the indirection, masquerading as "decoupling" , that results in the hidden coupling of things that are naturally not-coupled.*
      * (see Milan's in process Domain event video where separate aggregates are ultimately saved in the same transaction).

    • @leonardomangano6861
      @leonardomangano6861 Před rokem +2

      @@vincentcifello4435 You are right bro

  • @marna_li
    @marna_li Před rokem +23

    Yeah. You are not eliminating coupling, just moving it somewhere else. It doesn’t matter if it lives in a separate assembly. That will also make stuff messier. I’d use EF directly in request handlers within vertical slices. Only extracting stuff to classes when it makes sense to.

  • @Fafix666
    @Fafix666 Před rokem +66

    You should run a code review series where people show their approach, and you point out the good and the bad.

  • @superpcstation
    @superpcstation Před rokem +65

    I would love some code review videos. Also I'd love to see how you'd fix this problem

  • @andreiguzovski7774
    @andreiguzovski7774 Před 11 měsíci +5

    Depending on such abstraction decouples you from your persistence provider(in this case EF Core). Application no longer has to reference EF Core. Moreover it enables you to create several infrastructures(if needed) and easily change it in the future. One of the reasons why teams stick to their ORM provider despite improvements in others is because they neglect this step. The same teams also can't use different ORMs for reads and writes for the same reason. Dapper for queries and EF Core for commands is worth considering.

  • @leuquim
    @leuquim Před rokem +18

    I appreciate the "code review" styled video as the stacked opinions help to think about a problem while taking a couple steps back, opposed to just the direct "information absortion" mode we fall into when watching a video. A part of me relates to Milan because I have a fear of doing things "wrong", both for my perception of the code and to mitigate future (unknown) issues. Another part of me relates to Derek because experience tells me I tend to over-engineer projects in a way that rarely benefit anyone in the real world.
    I think specific architecture patterns or concepts are an easy way to get started and build acceptable solutions to a problem, but ultimately there's much more basic underlying concepts that take experience to be confident enough to use as the main guides in our decision making.

    • @CodeOpinion
      @CodeOpinion  Před rokem +3

      I think the trap is applying patterns/principles/etc as rules without understanding the underlying problems they are trying to address. Then taking that underlying problem and understanding in your context if it's valuable. There are always trade-offs and you need to be able to evaluate them. I alluded to that more-so at the very end.

  • @MiningForPies
    @MiningForPies Před rokem +14

    SingleOrDefault doesn’t throw an exception if there isn’t a result.

    • @sanjayidpuganti
      @sanjayidpuganti Před rokem

      Yes. If there are more than 1 it does

    • @MiningForPies
      @MiningForPies Před rokem +8

      @@sanjayidpuganti exactly, so he’s broken the original intent of method.

    • @adrian_franczak
      @adrian_franczak Před rokem +1

      exacly!

    • @atechdude
      @atechdude Před rokem +4

      The behavior of SingleOrDefault can be summarized as follows:
      If the sequence contains exactly one element, that element is returned.
      If the sequence is empty (contains no elements), the default value for the element type is returned.
      If the sequence contains more than one element, an InvalidOperationException is thrown.

  • @alexanderpabinger3960
    @alexanderpabinger3960 Před 7 měsíci +1

    I love this video and your comments. We talked about this kind of stuff 5 months ago: How can we share queries? How can we abstract the data access for unit tests? We decided to not share queries at all, instead depend on the DbContext (as you said there is no value in using an IDbContext where DbSets are exposed), because each query is so different and the result is mapped to it's own purpose. For the command-side, we decided to use DataAccessors (how we call them, doesn't really matter) and they can be easily mocked. They are also never shared between different command handlers. Thanks you your useful thoughts and videos!

  • @adambickford8720
    @adambickford8720 Před rokem +9

    Enterprise code is different. When a project lives many years and has multiple 'generations' of devs, you do things that are 'dumb' otherwise. It's easier to find corporate drone devs that can recognize and churn out more dumb patterns than devs who will grok and truly 'own' the app.

    • @evancombs5159
      @evancombs5159 Před rokem +3

      This was what I was thinking too. There are things I do that the value is in trying to guide future devs towards better code that I know if I let them to their own devices they would create crap code.

    • @6stringmonk
      @6stringmonk Před rokem +4

      This comment is spot on in my experience. I work somewhere where it is common to have a large codebase existing for 2 decades. I've used this "query object" pattern on a few projects over the past 5 years and they've been the easiest apps to maintain and add cross cutting concerns to even though much of the code is redumbdant. It's kind of like N-Tier chopped down to its bare minimum along with favoring SRP over DRY. It's overkill for very small projects but it actually helps coding momentum in medium-sized+ projects where there are a lot of people coding but you are not sure where all the data access and cross cutting concerns are going to land.

    • @carlosbaldwin6335
      @carlosbaldwin6335 Před 9 měsíci +1

      this comment is gold, after two years working in a project with multiple devs i think this architecture allow us to do things quickly and feel realy natural any change. It improve the development cicle.

  • @banatibor83
    @banatibor83 Před 11 měsíci +2

    The guy in the video what you reviewed almost reached perfection IMO. As he said he refactored the code to be more vertically sliced but exposing some of the entity framework defeated the purpose, but I think he wanted to keep it a somewhat more appealing length. If he would have transformed the result from the db queries into some domain specific object that would have made a true separation. With true separation you can switch out the whole persistence layer without disturbing the domain layer. If you go the extra mile and actually implement a strategy pattern you can mix persistence layer solutions and still providing a unified interface towards the domain layer.

  • @nyonyo3553
    @nyonyo3553 Před rokem +16

    Let me put a handler in your handler, so I can handle the requirements your handler should handle, but wait there's more!
    I've hidden your DbContext behind an interface that is just a copypasta of the DbContext itself. And why? I have no idea really.

    • @CodeOpinion
      @CodeOpinion  Před rokem +6

      Because they don't want to couple directly to the DbContext but rather an interface they own that lives in the Infrastructure layer. But you're still coupled to it because you're exposing the DbSet. I also don't get it.

    • @markovcd
      @markovcd Před rokem +1

      Cargo cult programming.

    • @dariogriffo
      @dariogriffo Před rokem

      Exactly like exposing Iqueryable to be able to do .Include

    • @pilotboba
      @pilotboba Před rokem

      @@CodeOpinion The IApplicationContext should actually use IDbSet and not DbSet. I agree with that assessment. Only the EF Contracts should be a application layer dependency, not EFCore proper.

  • @sj82516
    @sj82516 Před rokem +1

    Appreciate this kind of video to show your different opinion and thoughts. :)
    I try to apply CA (without CQRS) and I did put query into repository layer to keep everything fit into CA as possible. But I didn't put one query into one class.
    Good to know CQRS and different opinions.

    • @sergeykichuk2586
      @sergeykichuk2586 Před 2 měsíci

      That’s good approach but the problem is you can still have CQRS and you don’t need these query handlers you can inject your repositories directly!

  • @dagochen
    @dagochen Před rokem +4

    7:15 An OrderService should return Orders, because its domain logic. It should not return something that can be sent out. That's what the handler should handle!
    7:40: Exceptions are not made for control flow. Validate your id before doing anything!
    18:00: Splitting logic into seperated interfaces for each already seperated handler adds complexity, but no value.
    To really reach seperation of database/persistence from usecases:
    In the Handlers, call a domain service. The domain service uses a repository, which is implemented in the persistence layer and gets the DBContext injected.
    Result: Domain service can be reused in several different handlers to get, create, update delete your domain objects. Service makes sure, everything is valid/consistent. Repository takes care of persistence and uses EFCore or whatever to achieve that.

    • @gbroton
      @gbroton Před 8 měsíci

      You are confusing a domain service with a application service. Domain services does not use repositories. In fact anything related to domain doesn't.

  • @nickolaki
    @nickolaki Před rokem

    I love these style of videos, as a mid ish level software engineer my next steps to improving are self reflection on the methods and tools I've picked up over the last couple of years.

  • @darylolson5089
    @darylolson5089 Před rokem +5

    I really like this style of video. The review provides another point of view that helps me think of the nuances in the various approaches to application design and implementation. I would love to see more of these.

  • @phantastik3389
    @phantastik3389 Před 9 měsíci

    This comment is in regards to a generic repo; when I create a generic repo. My "get by id" usual looks like this =>
    Task getFirstOrDefault(Expression filter); I have a few like methods like that I use so I understand where he's coming from.

  • @rhtservicestech
    @rhtservicestech Před rokem +2

    10:15 The EF SingleOrDefaultAsync does not throw an exception if there are no records. It returns null, thus the "Default". When looking for a specific ID, it is best use to SingleOrDefault vs FirstOrDefault. If there are multiple rows with the same ID, FirstOrDefault will allow the operation to be performed, which can cause data issues.;

    • @proosee
      @proosee Před 11 měsíci

      Well, I assume everyone has constraint on ID field (since "ID" stands for "identity"), so this case is a bit exotic, but you're right that "Single..." should be used just because it express your intentions better.

  • @hektonian
    @hektonian Před rokem +4

    Or I could just implement the query handler where my DbContext is to avoid that silly leaky interface business altogether.

  • @edgeofsanitysevensix
    @edgeofsanitysevensix Před rokem +4

    I really don't get why some devs insist on using MediatR. To me it offers almost nothing since seperation can be acheived easily without it. Maybe if I was dispatching commands to a handler which drops a message onto a message bus? If it's just seperating controller layers from DB/Service layer then I don't see the point.

    • @yardeZ93
      @yardeZ93 Před rokem +1

      This is not the main idea of this tool.... What about pipeline behavior? I personally find that feature very powerful and I believe it is the main purpose of the library and not that API/Application separation.

    • @edgeofsanitysevensix
      @edgeofsanitysevensix Před rokem

      @@yardeZ93 Well fine. But I do see it used 'because its cool'

  • @jwbonnett
    @jwbonnett Před rokem +8

    I think it's not really about the abstraction but limiting how and where you can implement things, it means that there is less chance of you messing something up (the intern problem) if you use the current architecture layout. Especially is such large systems. It's a little more work, but you get used to where everything is, so moving things out of the way isn't really a problem.

  • @emanuelrodriguez3155
    @emanuelrodriguez3155 Před rokem

    Thx for this video derek, it's a good point of view that some future engineers can have when you are learning. I would like to see more of this content.

  • @awright18
    @awright18 Před rokem +3

    I really enjoy your take on things, and this type of video. I feel like the Milan's video that was pretty balanced at least in offering different options, and explaining some of the tradeoffs involved in the approaches although I don't believe it answered your question of "what does this buy you?". Also as Milan states below it is a lot of what people might see in the wild, wether or not its a preferred approach. To extend your thoughts a little further, I do see mediator or frameworks like it used often in web applications and treated like an entry point when typically the actually endpoint is the entry point in those situations I have the same thought. What is mediator actually adding besides indirection? To be fair I used to program like this until I realized as you said the single member interfaces are often simply a function. The purpose of many applications is to handle specific use cases, and its not often that we need to have more than one way to handle them at runtime. This reminds me of the memes about jr / mid / sr level engineers where the jr does something simple to solve the problem as they become more experienced (mid level) they make more complex solutions, and then after gaining more experience (sr level) they regress back to the simple solutions with the understanding of why simple solutions are often best.

    • @CodeOpinion
      @CodeOpinion  Před rokem +1

      What's the value of mediatr type libraries? Depends where it's being used. It some places it might be useless, others it can be helpful. For example, if you were using aspnet core and you specifically want to remove aspnet core dependencies from your code. Meaning, are you creating a web application or an application. It's used over an integration boundary. So assuming you don't put anything aspnet related in your request objects. Meaning, you're using it at the outer most I/O boundary that you might not control and convert it to something you do control. Let's say you have a request/handler that is used in a a controller as the entry point. You also have another entry point that lets say has to periodically pull data from an external system, translate it and call that same request/handler. In both situations you're taking the top level entry point and translating that in your application request. Can you do this without Mediater, absolutely, it just hides the execution, which then adds things like behaviors/piplines etc. If you're not doing any of that, does it provide you with any value?

  • @thedacian123
    @thedacian123 Před rokem

    So in a nutshell instead wrapping each query into specific service/abstraction would be ok that in each Meadiator query handler to write query directly as simple as possible using a ligther tool the ef as Dapper? Thank you!

  • @lexuantruong3835
    @lexuantruong3835 Před rokem

    I think we can move the handlers of the read side to another project instead of developing a new abstraction layer In the project, we can use many ways to read data quickly and easy to test. Additionally, application project, not dependency persistence library

  • @CryptoWulf_app
    @CryptoWulf_app Před 11 měsíci

    How do you handle scenarios where you want to reuse a Query?
    The way I pick was to move the code to a service and used this service in both Queries but I started without one first.
    One other solution could be to orchestrate everything in the Controller but then you cant return Viewmodels from your queries.

  • @madfish1973
    @madfish1973 Před rokem

    Great video! For me it's about decoupling the query handler from the storage layer and technology. We're using EF SQL today, but in six months we may use CosmosDB (especially when we consider the polyglot nature of CQRS projections). Having non-leaky injected interfaces implemented in their own assemblies allows us to do this without altering UI or logic layers.
    Since these interfaces should not leak technology types, vocabulary or concepts, we should make them non-persistent in nature. EF supports state, other storage layer technology does not.

    • @madfish1973
      @madfish1973 Před rokem

      I'm a huge fan of my EF models being internal to the storage assembly, enforcing clean tech agnostic interfaces.

  • @br3nto
    @br3nto Před rokem +1

    16:24 if you have a class (or interface) with one method, you have a function. I think you just described MediatR lol. Thought it’s more like a closure, as the constructor closes over the variables used in the Handler.

  • @brandon9247
    @brandon9247 Před 7 měsíci

    Great video! I would have liked to see as side-by-side of what would be more favorable and meaningful. If the takeaway was to "leave it as is", does it imply there was no problem at all initially? If not, how do we identify when there is a problem and when there isn't? Yes. The details about coupling was a step in the right direction, but I need a "to do" and "not to do" side-by-side for it to sink in.

  • @llindeberg
    @llindeberg Před rokem +5

    Its for test faking! Not that I agree with it necessarily, but i do miss it sometimes instead of using in-memory database for tests. Would öove to hear your comments

    • @anthonymorgan2001
      @anthonymorgan2001 Před rokem +2

      Seconded. Can we see an example of unit testing the logic in the handler without using this?

    • @Timelog88
      @Timelog88 Před rokem +1

      Yeah I also generally wrap the efcore dbcontext in my own wrapper class because it's impossible to fake itself. What I mostly find disturbing in the example is the sheer amount of interfaces. It's so useless to make an interface type for single implementations.
      Most of the time when I ask people why they do it the answer is because they want to mock it. But why would you ever want to fake more then the external infrastructure? Sociable tests are a thing, and in my experience worth the tradeoff of having multiple tests fail if you break your own code. Since I started doing TDD and sociable tests the amount of interface types I use has dropped significantly.

    • @llindeberg
      @llindeberg Před rokem

      ​@@Timelog88 To take it to the extreme, one could do with only e2e-integrationtests I guess. But unit tests with as many dependencies mocked as possible isolates the error for quicker debugging. There's an extreme of that side too, though, mock C#/.NET? But I see your point, tradeoff worth considering. I'm sad Microsoft are hesitant to recommend/expose it.

    • @Timelog88
      @Timelog88 Před rokem +1

      @@llindeberg Well personally I stopped using mocks entirely. I just do pure state based tests that test behavior and abstract away all implementation details from the tests feasible. The way I do that is a fairly novel way of testing introduced by James Shore called Nullable Infrastructure. This means that I limit the use of layers in my code, and the amount of dependencies in my code.
      The tradeoff? Test code in my production code. But as a counter argument to that, Microsoft does it as well, fe. NullLogger, NullStream and UrlTestEncoder. Main difference is that I use Embedded Stubs.

  • @Greenthum6
    @Greenthum6 Před rokem +3

    Great code review and I fully agree on your points. If you want to use Clean Architecture pattern and hide the persistance layer's implementation details then do it properly. In this example EF Core's DbApplicationContext is exposed as-is and the caller in application layer can misuse it freely (just cast the result to DbApplicationContext and off you go). Also greate insight on dropping out the cancellation token without a reason to keep the code nicer.
    I think the root cause may rely in the original Clean Architecture code example where the author did just this. I don't know why EF Core dependency was added all the way to domain layer, but this idea has been copied by many without understanding the consequences. I have used mostly Dapper with repository pattern and then you really need to think about the layer separation when applying clean architecture - you need to actually fetch or store the data before returning the response.

    • @pilotboba
      @pilotboba Před rokem +1

      "If you want to use Clean Architecture pattern and hide the persistence layer's implementation details then do it properly."
      What's properly? That's the $100 question here.
      " I don't know why EF Core dependency was added all the way to domain layer,"
      I don't think this was done. What are you talking about? Are you talking about the IApplicationContect interface created in the application layer? That can be done by only depending on EFCore contracts.

    • @Greenthum6
      @Greenthum6 Před rokem

      @pilotboba Referring to Jason Taylor's "clean architecture solution template": You are right, EF was not added into the domain layer there but the application layer instead.
      IApplicationContext has IDbSet, which is a hard EF dependency.

    • @pilotboba
      @pilotboba Před rokem

      @@Greenthum6 I also think Jason addresses this when he talks about it and it is a pragmatic decision he made. I generally agree with him. The overhead of wrapping the ef interfaces so you can remove a soft dependency on a contracts project is not worth the time, complexity, and extra layers.
      I think any clean architecture templates out there are guidance and not hard and fast rules. Use what you like, throw away or modify the rest. That's how I approach it.

  • @adiazwise
    @adiazwise Před 8 měsíci

    It’s great to see different point of view; we can learn more on this long pathway.
    I will take both opinions.

  • @13odman
    @13odman Před rokem

    Great video. I'm struggling with the same indirection thoughts.

  • @luizfernandopereira5120
    @luizfernandopereira5120 Před rokem +1

    I got a bad feeling when I see this abstractions, especially when we try to abstract the DataSource with Services/Repository patterns. I understand you want to have only one way to writing/structure your code base inside the applications so use the Mediator even though its just a thin layer for some cases but can serve as a agreggator for others its ok in small applications or modules. Still would simplify your life by making a vertical arquiteture and only abstract your outboundaries .

  • @szotsmiklos8549
    @szotsmiklos8549 Před 11 měsíci

    This sort of indirection can make sense if we also want to have different compilation units for application logic and database access. CA on steroids is Diamond Architecture, where the core of the project doesn't depend on any infrastructure lib. In CQRS, you'd want commands and queries (as classes) to be next to each other so it's easy to see all features/capabilities of the system. Still all repository implementation along with 'xyzQueryServiceImpl' would go to a DB project. Why? Because some languages are slow to compile (scala, rust) and a larger monolith's compile time can be sped up by this approach

  • @44Bigs
    @44Bigs Před 9 měsíci

    11:41 this is probably the worst offends, but SO common: adding all these layers, but with leaky abstractions everywhere. The result is tightly coupled code spread across multiple classes and assembles.

  • @dii2
    @dii2 Před rokem +7

    I like this video review. I'm a big advocate of using EFCore/Dapper/etc directly in the command handler directly as opposed to abstracting it into some IRepository class (some argue for testing purposes). If you are truly worried about unit/integration testing, EF Core provides an In-Memory database that you could use in your test project. At the end of the day its all about exercising pragmatism for various use cases.

    • @irvingceron1016
      @irvingceron1016 Před rokem

      That's cool, EF really has it all it seems

    • @Greenthum6
      @Greenthum6 Před rokem +4

      Don't use EF's in-memory database for testing. Use the real database engine to make sure your queries really work.

    • @davideastman5806
      @davideastman5806 Před rokem +1

      It should be noted that Microsoft explicitly discourages testing using the EF Core In-Memory database. From the docs: "While some users use the in-memory database for testing, this is discouraged."

    • @irvingceron1016
      @irvingceron1016 Před rokem

      @David Eastman
      Oh lol, why do people do it then?

    • @juniorzucareli
      @juniorzucareli Před rokem +1

      ​@@davideastman5806 Yes, using inmemory database is not recommended.
      But, people add indirection by arguing that it's for testing, to mock.. Using inmemory, this argument no longer makes sense.

  • @darylclarino5439
    @darylclarino5439 Před rokem +3

    Early on, I enjoyed adding patterns whenever I could to a project that I was working on, but as time went by I prefer my codebase to be as lean as it can be and only add abstractions when I truly need it. The CA pattern is a consistent way to implement a project, but I feel that it has this underlying assumption that a layer might be swapped out in the future. I understand the persistence layer "might" get swapped, but i'm on the fence about the application layer, do we really need to have a dedicated "Application" and "Web" or "Api" layer? In most cases an Api project will always be an Api project, so why not just define whatever is in the Application layer in the Api layer.

    • @CodeOpinion
      @CodeOpinion  Před rokem +1

      It's not about swapping out in the future, it's about coupling to abstractions rather than implementations and having a direction of dependencies. Where things go wrong is when people take a template or a formula for doing that and not taking their context into consideration.

    • @darylclarino5439
      @darylclarino5439 Před rokem

      @@CodeOpinion i see what you mean, and i agree sometimes people just use the patterns for the sake of using them

  • @zfold4702
    @zfold4702 Před rokem +2

    There is definitely value to it. Consider the Order Query requires to combine results from multiple queries to produce the final result, your design is open to introduce that glue in thin query handler while keeping the query details in the respective Service class. You won't see value in vanilla use cases but this helps in complicated enterprise applications where data needs to be assembled from multiple queries and sources.
    In real world, scenarios can begin vanilla and get complicated as business evolves. So following something like this helps.

  • @buarki_
    @buarki_ Před rokem +3

    Ain't quite sure if I'm properly dressed to witness such code formalism :)
    btw, looking forward to the day LOPJB (Layered-Oriented Programming Just Because) will no longer be so appealing for newbies/(almost) mid engineers. Lately in my job we released a dumb service that just acts as a CMS offload to offer some lower latency for two app-specific queries. Guess which "architecture' one guy from my team just started applying to it (just because)?

    • @CodeOpinion
      @CodeOpinion  Před rokem +4

      Did you just make up LOPJB? Either way, I'm using it and will give credit.

    • @buarki_
      @buarki_ Před rokem

      @@CodeOpinion lmao yes, it just popped up in my head here, feel free to spread the word against LOPJB

  • @jedielson31
    @jedielson31 Před rokem

    What do you think of moving query handlers to Persistence layer?

    • @CodeOpinion
      @CodeOpinion  Před rokem

      I don't think of layers in terms of clean architecture. I don't think of a "persistence layer". I think of how I handle persistence given a use case or a set of features. That could be in a transaction script if its CRUD, or maybe i have a repository if i'm using an aggregate. It depends on the context. As mentioned at the end of the video, a large factor is how much coupling is involved to the underlying data.

  • @adrian_franczak
    @adrian_franczak Před rokem

    Great video! I hope this will have more views than original one.

  • @enterprise_programmers

    Hi, I'm 16 years old and I love microservices and ddd and I've been on some enterprise projects i really liked your review and you made some excellent points, I recorded some videos about microservices and architecture and I'll be happy if you review them and gave me your thoughts about it and say witch part I'm right or wrong ❤️

  • @megaFINZ
    @megaFINZ Před rokem +1

    I don't get the idea of using MediatR just for cross-cutting concerns. You can just use decorators instead.

  • @PaulSebastianM
    @PaulSebastianM Před rokem +1

    I always love to learn from more senior devs. Trust your elders and all that😂

  • @mabdullahsari
    @mabdullahsari Před rokem

    06:50 That's you explaining what a Poltergeist / Gypsy Wagon is. 👍

  • @spicynoodle7419
    @spicynoodle7419 Před 11 měsíci +2

    Wow, this guy managed to take a single, concise query and spread it around the codebase like he's making a PB&J sandwich.
    This video really felt like reading the *EnterpriseQualityCoding/FizzBuzzEnterpriseEdition*

    • @spicynoodle7419
      @spicynoodle7419 Před 11 měsíci

      The problem with this video is that he is creating a million classes for a million queries. Creating an abstraction over a single immutable constant. This is wrong. At work I use Eloquent ORM, it has one interface with different DB drivers and that is a way better architecture.

  • @iankirkpatrick2022
    @iankirkpatrick2022 Před rokem

    I really appreciate your videos Derek. I had a couple thoughts of my own here that I have wrestled with and want to get your opinion (or other people's here) on.
    I have made a habit of always hiding EF from my business layer (where my query and command objects live if I'm using CQRS). I do this because of 3 different types of experiences I've encountered that made me decide to do this. My main question is, am I overreacting from these experiences (I know that word overreact is subjective, sorry)
    1. Poorly designed database schema where I want to hide the details of tables and queries out of the high level areas my app (the business layer).
    I've worked on many projects where the database was designed poorly or without foresight and we didn't want to take time re-designing it (and therefor performing data migrations at deployment time). I'm not just talking column name changes. I've had to work on projects where they stored two different types of entities in the same table that were similar but different and used in two completely different contexts. I wanted my domain to represent them with 2 different classes... not even having a base class in common cause they weren't ever reasoned with as similar entities... yet my EF model had to be the same cause they were the same table. I also needed 2 different sets of queries (use these where clauses to get records of these types but these other where clauses to get records of the other type).
    I really did not like seeing the complexity of "these are the same models... but oh wait, they're totally different." in my business logic. It was too low level for the business layer which I wanted to be higher level.
    2. Storage location switch.
    I've had a couple experiences where we use to cache a set of data from an API in the database so we had the business level go directly to EF to get the data... then we decided to cache in redis... suddenly I found myself spending a whole month updating references and query operations to use a redis client instead which, if we had abstracted the querying out, it probably would have been half a day or at most a couple days.
    Worse, suppose we did do a table split like what I described above in the first example... depending on the complexity of the queries to that table just to differentiate between the 2 tables, that change could take a while and be very prone to missing references or updating some incorrectly.
    3. Hiding EF specific operations (i.e tracking nuances).
    I've had lots of times where I've had to do some wierd logic in the EF context to deal with nuances in tracking and sometimes cachinng... I don't like putting code like "Add this entity, but check to see if a related entity is already tracked cause if not, you gotta attach that first... oh wait, i've already tracked a duplicate instance of that entity from another query so I gotta swap this instance out for that one". Logic like that doesn't belong in high level logic like the business layer in my opinion.
    For reasons like these, I've just made it a rule for my projects to always just hide EF completely so I don't even have to worry about those issues. I don't even allow myself to add a package reference to EF in my business assembly.
    Am I overreacting? How else could I address these issues if I allow EF to exist in my business layer?

    • @CodeOpinion
      @CodeOpinion  Před rokem

      No, not overreacting. I can't express this enough, it all comes down to coupling. If you have specific data that's going to be used in a high number of places (likely queries), than you likely want to expose that behind some API that you can control. Writes are often limited to a select number of actual usages. If you're using an aggregate, maybe its only there. If you're using transaction scripts, maybe it's just a few places that perform a write. In those cases, abstracting your persistence has a very different value than the earlier mention of a query that has a high degree of coupling. It's about where you need control.

  • @SergijKoscejev
    @SergijKoscejev Před rokem

    I just use odata for query separations. I cant imagine how much time i've saved for a single-developer side job

  • @Veretax
    @Veretax Před rokem

    What confused me was his abstraction was still using the DB sets transforming them into the objects that you might want from a testability perspective this throws me a little bit because if you're wanting to not depend on the database for testing then you need to be able to create mocks somewhere

  • @dariuszlenartowicz
    @dariuszlenartowicz Před rokem

    Separated purpose WriteSide - ReadSide is not that hard. What about specyfic queries from Write-Side to accomplish use-case?

  • @MrJonnis13
    @MrJonnis13 Před rokem

    This style of videos are like code reviews.
    Really interesting and useful.
    @CodeOpinion, I would love seeing you making such videos regularly.

  • @brakenthemole2377
    @brakenthemole2377 Před rokem

    It would be great to see what your thoughts are on the alternative.

  • @Galakyllz
    @Galakyllz Před rokem +4

    I definitely enjoyed this style of video. With regards to the content, there's nothing worse than being excited about a new project, you start abstracting out the different functions, and then realize that you've mapped one-to-one-...to-one all the way down to the database. That said, I think storing anything but a one-liner in a handler leads to bad places, but the amount of indirection applied to this specific project was too much. Once you start creating abstractions of functions (`ExecuteAsync` in this case), you've lost me.

  • @jamesmussett
    @jamesmussett Před rokem +3

    The levels of indirection I've seen over the years is really starting to bug me. It's got to a point now where I even see MediatR as unnecessary in some use cases and it's just easier to have a single class for the endpoint itself rather then having any kind of indirection.
    (I say endpoint, can be using FastEndpoints, controllers, or any other kind of endpoint construct. As long as it's a class with a single method / purpose)

    • @pilotboba
      @pilotboba Před rokem

      The Endpoints are a UI/Presentation layer. How does the endpoint query the data? Are you coding to an implementation in the endpoint?
      What if you had a second Presentation layer, say a graphql server. You would have to write the query all over again?
      I don't think there is a simple, single, correct answer her for every use case and application.

    • @atechdude
      @atechdude Před rokem

      I don't use Mediator :)

    • @jamesmussett
      @jamesmussett Před rokem

      @@pilotboba I don’t disagree with the fact that certain use cases will require a different approach. But as ti mentioned, it certainly doesn’t require libraries like MediatR. Thinking about all the use cases upfront certainly helps eliviate having to re-write everything later on, but I appreciate that requirements can always change.
      From my personal experience, endpoints are designed for specific scenarios in which the database queries are normally optimised and tailored for. Query Language APIs like graph QL will most likely have to have it’s own queries written for it anyway. Adding any kind of shared logic and indirection between then is more likely to cause issues in query performance and just add unnecessary complexity.

    • @pilotboba
      @pilotboba Před rokem

      @ti Guess you didn't understand my "what if". I wasn't saying you are designing for the future, I am saying your current design INCLUDEs 2 presentation layers. The read model should be available to both presentation layers rather than implementing it twice.
      But, sure, if you know it will only ever be an API and you want to implement the read model in the endpoints, go for it. I am usually more pragmatic than dogmatic.

  • @maurosampietro9900
    @maurosampietro9900 Před 11 měsíci

    Based on the article: “repository pattern is simple but yet misunderstood”. I’m tempted to let my web services (fastendpoints) directly use EF. I also want to completely avoid dtos and mappings. I’d play around with the serializer (eg: custom jsonconverter) to cut out unwanted data if linq select in anonymous types is not possible . What your thoughts?

    • @carlosbaldwin6335
      @carlosbaldwin6335 Před 9 měsíci

      dto's and mappings give you an order to manage you data. When you work with a lot of people, you need to understand really fast things.

  • @mihais2911
    @mihais2911 Před rokem +1

    At 13:10 is a bit confusing what you're saying about CancellationToken. Could you please confirm that what you meant is that it should really be passed on and not remove it? Because you seem to be saying that and then finish by saying that "it's kind of the indicator like oh it feel uncomfortable". Thanks!

    • @CodeOpinion
      @CodeOpinion  Před rokem +6

      Yes, it should be getting passed through and used. What I mean is that it was removed, probably because it felt odd to have to keep passing it from layer to layer. And that "oddness" is the indicator that you have a lot of indirection. Removing it's usage is hiding the "oddness".

  • @asdqwe4427
    @asdqwe4427 Před 11 měsíci

    I fully agree with you, but man is this an uphill battle in 90% of organisations. You’re doing the lords work!

  • @alexandru-mihailadam8798

    We would really like to see a clean architecture from your point of view, in any language you would like to.

  • @temp50
    @temp50 Před 11 měsíci

    4:20 Yeah this is why the onboarding process for a new colleague usually takes like half a year ffs! :) Nobody will understand the reasoning later on, especially if it is not written down.
    But obviously it will not be written down since the code should be self-explanatory, nobody's wiring code-related documents only high level ones.

  • @Musician4231
    @Musician4231 Před rokem

    Incredible mashup and discussion!!

  • @MohamedCherifBOUCHELAGHEMdz23

    Can you make a video how to design testable code?
    Code that allows to write tests easily and those tests can run really quick in milliseconds?

  • @colton2432
    @colton2432 Před 11 měsíci

    Trying to summarize your thoughts at the end to better understand: because you're already implementing a CQRS pattern each Read Model is specialized and adding indirection to the persistence layer isn't providing value because IF the underlying persistence implementation changes the specialized Read Model may be irrelevant and because it's specialized and will likely have limited usages?
    However on the command/write side it could be more valuable because we may need to query the aggregate root in order to validate or apply a state change which is a domain centric action instead of a specialized usage based on the persistence implementation?

  • @ghevisartor6005
    @ghevisartor6005 Před 6 měsíci

    uuuhmm i had a project in blazor server, there is no intention to make a mobile app or some other kind of front end...so i have the dbcontext directly in the blazor component for fetching and saving stuff. I cant see how this is bad given the requirement of the project. If i will ever need to make some page render in web assembly mode i will move the methods in an api just for that page needing of client side performance. Maybe i'm not writing big enough projects...

  • @awmy3109
    @awmy3109 Před rokem

    You shouldn't unit test with a concrete instance of DbContext. That's integration testing.

  • @wallyhighsmith9005
    @wallyhighsmith9005 Před rokem

    You guys are on to something …. This content is very valuable

  • @mux____
    @mux____ Před 11 měsíci

    This was fire- love this style of video

  • @pispis3617
    @pispis3617 Před 9 měsíci

    "Calling everething as service killing me"
    YES YES YES YES!!!!!!!!!!!!!!

  • @piromanaBG
    @piromanaBG Před rokem +1

    If you expose DbSets or IQueriable, you are doing something that is not Clean!
    Having the Infrastructure Layer on top of other layers is beneficial because you decouple your app logic from the infrastructure wiring code.
    If you add on top some bootstrap layer, your web application will be oblivious that it is a web app (e.g., you can extract your Controllers in a class library).
    And you can design your business logic like all the data you need is in memory. The result is code more in line with the OOP and SOLID principles. The idea is to design your app like your data is in memory. And your system to speak the business language.
    The idea of using Repositories is to use them to make queries through Aggregate Roots, but returning the whole Aggregate is unnecessary. This way, your Aggregate root can force all invariants. And you have a single flow point between different Aggregates, which leads to better (in my opinion) database schema design. The Entity from one Aggregate should not have a foreign key to the Entity from another Aggregate. These foreign keys are made through the Aggregate Roots.
    Bootstrap Layer -> ASP app
    Infrastructure Layer -> Persistence etc. (here, the Repositories are implemented)
    Web Layer -> Controllers and MediatR
    Application Layer -> CQRS, Repositories Interfaces
    Domain Layer -> SOLID OOP (Entities, Aggregates, etc.)

  • @andersborum9267
    @andersborum9267 Před 11 měsíci +1

    Developers should generally start returning the result of e.g. queries as opposed to assigning them to a variable and then just returning the variable; guys, it's not adding any value assigning stuff to a variable and then on the following line, returning that particular line. Your method (that encapsulates the query or operation) should relay the intent of the contents of the method.

  • @robotrabbit5817
    @robotrabbit5817 Před rokem

    This style of video is great, but also your traditional way of doing it is.
    This style allows us viewers to get their thoughts verified heir on approaches out there on CZcams that do not really discuss the approach. The video you reviewed felt like a how to video but only your commentary added the discussion.

  • @mohammadtoficmohammad3594

    Thank you both , i personally don't like commenting on others content, you could just place your opinion without personalization, coding is like writing a poet its not science, there are many ways to solve same problem, interface for persistent layer is a requirement for clean architecture , domain should not depend on persistent layer

    • @mihais2911
      @mihais2911 Před rokem

      As long as you're not being disrespectful, why not commenting on others content? Derek has a lot of experience hence a lot to say. I love what he did here. I bet Milan and many others learned a lot from this video. It's a toxic mentality that commenting on others people is a bad thing. It's my pet peeve.

    • @mohammadtoficmohammad3594
      @mohammadtoficmohammad3594 Před rokem +1

      @@mihais2911 judge me when you are perfect, and i am sure no one is perfect

    • @mihais2911
      @mihais2911 Před rokem +1

      @@mohammadtoficmohammad3594 But you just judged Derek because he commented on Milan's work.

  • @ToadieBog
    @ToadieBog Před rokem +1

    Awesome video. Ok but seriously...there at the end...he has snake eyes, I swear. It was kind of mesmerizing.

  • @leopoldodonnell1979
    @leopoldodonnell1979 Před rokem

    Patterns can be awesome, but the practice of turning helpful patterns into boilerplate often ruins the utility of code; even the smallest task requires a survey of tens of files.
    If it is simple, keep it simple.
    I love CQRS because it really enables focus on what’s important.
    I’d also note that no style, whether it is CQRS or Clean, is going to save you from over coupling and low cohesion

  • @MrFreddao
    @MrFreddao Před 9 měsíci

    "Calling everything as service kills me" HAHAHA Indeed, this days you can name everything "service" and nobody will claim.

  • @toopkarcher
    @toopkarcher Před 10 měsíci

    It's like we forgot that our job is to bring value to people, not marvel at some fancy abstractions or design patterns.

  • @moke_codes
    @moke_codes Před rokem +2

    I wonder when people started adding indirection and abstractions only for the "what if" reasons. How difficult would it be to change every handler because you decide to use Dapper instead of EF Core, in comparison to creating another persistence project that does this and changing every existing query?

  • @MarcusTheDorkus
    @MarcusTheDorkus Před 11 měsíci

    Indirection without a very clear purpose makes code so hard to follow. Especially when you're creating a new interface and injecting the implementation through a DI framework. You end up needing to run the code to figure out what concrete types everything resolves to.
    And if anyone needs another reason to argue against indirection for indirection's sake, keep in mind that there are performance penalties for it. Interfaces require vtable lookups and processors don't particularly like jumping around all over the place.

  • @Masteroxify
    @Masteroxify Před rokem +2

    I am really DDD guy. So i would make handler which inject repository, validator and mapper. Firstly we validate a request then repository return desired entities and request handler maps it to response.
    Additionally request handler should handle all possible exception imo (or we can leave it in Filters, i dont know)
    NotFoundException is good but in Write operation. In Read operation it is completly expected to not found values.

  • @huguesviens
    @huguesviens Před 11 měsíci +2

    I'm only halfway where you don't see the value. There is indeed a value, there is no EFCore dependancy now in the application layer. It enables to change the ORM provider somewhere down the line with no impact to your application layer. Do we really need this level of abstraction ? it is debatable but not valueless.

  • @nickolaki
    @nickolaki Před rokem

    I would love to hear why you don't approve of sending back your data schema object. I sometimes find myself mapping DTO on domain entities and they have the same exact properties as the entity itself.

    • @juniorzucareli
      @juniorzucareli Před rokem

      Well, they change for different reasons.
      There really are times when your dto has many properties of your domain model.. however, there will be times when you don't want to return all the data that is in your domain model, some sensitive data..
      But in general, I don't like to put rules, it depends a lot on the type of application you are developing.

  • @pguti778
    @pguti778 Před rokem

    I can't believe in 2023 the C++ windows "I" prefix naming convention for interfaces are still there... This I don't like of C# !!! 😂😂😂😂

  • @crazyfox55
    @crazyfox55 Před rokem

    I think the example is lacking complexity. If the domain was more complex with the query handler needing to collect or modify the response based off some domain specific rules. Then creating some services to allow the query handler to become persistence ignorant would allow for a more focused query handler.

    • @CodeOpinion
      @CodeOpinion  Před rokem

      Question: If you're underlying data model was used in a dozen places, would you want to want the query handler to be persistent ignorant?

    • @crazyfox55
      @crazyfox55 Před rokem

      @CodeOpinion if the goal is DRY then maybe that is a good reason too.

  • @ahokai
    @ahokai Před rokem

    Is using an interface extensible (everywhere) a common practice in C#? If no other implementations are needed for a class, I don't really see why you want to use an interface for it. Would like to hear others' comments.

  • @eminovperviz
    @eminovperviz Před rokem

    Dear Martin,
    I like your videos and Milan have got nice video contents as well.
    What would be your approach in this scenario ? And, do you have "Clean Architecture" or "Some Architecture" example, skeleton or something like this ?
    Maybe you have already shared a video about this concept that i have missed ))
    If you annswer, i will be glad. Thanks in advance 👍

  •  Před 11 měsíci

    What I've seen everywhere
    1. Super convoluted - need a big team with specialists to maintain it
    2. Build on top of bad technologies, thinking vanilla tech, eg. EcmaScript2020, is obsolete
    3. Use the wrong methodologies (Agi$e)
    4. Use the wrong architecture and the wrong paradigm (abstract and interface rules!)
    5. Designed by incompetent with big mouth (cronyism) - using fast talk technique to seduce the moron leader in place
    6. Let users design the features they want - letting developer build a Frankenstein monster

  • @furious2563
    @furious2563 Před rokem +1

    Curious about your pet peeve, what do you call things that others would call a 'service'? In the context of this 'orderService', I think I would have called it 'orderStorage'.

    • @CodeOpinion
      @CodeOpinion  Před rokem +4

      I wouldn't create it in the first place so I wouldn't need to think about naming it. But to answer somewhat, let's say I had to make a call for currency exchange. I'd call it CurrencyExchange.

    • @CoreCommander2
      @CoreCommander2 Před rokem +4

      Names should convey meaning. Calling something ProductService, for example, doesn't tell me anything about what the service does. I know it works with products and that's about it. ProductCatalogService is a better name - now I know that the service is responsible for listing and displaying products, but I could figure that out if it was just named ProductCatalog. The Service part is superfluous.

    • @wertrager
      @wertrager Před rokem

      @@CoreCommander2 But would you put it ina a Services folder?

    • @CoreCommander2
      @CoreCommander2 Před rokem +3

      @@wertrager no, definitely not. I'd put it in a folder for the feature or bounded context. Namespacing by technical concerns is an anti-pattern IMO and it drives me nuts when I see it. Don't even get me started on project-per-layer...

    • @Galakyllz
      @Galakyllz Před rokem

      @@CoreCommander2 I've come to find that "services" provide the one-liners for "handlers" (making testing easier), "managers" provide useful functions for "services" (aggregating data), "repositories" provide data access for "managers" (connecting directly to storage). So, for me, when I see a "service" I know exactly what scope of the problem it's solving.

  • @CesarDemi81
    @CesarDemi81 Před rokem

    Clean Architecture is one of the biggest trojan horses. And there are people trying to justify it by any means. Incredible!

  • @atechdude
    @atechdude Před rokem

    What a huge mess IMO. Too many abstractions and absolutely no gain except pissing off Junior Devs LOL. I am not saying expose your Entities to your UI / Controllers, Razor Pages etc... So some level of abstraction is needed. You are still going to be in mapping hell when it comes to your presentation layer but that is somewhat expected. Get a tool like Mapperly for that. Great video as always man. I was cracking up on your opinion of naming everything IInsertResponsibiltyHereService hahaha.

    • @CodeOpinion
      @CodeOpinion  Před rokem

      IEveryingIsAServiceApparentlyAndNeedsAnInterface_EndSarcasm

    • @atechdude
      @atechdude Před rokem

      HAHAH

  • @cheeseburger1884
    @cheeseburger1884 Před 11 měsíci

    I love this crossover =d

  • @pyce.
    @pyce. Před 8 měsíci

    I think the concept was "with" Milan, he just didn't manage to demonstrate it in the best way.
    I do believe clean architecture is the best approach in most cases and I think Amichai demonstrates the gist of it terrifically: czcams.com/video/1OLSE6tX71Y/video.htmlsi=WlEuQ-dLh6I98-Jx

  • @elpe21
    @elpe21 Před rokem

    love the video !

  • @edmonddantes587
    @edmonddantes587 Před 11 měsíci

    lol i'd just throw everything into the command/query handler or maybe even the controller directly. YOLO

  • @markcampbell2491
    @markcampbell2491 Před rokem

    I hate this abuse of single interface to single class craziness! at very least just have a single class implement many interfaces and use that...either way to me this indirection and "single abstractions" is crazy

  • @keithnicholas
    @keithnicholas Před rokem

    always makes me cringe when people abstract away from the database/datastore, which are often highly optimized data container/manipulators that often are treated as dumb storage services. Backends need to be as thin as practical!

  • @E_G_
    @E_G_ Před 9 měsíci

    Great video,, two guy I love to watch. Thank you all to creating good contents.

  • @Fred-yq3fs
    @Fred-yq3fs Před rokem

    Indirection is bad. I pondered the same questions and came to the conclusion the query side can use all the EF goodness as is. Persistence agnostic / clean architecture should not become a cult, especially if you want to use CQRS. Anyway, how often do you change your persistence level? Do it per query then. If you have a generic GetOrder service + a specific mapper then you're presumably sharing code between handlers, and we know code sharing is bad: SRP principle, right? It's better to be specific, stick to the problem at hand. Besides, don't throw exceptions for flow control, and pass down those cancellation tokens whereever you can: spare resources!

  • @gordonfreimann
    @gordonfreimann Před 10 měsíci

    Noone talks about how difficult it is to introduce transaction logic into this madness

    • @carlosbaldwin6335
      @carlosbaldwin6335 Před 9 měsíci

      it's really easy. Just call services and repositories inside handler's and that's it. Use strategy instead.

  • @DamageSoftware
    @DamageSoftware Před 11 měsíci

    Yeah I stopped witching the moment this guy created a service. The whole point of vertical slice architect is to get away from those GOD services.