A critical look at Marvel vs. Capcom....



  • Having worked on an actual MVC project for once, and spent enough time deep in the patterns, I'm beginning to question its utility.

    So the workflow in the app I maintain is something like this:

    1. User clicks button to frobnicate widget.
    2. HTML element onclick event calls [Java | Type]script method which gets or posts an HTTP endpoint
    3. Endpoint is mapped to a controller
    4. Controller calls a Service
    5. Service calls a Repository
    6. Repository calls a homegrown data layer that builds a SQL statement and executes it
    7. SQL results are consumed into a strongly-typed DataTable
    8. Mapper class takes values from this DataTable and maps values to a Model
    9. Repository passes Model results to Service
    10. Service maps Model results to a Viewmodel using a second mapper class and returns to Controller
    11. Controller returns Viewmodel results via HTTP response
    12. [Java | Type]script consumes results and does the needful

    Now, when I was a youngling developer, the elders taught me the importance of separation of concerns, and that code should be divided into layers. Usually, it was presented as three layers:

    • Presentation layer: responsible for putting text on a page and mapping variables to onscreen values, as well as gathering user input and passing that on to the...
    • Business layer: handles operations on a very high level, that is to say, frobnicating a widget. It cares not for the nitty-gritty of how a widget is frobnicated in the database, as that's the concern of the...
    • Data layer: handles CRUD/persistence operations and maybe does some mapping to and from classes at best.

    This makes for a rather simple architecture as there's a clean, logical separation of concerns, and not too many steps in between that would all need to be retrofitted should there need to be a major change in the workflow.

    Later on in my career, I encountered an even simpler pattern, which I will call the "ASPX and Stored procedure" pattern, which has the business layer moved, typically into the data layer. The process of frobnicating a widget, or getting a list of unfrobnicated widgets, are encapsulated in stored procedures. At times, I was concerned about maintenance of such an architecture, but over the years, I ended up doing a lot of major changes, and when it came time to find out how frequently a stored procedure was used, 95% of the time it would only be called in one or two places in the whole app.

    This raises a question which begs to be answered: if a two or three layer architecture yields maintainable code, why do we need the whole MVC pattern? One argument I've heard is, "well, if a shop uses MVC, you know their code is architected a certain way and it's easy for newcomers to pick it up." That seems extremely optimistic, as 1) there's always ramp-up time as new developers come on, 2) good developers have a skill called "reading other people's code" which renders such a requirement moot, and 3) there are no guarantees as to how well the pattern is adhered to.

    "But what if your API needs to be consumed by an IoT toaster without a filesystem?" I would hope that this toaster has the ability to call stored procedures. I've worked on .NET CF devices with very stripped-down functionality, and even those could connect to a database. Failing that, make a webservice.

    It all reeks of cargo-cultism, like how some DBAs will turn everything into a star schema when given the chance, even though a star schema is designed for a very specific problem.


  • Notification Spam Recipient

    @Groaner said in A critical look at Marvel vs. Capcom....:

    an actual MVC project

    I guess I've never done this, based on your breakdown. No comment.



  • @Groaner That was my take on it too. Best project I ever worked on was similar to your "ASPX and SP" pattern. We had the ASPX page (SaveAppeal button), then we had a business layer (SaveAppeal function), and finally the core/database layer (technically two parts because the OnBase parts landed in a different DLL than the SQL parts). Nowhere near as convoluted or flaky as anything I've seen since. The situation around that system is both funny and sad. They're thrown a dozen teams of "highly qualified" Indian contractors at it and they haven't been able to update or replace it. Still living on borrowed time because ITIL something something but 20 years was a good run.

    @Groaner said in A critical look at Marvel vs. Capcom....:

    It all reeks of cargo-cultism

    Welcome to my world. People hate my way because "it's too much code" and a framework is "so much easier," except they write ten times the boilerplate to satisfy the framework that further locks them into a straightjacket because every deviation has to propagate through forty layers they don't really understand. Yet I'm the evil code cowboy...



  • @Groaner said in A critical look at Marvel vs. Capcom....:

    Having worked on an actual MVC project for once, and spent enough time deep in the patterns, I'm beginning to question its utility.

    So the workflow in the app I maintain is something like this:

    1. User clicks button to frobnicate widget.
    2. HTML element onclick event calls [Java | Type]script method which gets or posts an HTTP endpoint
    3. Endpoint is mapped to a controller
    4. Controller calls a Service
    5. Service calls a Repository
    6. Repository calls a homegrown data layer that builds a SQL statement and executes it
    7. SQL results are consumed into a strongly-typed DataTable
    8. Mapper class takes values from this DataTable and maps values to a Model
    9. Repository passes Model results to Service
    10. Service maps Model results to a Viewmodel using a second mapper class and returns to Controller
    11. Controller returns Viewmodel results via HTTP response
    12. [Java | Type]script consumes results and does the needful

    Now, when I was a youngling developer, the elders taught me the importance of separation of concerns, and that code should be divided into layers. Usually, it was presented as three layers:

    • Presentation layer: responsible for putting text on a page and mapping variables to onscreen values, as well as gathering user input and passing that on to the...
    • Business layer: handles operations on a very high level, that is to say, frobnicating a widget. It cares not for the nitty-gritty of how a widget is frobnicated in the database, as that's the concern of the...
    • Data layer: handles CRUD/persistence operations and maybe does some mapping to and from classes at best.

    This makes for a rather simple architecture as there's a clean, logical separation of concerns, and not too many steps in between that would all need to be retrofitted should there need to be a major change in the workflow.

    I don't really understand the this part. Apparently the application you work on use three-layer data model
    as you describe it, but... something?

    It's little convoluted, indeed, especially the abundance of data structures, but what does that have to do with MVC?

    This raises a question which begs to be answered: if a two or three layer architecture yields maintainable code, why do we need the whole MVC pattern?

    I don't understand the question. How do these two things relate? MVC is a presentation-layer thing, independent of the data layer and business layer. Sometimes the "business layer" can be skipped, in simple cases.

    Although it's true that MVC does not have any point if there are no different "Views" - which is usually the case. Fat client is pretty much dead and buried nowadays and browsers can handle just one html so we don't need to render two/three different ones (MSIE and Mozilla). And if you have one possible "View", you don't need generic Model (the Data Layer API is sufficient enough) nor the generic Controller (because that is just a hassle without any added value).

    So yeah, it might be a little bit of Cargo Cult.

    "But what if your API needs to be consumed by an IoT toaster without a filesystem?" I would hope that this toaster has the ability to call stored procedures. I've worked on .NET CF devices with very stripped-down functionality, and even those could connect to a database. Failing that, make a webservice.

    :wtf_owl: Stored procedures called directly? :trwtf:
    Just no. Don't do that. Do a webservice (RPC, REST-like, whatever) or anything with proper API


  • BINNED

    Unless I’m hopelessly out of touch, I don’t see how MVC differs at all from your three-layer architecture?

    Model = Data
    View = Presentation
    Controller = Business

    But LHS is a cargo cult and RHS is clean and logical, apparently…


  • Discourse touched me in a no-no place

    @Groaner The MVC terminology came originally from doing desktop GUI apps.

    • Model was the data objects of the application, including database and files and stuff in memory.
    • View was the rendering of the model on the screen; changes to the model become changes to the displayed view immediately.
    • Controller was the code to take GUI events (like “the mouse was clicked at this coordinate”) and change them into alterations to the model.

    That sort of thing makes sense. Mulching those together causes huge confusion. But… I've never understood how any of that works on the web. I can sort of apply it in my mind to an SPA (and then the client-local model does back-end magic to communicate with the server) but the other bits of it just never clicked.



  • @Groaner said in A critical look at Marvel vs. Capcom....:

    Controller calls a Service
    Service calls a Repository
    Repository calls a homegrown data layer that builds a SQL statement and executes it
    SQL results are consumed into a strongly-typed DataTable

    IMO, the repository should be your data layer. And if you had classes generated by an ORM, that would be your data layer.


  • kills Dumbledore

    @kazitor said in A critical look at Marvel vs. Capcom....:

    Unless I’m hopelessly out of touch, I don’t see how MVC differs at all from your three-layer architecture?

    Model = Data
    View = Presentation
    Controller = Business

    But LHS is a cargo cult and RHS is clean and logical, apparently…

    Data access is a separate layer to any of the MVC sections, called by the controller and returning models. A model should just be a plain data class.

    Since there are viewmodels in the architecture described, this is actually MVVM. I'm not sure if MVVM is overly complex (at least in the way it's usually used within asp.nedlt MVC), or if I misunderstood something fundamental when attempting to use it, but it always seemed like a massive faff that was just slightly less annoying than creating a new model and related data access method


  • 🚽 Regular

    @Groaner said in A critical look at Marvel vs. Capcom....:

    This raises a question which begs to be answered

    👀


  • Considered Harmful

    I feel like this whole thread is a 🚎, but whatever, it beats working.

    To me, what makes MVC good is the fact that you can easily isolate any of its parts and mock out the others. The view depends on nothing else but the model, which should be just a plain old C# object, so you can very easily plug in a mock or fake in its place, or hook it up to a completely different controller. You can test it in isolation, a designer can look at the "form submitted" state without submitting the form, etc.

    Similarly, the model is separate from both the data access (service/repository) and the business logic (controller), which again means that either of these can be swapped out for a different implementation, shared between multiple implementations, and mocked and faked.

    I could write something about Controllers, but it's the same deal as the other two: it's independently usable and testable.

    TBH the separation between service and repository is a little less useful to me, and I often just merge those two. (He said, as if he was able to use MVC at work.) I guess you might want to test your data transformation/mapping logic, but I just use AutoMapper anyway so it usually Just Works.

    Try any of that with an ASPX, I dare you.


  • ♿ (Parody)

    @error said in A critical look at Marvel vs. Capcom....:

    I feel like this whole thread is a 🚎, but whatever, it beats working.

    I'd say it's a long running gripe between Groaner's lawn and people who adhere to a particular design philosophy.


  • Notification Spam Recipient

    @Groaner said in A critical look at Marvel vs. Capcom....:

    "ASPX and Stored procedure" pattern, which has the business layer moved, typically into the data layer.

    I worked in something like this. It's absolutely horrible if business layer has any complexity to it.


  • Considered Harmful

    @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    "ASPX and Stored procedure" pattern, which has the business layer moved, typically into the data layer.

    I worked in something like this. It's absolutely horrible if business layer has any complexity to it.

    It's also a real pain in the ass to keep the sproc versions synced with the application versions when doing a CI deploy, especially when you have different versions deployed across different environments. That's a DB schema issue, but thankfully, we don't change the schema often. If all your logic is in sprocs, you'd be changing it a lot more.


  • Notification Spam Recipient

    @error said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    "ASPX and Stored procedure" pattern, which has the business layer moved, typically into the data layer.

    I worked in something like this. It's absolutely horrible if business layer has any complexity to it.

    It's also a real pain in the ass to keep the sproc versions synced with the application versions when doing a CI deploy, especially when you have different versions deployed across different environments. That's a DB schema issue, but thankfully, we don't change the schema often. If all your logic is in sprocs, you'd be changing it a lot more.

    Yeah, client says something innocent like "we want to split this column into two, because reasons" and you're like "sure, will be ready in two weeks, maybe".


  • I survived the hour long Uno hand

    @error said in A critical look at Marvel vs. Capcom....:

    I feel like this whole thread is a 🚎, but whatever, it beats working.

    To me, what makes MVC good is the fact that you can easily isolate any of its parts and mock out the others. The view depends on nothing else but the model, which should be just a plain old C# object, so you can very easily plug in a mock or fake in its place, or hook it up to a completely different controller. You can test it in isolation, a designer can look at the "form submitted" state without submitting the form, etc.

    Similarly, the model is separate from both the data access (service/repository) and the business logic (controller), which again means that either of these can be swapped out for a different implementation, shared between multiple implementations, and mocked and faked.

    I could write something about Controllers, but it's the same deal as the other two: it's independently usable and testable.

    TBH the separation between service and repository is a little less useful to me, and I often just merge those two. (He said, as if he was able to use MVC at work.) I guess you might want to test your data transformation/mapping logic, but I just use AutoMapper anyway so it usually Just Works.

    Try any of that with an ASPX, I dare you.

    I second @error's comments, especially about the isolation and mocking.

    I've worked on a project that uses predominantly EntityFramework code-first as its ORM for the model layer on the API backend. When I first started working with it, we were using EF6, and I cussed at EF a lot, because every time we tried to do a complicated query via LINQ & EF, the performance was terrible, and it would save a ton of time and server resources to just redo it as a stored procedure. But the tech lead on the project kept challenging me to keep it in EF and tune it, and eventually I was able to sort out the problem. And, by and large, he was right -- 90%+ of our terrible EF queries weren't problems with EF, but problems with how we built the query (aka, our code).

    Once I got to the point where I was comfortable with the right way to write LINQ that EF could translate properly, I definitely saw the benefits of the ORM model over stored procedures:

    1. The LINQ queries were much more accessible for even junior developers to be able to write/modify
    2. You have the ability to make a good delineation between processing (sort/filter/etc) on the SQL server vs on the web server, while still having a single location & syntax for managing the queries (instead of having to manage both T-SQL and the CLR language of your choice)
    3. You only have one spot to manage your data model

    I was especially impressed (once I got over the initial frustration) with the migration to EF Core. With the .NET Core rewrite, the EF team made the explicit decision to be a bit less hand-holdy of bad LINQ code, and require you to explicitly opt-in to client-side processing when you write a query that can't be translated into T-SQL (compared to the EF 6 behavior of just implicitly doing it and creating the Query That Sucks(tm) that we struggled with so much when I started on the project).

    tl;dr: I'll never go back to advocating "put it all in stored procedures", unless I'm at a large enough organization that they actually do have full up DBA & database developers actively attached to projects. I've learned to love the ORM blinks twice


  • Considered Harmful

    @izzion Back in the .NET 2.0 days I had to build a search form that had roughly 30 fields, and each field if specified required a separate join on the backend. First stab at that had a static query with all possible joins, and it ran slow AF. I had to do unspeakable things with dynamic SQL to only join the necessary data for a given query. I would have killed for something like EF at that point.


  • ♿ (Parody)

    @error said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    "ASPX and Stored procedure" pattern, which has the business layer moved, typically into the data layer.

    I worked in something like this. It's absolutely horrible if business layer has any complexity to it.

    It's also a real pain in the ass to keep the sproc versions synced with the application versions when doing a CI deploy, especially when you have different versions deployed across different environments. That's a DB schema issue, but thankfully, we don't change the schema often. If all your logic is in sprocs, you'd be changing it a lot more.

    Yeah, I almost can't believe the people who say their stuff works like that. I mean...I do believe them, but I can't imagine thinking it was a good idea.



  • @Kamil-Podlesak said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Having worked on an actual MVC project for once, and spent enough time deep in the patterns, I'm beginning to question its utility.

    So the workflow in the app I maintain is something like this:

    1. User clicks button to frobnicate widget.
    2. HTML element onclick event calls [Java | Type]script method which gets or posts an HTTP endpoint
    3. Endpoint is mapped to a controller
    4. Controller calls a Service
    5. Service calls a Repository
    6. Repository calls a homegrown data layer that builds a SQL statement and executes it
    7. SQL results are consumed into a strongly-typed DataTable
    8. Mapper class takes values from this DataTable and maps values to a Model
    9. Repository passes Model results to Service
    10. Service maps Model results to a Viewmodel using a second mapper class and returns to Controller
    11. Controller returns Viewmodel results via HTTP response
    12. [Java | Type]script consumes results and does the needful

    Now, when I was a youngling developer, the elders taught me the importance of separation of concerns, and that code should be divided into layers. Usually, it was presented as three layers:

    • Presentation layer: responsible for putting text on a page and mapping variables to onscreen values, as well as gathering user input and passing that on to the...
    • Business layer: handles operations on a very high level, that is to say, frobnicating a widget. It cares not for the nitty-gritty of how a widget is frobnicated in the database, as that's the concern of the...
    • Data layer: handles CRUD/persistence operations and maybe does some mapping to and from classes at best.

    This makes for a rather simple architecture as there's a clean, logical separation of concerns, and not too many steps in between that would all need to be retrofitted should there need to be a major change in the workflow.

    I don't really understand the this part. Apparently the application you work on use three-layer data model
    as you describe it, but... something?

    It's not a three-layer model. If it were, the call stack wouldn't be near a dozen layers deep.

    It's little convoluted, indeed, especially the abundance of data structures, but what does that have to do with MVC?

    I see the Repository and Service patterns pop up frequently in the MVC world, not just in the app I maintain, which suggests to me that Model-View-Controller doesn't just mean Model, View, and Controller.

    This raises a question which begs to be answered: if a two or three layer architecture yields maintainable code, why do we need the whole MVC pattern?

    I don't understand the question. How do these two things relate? MVC is a presentation-layer thing, independent of the data layer and business layer. Sometimes the "business layer" can be skipped, in simple cases.

    Although it's true that MVC does not have any point if there are no different "Views" - which is usually the case. Fat client is pretty much dead and buried nowadays and browsers can handle just one html so we don't need to render two/three different ones (MSIE and Mozilla). And if you have one possible "View", you don't need generic Model (the Data Layer API is sufficient enough) nor the generic Controller (because that is just a hassle without any added value).

    So yeah, it might be a little bit of Cargo Cult.

    I used to work with a guy that would label all his classes with a Fowler citation of which pattern it implemented. He probably came from the Java world, so I was ultimately able to forgive him for it. Sort of.

    "But what if your API needs to be consumed by an IoT toaster without a filesystem?" I would hope that this toaster has the ability to call stored procedures. I've worked on .NET CF devices with very stripped-down functionality, and even those could connect to a database. Failing that, make a webservice.

    :wtf_owl: Stored procedures called directly? :trwtf:
    Just no. Don't do that. Do a webservice (RPC, REST-like, whatever) or anything with proper API

    36246e9d-7e2a-4380-a681-3522861ed742-image.png

    I'm with you on at least putting it behind a webservice, but stored procedures already have the elements of an API: a unit of work, input parameters, and a contract (which can be altered at any time).


  • Considered Harmful

    @Groaner said in A critical look at Marvel vs. Capcom....:

    a contract (which can be altered at any time).

    Remind me not to sign any contracts from you.

    :vader:



  • @dkf said in A critical look at Marvel vs. Capcom....:

    @Groaner The MVC terminology came originally from doing desktop GUI apps.

    • Model was the data objects of the application, including database and files and stuff in memory.
    • View was the rendering of the model on the screen; changes to the model become changes to the displayed view immediately.
    • Controller was the code to take GUI events (like “the mouse was clicked at this coordinate”) and change them into alterations to the model.

    That sort of thing makes sense. Mulching those together causes huge confusion. But… I've never understood how any of that works on the web. I can sort of apply it in my mind to an SPA (and then the client-local model does back-end magic to communicate with the server) but the other bits of it just never clicked.

    And it's all really just a rebranding of the age-old concept of "separation of concerns." With necessary overcomplication, of course.



  • @error said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    a contract (which can be altered at any time).

    Remind me not to sign any contracts from you.

    :vader:

    Move fast and break things, baby!



  • @Groaner said in A critical look at Marvel vs. Capcom....:

    the age-old concept of "separation of concerns."

    If it's such an age-old concept, why does so much old code ignore it?



  • @sockpuppet7 said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Controller calls a Service
    Service calls a Repository
    Repository calls a homegrown data layer that builds a SQL statement and executes it
    SQL results are consumed into a strongly-typed DataTable

    IMO, the repository should be your data layer. And if you had classes generated by an ORM, that would be your data layer.

    Architects would disagree, saying that a Controller should only deal with a Service, since a Service is concerned with performing a business action and a Repository is concerned with persisting or retrieving data (why we're calling something that isn't a background process a Service is another question for another time), so you can change to a different Repository at any given point in time (e.g. switching from a SQL backend to CouchDB*, or a plain text file store). And even the Repository doesn't necessarily need to be tied to one database architecture - that's handled by even lower layers.

    There is no ORM because the application I work with is probably old enough to drive, if not vote, and thus has hand-rolled models and mappers.

    There is admittedly no reason for half of the layers of abstraction above if a proper ORM is available. Which isn't in use here because reasons.

    *I probably need to update my square-wheel-reinventor jokes from circa 2012. What's the latest in stupid, non-ACID data stores for people who don't like to learn SQL?



  • @Jaloopa said in A critical look at Marvel vs. Capcom....:

    @kazitor said in A critical look at Marvel vs. Capcom....:

    Unless I’m hopelessly out of touch, I don’t see how MVC differs at all from your three-layer architecture?

    Model = Data
    View = Presentation
    Controller = Business

    But LHS is a cargo cult and RHS is clean and logical, apparently…

    Data access is a separate layer to any of the MVC sections, called by the controller and returning models. A model should just be a plain data class.

    Since there are viewmodels in the architecture described, this is actually MVVM. I'm not sure if MVVM is overly complex (at least in the way it's usually used within asp.nedlt MVC), or if I misunderstood something fundamental when attempting to use it, but it always seemed like a massive faff that was just slightly less annoying than creating a new model and related data access method

    Viewmodels can also be wildly divorced from plain old models as well. You might show an Order on a page, but the viewmodel might contain values for each of the dropdown lists, as well as individual order items.


  • I survived the hour long Uno hand

    @Groaner said in A critical look at Marvel vs. Capcom....:

    *I probably need to update my square-wheel-reinventor jokes from circa 2012. What's the latest in stupid, non-ACID data stores for people who don't like to learn SQL?

    Cloud :tro-pop:



  • @error said in A critical look at Marvel vs. Capcom....:

    I feel like this whole thread is a 🚎, but whatever, it beats working.

    To me, what makes MVC good is the fact that you can easily isolate any of its parts and mock out the others. The view depends on nothing else but the model, which should be just a plain old C# object, so you can very easily plug in a mock or fake in its place, or hook it up to a completely different controller. You can test it in isolation, a designer can look at the "form submitted" state without submitting the form, etc.

    Similarly, the model is separate from both the data access (service/repository) and the business logic (controller), which again means that either of these can be swapped out for a different implementation, shared between multiple implementations, and mocked and faked.

    I could write something about Controllers, but it's the same deal as the other two: it's independently usable and testable.

    I keep hearing praises being sung about mockability and dependency injection/IoC (don't get me started on dependency injection/IoC, also known as "Everything's an Interface that's only implemented by one class, and if you didn't decorate your types perfectly, now you get an unhelpful error when your IoC framework shits itself since it can't map to a desired type without telling you where to look.").

    If the QA team wrote unit tests, I could perhaps see the value in this. But at every place I've worked, the QA team have always done either manual or automated testing of the actual UI, making a mockery of the idealized process.

    TBH the separation between service and repository is a little less useful to me, and I often just merge those two. (He said, as if he was able to use MVC at work.) I guess you might want to test your data transformation/mapping logic, but I just use AutoMapper anyway so it usually Just Works.

    Try any of that with an ASPX, I dare you.

    That's what ObjectDataSource/EntityDataSource is for. Behold, now your Webforms page is calling a business layer, and your business layer can be isolated and directly tested.

    Even if you're stuck on SqlDataSources calling stored procedures, you can at least test those stored procedures.





  • @boomzilla said in A critical look at Marvel vs. Capcom....:

    @error said in A critical look at Marvel vs. Capcom....:

    I feel like this whole thread is a 🚎, but whatever, it beats working.

    I'd say it's a long running gripe between Groaner's lawn and people who adhere to a particular design philosophy.

    I should also mention that just because it says there's a design philosophy doesn't mean that that actual design philosophy is being employed.

    It's sort of like how one team I worked with called themselves "Agile," but there was no daily scrum, no scrum master, no story points, no retrospective, no sprints, no estimation, no velocity.... Then, when you go to work on a team that actually does those things it's sort of a culture shock.



  • @MrL said in A critical look at Marvel vs. Capcom....:

    @error said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    "ASPX and Stored procedure" pattern, which has the business layer moved, typically into the data layer.

    I worked in something like this. It's absolutely horrible if business layer has any complexity to it.

    It's also a real pain in the ass to keep the sproc versions synced with the application versions when doing a CI deploy, especially when you have different versions deployed across different environments. That's a DB schema issue, but thankfully, we don't change the schema often. If all your logic is in sprocs, you'd be changing it a lot more.

    Yeah, client says something innocent like "we want to split this column into two, because reasons" and you're like "sure, will be ready in two weeks, maybe".

    That's not a problem of stored procedures, that's a problem of "you never store more than one fact in a column, period."

    If the customer unilaterally decides that a column should contain multiple facts, well, life sucks and it takes time to change.


  • ♿ (Parody)

    @Groaner said in A critical look at Marvel vs. Capcom....:

    @sockpuppet7 said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Controller calls a Service
    Service calls a Repository
    Repository calls a homegrown data layer that builds a SQL statement and executes it
    SQL results are consumed into a strongly-typed DataTable

    IMO, the repository should be your data layer. And if you had classes generated by an ORM, that would be your data layer.

    Architects would disagree, saying that a Controller should only deal with a Service, since a Service is concerned with performing a business action and a Repository is concerned with persisting or retrieving data (why we're calling something that isn't a background process a Service is another question for another time), so you can change to a different Repository at any given point in time (e.g. switching from a SQL backend to CouchDB*, or a plain text file store). And even the Repository doesn't necessarily need to be tied to one database architecture - that's handled by even lower layers.

    Talk like this makes me want to vomit. Occasionally someone mentions that we should migrate away from Oracle and I laugh at them. I have lots of sql and hql in what this sort of person would call a "controller."

    The main effect of putting it all in a service (and I already do have lots of services and service methods) would be to scatter my code around and have a zillion similarly named methods because I always need to access the same data in sliiiiightly different ways. Or you have monster methods building codethulu dynamic queries.



  • @HardwareGeek said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    the age-old concept of "separation of concerns."

    If it's such an age-old concept, why does so much old code ignore it?

    Simple, there's another age-old concept called "technical debt!"


  • I survived the hour long Uno hand

    @Groaner said in A critical look at Marvel vs. Capcom....:

    If the QA team wrote unit tests, I could perhaps see the value in this. But at every place I've worked, the QA team have always done either manual or automated testing of the actual UI, making a mockery of the idealized process.

    :theresyourproblem.pptx:

    The unit tests are by devs, for devs, so they can have confidence that what they're handing over for QA to verify (after they've already QA'd it themselves, since you do run your code before you commit it, right?) that their changes didn't result in unintended changes to other core processes. If the unit tests aren't being written or run until the code goes "over the wall" to QA (and having QA be "over the wall" from the devs is a bit of :trwtf: anyway but I digress), then of course there's no value to the process.



  • @boomzilla said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    @sockpuppet7 said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Controller calls a Service
    Service calls a Repository
    Repository calls a homegrown data layer that builds a SQL statement and executes it
    SQL results are consumed into a strongly-typed DataTable

    IMO, the repository should be your data layer. And if you had classes generated by an ORM, that would be your data layer.

    Architects would disagree, saying that a Controller should only deal with a Service, since a Service is concerned with performing a business action and a Repository is concerned with persisting or retrieving data (why we're calling something that isn't a background process a Service is another question for another time), so you can change to a different Repository at any given point in time (e.g. switching from a SQL backend to CouchDB*, or a plain text file store). And even the Repository doesn't necessarily need to be tied to one database architecture - that's handled by even lower layers.

    Talk like this makes me want to vomit. Occasionally someone mentions that we should migrate away from Oracle and I laugh at them. I have lots of sql and hql in what this sort of person would call a "controller."

    In a previous life, the Decider™ frowned upon bit columns in favor of Y/N (or Q, or 2, or empty string, or null, you get the drift) columns in case we ever needed to migrate to Oracle.

    Because someday we just might outgrow SQL Server with our tiny databases with row counts that typically maxed out in the hundreds of thousands and very rarely in the millions.

    I didn't tell him that the app made extensive use of SQL Server functions and procedures that would have made such a transition far more difficult.

    The main effect of putting it all in a service (and I already do have lots of services and service methods) would be to scatter my code around and have a zillion similarly named methods because I always need to access the same data in sliiiiightly different ways. Or you have monster methods building codethulu dynamic queries.

    Where I draw the line is that if the same operation happens in two or more places, that must be encapsulated. Pretty cut and dry. There's no need to create a Service until there's an entire collection of such operations, at which point the extra effort not only makes maintenance easier, but creates the convenience of having a collection of solved problems and building blocks.


  • Considered Harmful

    @Groaner said in A critical look at Marvel vs. Capcom....:

    @boomzilla said in A critical look at Marvel vs. Capcom....:

    @error said in A critical look at Marvel vs. Capcom....:

    I feel like this whole thread is a 🚎, but whatever, it beats working.

    I'd say it's a long running gripe between Groaner's lawn and people who adhere to a particular design philosophy.

    I should also mention that just because it says there's a design philosophy doesn't mean that that actual design philosophy is being employed.

    It's sort of like how one team I worked with called themselves "Agile," but there was no daily scrum, no scrum master, no story points, no retrospective, no sprints, no estimation, no velocity.... Then, when you go to work on a team that actually does those things it's sort of a culture shock.

    My employer self-identifies as Agile.



  • @Kamil-Podlesak said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Having worked on an actual MVC project for once, and spent enough time deep in the patterns, I'm beginning to question its utility.

    So the workflow in the app I maintain is something like this:

    1. User clicks button to frobnicate widget.
    2. HTML element onclick event calls [Java | Type]script method which gets or posts an HTTP endpoint
    3. Endpoint is mapped to a controller
    4. Controller calls a Service
    5. Service calls a Repository
    6. Repository calls a homegrown data layer that builds a SQL statement and executes it
    7. SQL results are consumed into a strongly-typed DataTable
    8. Mapper class takes values from this DataTable and maps values to a Model
    9. Repository passes Model results to Service
    10. Service maps Model results to a Viewmodel using a second mapper class and returns to Controller
    11. Controller returns Viewmodel results via HTTP response
    12. [Java | Type]script consumes results and does the needful

    Now, when I was a youngling developer, the elders taught me the importance of separation of concerns, and that code should be divided into layers. Usually, it was presented as three layers:

    • Presentation layer: responsible for putting text on a page and mapping variables to onscreen values, as well as gathering user input and passing that on to the...
    • Business layer: handles operations on a very high level, that is to say, frobnicating a widget. It cares not for the nitty-gritty of how a widget is frobnicated in the database, as that's the concern of the...
    • Data layer: handles CRUD/persistence operations and maybe does some mapping to and from classes at best.

    This makes for a rather simple architecture as there's a clean, logical separation of concerns, and not too many steps in between that would all need to be retrofitted should there need to be a major change in the workflow.

    I don't really understand the this part. Apparently the application you work on use three-layer data model
    as you describe it, but... something?

    It's little convoluted, indeed, especially the abundance of data structures, but what does that have to do with MVC?

    This raises a question which begs to be answered: if a two or three layer architecture yields maintainable code, why do we need the whole MVC pattern?

    I don't understand the question. How do these two things relate? MVC is a presentation-layer thing, independent of the data layer and business layer. Sometimes the "business layer" can be skipped, in simple cases.

    Although it's true that MVC does not have any point if there are no different "Views" - which is usually the case. Fat client is pretty much dead and buried nowadays and browsers can handle just one html so we don't need to render two/three different ones (MSIE and Mozilla). And if you have one possible "View", you don't need generic Model (the Data Layer API is sufficient enough) nor the generic Controller (because that is just a hassle without any added value).

    So yeah, it might be a little bit of Cargo Cult.

    "But what if your API needs to be consumed by an IoT toaster without a filesystem?" I would hope that this toaster has the ability to call stored procedures. I've worked on .NET CF devices with very stripped-down functionality, and even those could connect to a database. Failing that, make a webservice.

    :wtf_owl: Stored procedures called directly? :trwtf:
    Just no. Don't do that. Do a webservice (RPC, REST-like, whatever) or anything with proper API

    In oracle, you can present stored procedures as REST. No need for anything but a database and some node.



  • @Groaner said in A critical look at Marvel vs. Capcom....:

    @sockpuppet7 said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Controller calls a Service
    Service calls a Repository
    Repository calls a homegrown data layer that builds a SQL statement and executes it
    SQL results are consumed into a strongly-typed DataTable

    IMO, the repository should be your data layer. And if you had classes generated by an ORM, that would be your data layer.

    Architects would disagree, saying that a Controller should only deal with a Service, since a Service is concerned with performing a business action and a Repository is concerned with persisting or retrieving data (why we're calling something that isn't a background process a Service is another question for another time), so you can change to a different Repository at any given point in time (e.g. switching from a SQL backend to CouchDB*, or a plain text file store). And even the Repository doesn't necessarily need to be tied to one database architecture - that's handled by even lower layers.

    The person you're describing isn't an architect; it's an architecture astronaut.


  • Notification Spam Recipient

    @Groaner said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    @error said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    "ASPX and Stored procedure" pattern, which has the business layer moved, typically into the data layer.

    I worked in something like this. It's absolutely horrible if business layer has any complexity to it.

    It's also a real pain in the ass to keep the sproc versions synced with the application versions when doing a CI deploy, especially when you have different versions deployed across different environments. That's a DB schema issue, but thankfully, we don't change the schema often. If all your logic is in sprocs, you'd be changing it a lot more.

    Yeah, client says something innocent like "we want to split this column into two, because reasons" and you're like "sure, will be ready in two weeks, maybe".

    That's not a problem of stored procedures, that's a problem of "you never store more than one fact in a column, period."

    If the customer unilaterally decides that a column should contain multiple facts, well, life sucks and it takes time to change.

    Pretty much any change in schema is a nightmare with stored procedures. Splitting a column is just an example.
    Not that change to logic itself is not a nightmare.

    For simple systems this approach may work, kind of. But i wouldn't go with SPs for even the simplest things.



  • @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    @error said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    "ASPX and Stored procedure" pattern, which has the business layer moved, typically into the data layer.

    I worked in something like this. It's absolutely horrible if business layer has any complexity to it.

    It's also a real pain in the ass to keep the sproc versions synced with the application versions when doing a CI deploy, especially when you have different versions deployed across different environments. That's a DB schema issue, but thankfully, we don't change the schema often. If all your logic is in sprocs, you'd be changing it a lot more.

    Yeah, client says something innocent like "we want to split this column into two, because reasons" and you're like "sure, will be ready in two weeks, maybe".

    That's not a problem of stored procedures, that's a problem of "you never store more than one fact in a column, period."

    If the customer unilaterally decides that a column should contain multiple facts, well, life sucks and it takes time to change.

    Pretty much any change in schema is a nightmare with stored procedures.

    Why? Schema changes will require a similar amount of effort whether you do SQL in the application, use an ORM or whatever.

    For simple systems this approach may work, kind of. But i wouldn't go with SPs for even the simplest things.

    How would you handle an operation that requires inserts into multiple tables that must all happen in the same transaction (for example, shipping an order)? You could either...

    • Set up a transaction in client code, and build DML by hand or through the use of an ORM to touch all the tables that need to be touched when shipping an order, or
    • Call dbo.ShipOrder


  • @Mason_Wheeler said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    @sockpuppet7 said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Controller calls a Service
    Service calls a Repository
    Repository calls a homegrown data layer that builds a SQL statement and executes it
    SQL results are consumed into a strongly-typed DataTable

    IMO, the repository should be your data layer. And if you had classes generated by an ORM, that would be your data layer.

    Architects would disagree, saying that a Controller should only deal with a Service, since a Service is concerned with performing a business action and a Repository is concerned with persisting or retrieving data (why we're calling something that isn't a background process a Service is another question for another time), so you can change to a different Repository at any given point in time (e.g. switching from a SQL backend to CouchDB*, or a plain text file store). And even the Repository doesn't necessarily need to be tied to one database architecture - that's handled by even lower layers.

    The person you're describing isn't an architect; it's an architecture astronaut.

    Well, that too. Although, if forced to choose between a stickler for building all the layers "properly", or having important business logic in Button1_Click(), it might be a difficult decision.



  • @error said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    "ASPX and Stored procedure" pattern, which has the business layer moved, typically into the data layer.

    I worked in something like this. It's absolutely horrible if business layer has any complexity to it.

    It's also a real pain in the ass to keep the sproc versions synced with the application versions when doing a CI deploy, especially when you have different versions deployed across different environments. That's a DB schema issue, but thankfully, we don't change the schema often. If all your logic is in sprocs, you'd be changing it a lot more.

    That's why you don't be a retarded Indian and put all of your logic in SPs. The only time an SP should have more than the most basic logic is when it's backing a report.

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Well, that too. Although, if forced to choose between a stickler for building all the layers "properly", or having important business logic in Button1_Click(), it might be a difficult decision.

    If you design your core application as static functions, the only logic in your click handlers should be copying input into parameters and catching exceptions before they crash the window manager. As a bonus, it's now easy to automate your program because it's not locked into a UI (a browser or a real one).


  • Notification Spam Recipient

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Why? Schema changes will require a similar amount of effort whether you do SQL in the application, use an ORM or whatever.

    Changes in schema don't propagate through stored procedures, so you don't know what stopped working. You have no tests for SPs, so you don't know what stopped working correctly. Hell, you can easily forget to update something if it's rarely used.

    With properly done data model you make a change in one place and immediately see what's affected and how, if you have tests set up, even better.

    How would you handle an operation that requires inserts into multiple tables that must all happen in the same transaction (for example, shipping an order)? You could either...

    • Set up a transaction in client code, and build DML by hand or through the use of an ORM to touch all the tables that need to be touched when shipping an order, or
    • Call dbo.ShipOrder
    using(var context = new AdventureWorksContext())
    {
        //do stuff
    
        context.Save();
    }
    

    Type safety, change propagation, error checking at compile time. You don't even have to think which tables were touched.

    That's the most desired situation of course, a proper ORM. But you can do similar things by hand with some more effort. The main thing is: keep SQL away from business logic, keep db away from application.

    do SQL in the application
    build DML by hand

    No, never again.


  • Considered Harmful

    Alright this thread is too batshit for me. I'm out.



  • @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Why? Schema changes will require a similar amount of effort whether you do SQL in the application, use an ORM or whatever.

    Changes in schema don't propagate through stored procedures, so you don't know what stopped working. You have no tests for SPs, so you don't know what stopped working correctly. Hell, you can easily forget to update something if it's rarely used.

    That's why you always do a global search for references before making any change. Before even deciding to make any change to assess the impact of such a change.

    using(var context = new AdventureWorksContext())
    {
        //do stuff
    
        context.Save();
    }
    

    Type safety, change propagation, error checking at compile time. You don't even have to think which tables were touched.

    And still have all the run-time errors to deal with, with the added bonus of not easily being able to tune your queries.

    That's the most desired situation of course, a proper ORM. But you can do similar things by hand with some more effort. The main thing is: keep SQL away from business logic, keep db away from application.

    Why? When you're using an ORM, your application is still marrying itself to the schema. That much doesn't change.

    do SQL in the application
    build DML by hand

    No, never again.

    I would agree with you, but there are these things called "legacy applications," so we'll have to deal with them for a while yet. Although, strangely enough, that problem isn't so bad if the application only deals in stored procedures and views....


  • Notification Spam Recipient

    @Groaner said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    @Groaner said in A critical look at Marvel vs. Capcom....:

    Why? Schema changes will require a similar amount of effort whether you do SQL in the application, use an ORM or whatever.

    Changes in schema don't propagate through stored procedures, so you don't know what stopped working. You have no tests for SPs, so you don't know what stopped working correctly. Hell, you can easily forget to update something if it's rarely used.

    That's why you always do a global search for references before making any change. Before even deciding to make any change to assess the impact of such a change.

    Yes, you are forced to do searches, because business logic in SPs is a fragmented mess that you have no control of.

    using(var context = new AdventureWorksContext())
    {
        //do stuff
    
        context.Save();
    }
    

    Type safety, change propagation, error checking at compile time. You don't even have to think which tables were touched.

    And still have all the run-time errors to deal with

    What runtime errors?

    with the added bonus of not easily being able to tune your queries.

    You can tune queries in ORMs, at least in good ones. But you don't have to worry about it if you write your BL well, as @izzion said.

    That's the most desired situation of course, a proper ORM. But you can do similar things by hand with some more effort. The main thing is: keep SQL away from business logic, keep db away from application.

    Why?

    Because SQL is a bad choice for writing business logic and dealing with db in application is just added complexity.

    When you're using an ORM, your application is still marrying itself to the schema. That much doesn't change.

    Not really. You either design schema to mirror business domain, or you translate schema objects to business objects and do BL with them. Either way, db is just a CRUD machine you don't deal with directly.

    I would agree with you, but there are these things called "legacy applications," so we'll have to deal with them for a while yet.

    I worked with stuff done this way in the past and from then on turned down every offer that involved it. I may consider doing it again for a lot of 💰, but those offers tend to pay less than market average :crazy:


  • Discourse touched me in a no-no place

    @Groaner said in A critical look at Marvel vs. Capcom....:

    don't get me started on dependency injection/IoC, also known as "Everything's an Interface that's only implemented by one class, and if you didn't decorate your types perfectly, now you get an unhelpful error when your IoC framework shits itself since it can't map to a desired type without telling you where to look."

    In the Java world, such things are found usually because there is actually two implementations of the interface, one of which is an automatically-constructed proxy (and the real implementation is in a different classloader to the clients of the interface). Without that, you're left stuck with more ghastly kinds of runtime codegen and that sort of complexity really can introduce weird bugs. (I've seen some strange shit with ORM-generated code. I write my own data binding layers now.)


  • Discourse touched me in a no-no place

    @MrL said in A critical look at Marvel vs. Capcom....:

    You don't even have to think which tables were touched.

    I've seen those things before. They're where it's all too easy to end up fetching a 100MB table from the database just to check whether there are any results, and then fetch all that data again just to get the first few values. And then people wonder vaguely why things aren't meeting their performance requirements.


  • Notification Spam Recipient

    @dkf said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    You don't even have to think which tables were touched.

    I've seen those things before. They're where it's all too easy to end up fetching a 100MB table from the database just to check whether there are any results, and then fetch all that data again just to get the first few values. And then people wonder vaguely why things aren't meeting their performance requirements.

    I wouldn't say it's easy to do that. You would need to have zero understanding of your ORM, zero understanding of your db and fuck up on top of that. Certainly possible, as experience shows, but not really easy.


  • Discourse touched me in a no-no place

    @MrL said in A critical look at Marvel vs. Capcom....:

    You would need to have zero understanding of your ORM, zero understanding of your db and fuck up on top of that

    But that's the thing: too many people treat having these binding layers as an excuse to not have any understanding. The fuck-ups follow inevitably from that.


  • Notification Spam Recipient

    @dkf said in A critical look at Marvel vs. Capcom....:

    @MrL said in A critical look at Marvel vs. Capcom....:

    You would need to have zero understanding of your ORM, zero understanding of your db and fuck up on top of that

    But that's the thing: too many people treat having these binding layers as an excuse to not have any understanding. The fuck-ups follow inevitably from that.

    Would those people put in the work to understand direct interaction with a db?


  • Discourse touched me in a no-no place

    @MrL said in A critical look at Marvel vs. Capcom....:

    Would those people put in the work to understand

    No. The rest of your sentence is unnecessary.

    🤡: “Work harder, not smarter.”


Log in to reply