A Contrarian View of Software Architecture - Jeremy Miller - NDC Oslo 2023

Ғылым және технология

I’ve spent an inordinate amount of time the past half decade across multiple companies working with very large, long running enterprise systems. Especially in long running, constantly changing systems, you want the code to be easy to understand, relatively painless to extend or modify, and when advantageous, be simple to modernize with updated technology. Unfortunately, the systems I’ve worked on have consistently failed to satisfy these goals.
Ironically enough though, my judgment is that the code in these systems has been hard to understand, extend or change, and modernize because they had all adopted much of the very industry conventional wisdom about how to build large, maintainable systems.
In particular, I want to demonstrate and explain how I think that prescriptive, layered architectural styles like Clean or Onion Architecture can actually cause harm in larger systems. I also want us to train our sights on how teams attempt to hide the actual persistence technology with “repository” abstractions and why I also think that’s harmful. I want us to shine a light on how teams fall down a trap of organizing code around business entities or data storage in ways that helps make the code in big systems hard to work with.
And of course, we’re going to talk about alternatives, or at least ways to ameliorate the potential problems with prescriptive architectural approaches. In particular, I’m going to show the shift to vertical slice architecture approaches for organizing code. I’m also going to examine ways to reduce code ceremony to improve code readability and use that to show the negative tradeoffs of using approaches like the Clean Architecture that mandate some elements of code ceremony to “force” developers into a consistent approach. And finally, we’re going to examine whether or not “consistency” should be a first class goal in code organization or architecture.
Check out our new channel:
NDC Clips:
@ndcclips
Check out more of our featured speakers and talks at
ndcconferences.com/
ndcoslo.com/

Пікірлер: 33

  • @russellf
    @russellf9 ай бұрын

    As an old dev, I’m on board with this approach. For me it is about listening to your intuition rather than following patterns. However, all the suggested alternatives are based on layered approaches - you can’t get away from layers. Ports and adapters or onion architecture are the right approaches you just shouldn’t get carried away. A-Frame (which sounds like “imperative shell, immutable core”) is just layering again: the thing connecting the other bits is just in the outer layer. I agree though that it’s a tough problem as software can be structured in more than one way and you can usually make a valid argument for each way.

  • @youtux2
    @youtux27 ай бұрын

    26:30 effective automation testing is more important than rules about abstraction and layers. Man this sounds sooo true.

  • @leoromano9760
    @leoromano97609 ай бұрын

    Always love Jeremey’s honesty which forces you to think critically

  • @robertlenders8755
    @robertlenders875511 ай бұрын

    I think this should be taken a step further and isolate the business logic behind actually pure functions. No global state, no DI instrumentation, no IWhatever, just immutable data as arguments to functions that return immutable results.

  • @z0nx

    @z0nx

    9 ай бұрын

    You just described domain code, which you can obviously already do regardless of the framework/library/whatever. Just no Tasks

  • @russellf

    @russellf

    9 ай бұрын

    @@z0nxI assume you mean, the domain logic shouldn’t be doing any side-effects (most things requiring Task)?

  • @awright18
    @awright1811 ай бұрын

    This was a decent talk, i think a lot of this is becoming more mainstream, thankfully. Also Uncle Bob has touted the idea of organization by use cases in the past, im not sure if uts in his recent literature as i haven't cared to read them, but it feels like another old idea resurfacing

  • @llindeberg
    @llindeberg11 ай бұрын

    Im sad I had to deal with all this in projects I inherited, and this is what I was taught right from the start. So much unnecessary headache. I've come to all the same conclusions from experience

  • @ChrisAthanas
    @ChrisAthanas11 ай бұрын

    32:56 audio drop out problem

  • @ChrisAthanas
    @ChrisAthanas11 ай бұрын

    39:46 bad audio issues

  • @ChrisAthanas
    @ChrisAthanas11 ай бұрын

    I feel Yegor Bugayenko approach to OO is the most scalable architecture solution

  • @raimeyuu

    @raimeyuu

    10 ай бұрын

    Interesting, could you elaborate? 🤔

  • @ChrisAthanas

    @ChrisAthanas

    10 ай бұрын

    @@raimeyuu yegor bugayenko on yt I have made a sample project in my gh Realityexpander Jpages

  • @iamkaransethi
    @iamkaransethi10 ай бұрын

    Quite liked the session! Getting through so many layers to get a simple task done is frightening but at the same time also seems reasonable to achieve loose coupling. Quite interesting to see how Marten and Wolverine do most of the heavy lifting for us so devs only care about the logical units. But it might also come at the cost of losing customisation and a bit of a learning curve, ey? Cheers

  • @JeffryGonzalezHt
    @JeffryGonzalezHt11 ай бұрын

    Great job on an amazingly difficult set of concepts to address. I think one of the keys here for me is around the "abstracting the database" thing - which in practice has turned into this weird "goal" without any reasoning behind it. If you can a) integration test locally and continually, and b) use a clean database (in a container, like he showed), THAT is actually what we were looking for all along. If you don't need to stub some IQueryable crap to "unit test", but can test the actual code, everything kind of just falls into place. And I agree - the ability to integration test locally with containers is the most liberating thing to happen in my career in a long, long time. It forces you to write code that doesn't presume too much infrastructure - which gives you all the flexibility we were actually after with this code abstraction craze.

  • @igelineau

    @igelineau

    11 ай бұрын

    totally agree, we've had great success with this approach in our current project.

  • @kaizer-777
    @kaizer-7777 ай бұрын

    It can be annoying to have to jump around to different files to touch on every layer of the app to make a change that impacts the system from the top to the bottom. That said, having loose coupling makes it a hell of lot easier to make sweeping horizontal changes when you need to. Not only that, it makes it a lot easier to throw more people at a project. Once the domain classes and interfaces have been designed, it's entirely manageable to have one developer focus on DB while another writes app services and yet another is focused on controllers and/or front-end. It's just so much easier to avoid stepping on toes when everything is properly decoupled. If you're a one-man-army, yeah, it's probably overkill.

  • @vanivari359

    @vanivari359

    7 ай бұрын

    i spent a lot of time in the last years firefighting projects which were build without layers and abstractions by unexperienced agile teams. Those projects have not been very complicated with a rather small code base, but after about a year all three projects were no longer maintainable. The teams spent so much time fixing bugs (especially unintended side-effects), that they did not have time anymore to implement new features or refactor the system to clean up their mess. Whenever we try to simplify by removing a layer or a mapping between a layer or an abstraction, people mess it up big time immediately. One of that projects was full of external data models of systems - some of those called systems do not exist anymore and everyone joining the project wonders why there are so many classes with "CaseNew" in the name and even in the API. They used the classes generated from the API-spec of a system called CASE-NEW (the "new" case management... great name) and exposed some of them in their own API. In that special case, the reason for that mess was the architecture guideline created by one of those fancy-talk gurus introducing "minimalistic" architectures in companies (he even hates logging frameworks, basically requires you to expose your DB entity model in your REST API etc). Meanwhile, as a side task, i build new features into a 21 year old very big application which is heavily structured with layers and all kinds of abstractions. Not a problem at all, it's still running in its 23 year now and even really bad/cheap offshore outsourcing providers have not been able to ruin that system during their maintenance contract. 10 triple-A-grade developers will most likely create maintainable software no matter what, but many projects don't even get a single AAA developer.

  • @kaizer-777

    @kaizer-777

    7 ай бұрын

    @@vanivari359 That's rough. I definitely appreciate working in projects that were well-designed and abstracted from the beginning. It makes all the difference a few years down the road.

  • @Ry4nWTF

    @Ry4nWTF

    2 ай бұрын

    @@vanivari359 that's a skill issue, not an architectural problem. I have seen the same issues you described in

  • @youtux2
    @youtux27 ай бұрын

    Perhaps on a superficial level, but aren't these vertical slices akin to microservices? (as a concept, not in the sense of physical separation)

  • @paulopozeti9528
    @paulopozeti95289 ай бұрын

    I'm going to use this video to trigger some people. Thanks!

  • @br3nto
    @br3nto11 ай бұрын

    18:35 yes!! This!

  • @Reverence12389
    @Reverence1238911 ай бұрын

    Points out important problems in the talk, but I would say it could have greatly benefited from giving better examples on how to solve the problems, especially in complex scenarios. Although, probably hard to achieve that and keep the talk to under an hour.

  • @djn138
    @djn1387 ай бұрын

    Sound keeps cutting out.

  • @mackie1001
    @mackie100111 ай бұрын

    I think we’ve simultaneously come to the same conclusion and I’ve had a lot of similar ideas. My current implementation does not use static handlers or split data loader and pure handler functions but it does effectively drop unit of work (a set of mutations and events) out of the bottom of the handler which is then persisted by the event store implementation. I think I will experiment with splitting out the data loading aspect. I assume in Marten the wire up is all dynamic duck typing and runtime chaining of async loader function return value and handler function inputs with some dynamic method level DI too? I like the idea as the arguments are front and centre as plain arguments and the static method means you can’t cheat and use instance fields to pass state behind the scenes. An alternative that requires less dynamic runtime method invocations might be to populate an in memory cache/rep object that allows retrieval of preloaded data (including from external sources) using a pleasant interface that can assert rules like a particular thing being required or optional etc. this is a little more opaque (a bit like using a service locator vs constructor dependency injection) however. Certainly food for thought! The other bit we did is to make the data itself immutable and the transformations on the materialised data are strictly via pure functions. There’s no Store() call needed as we only persist things that are returned from the handler. It sounds like you’re looking to go the same way.

  • @vladluteen2299
    @vladluteen229911 ай бұрын

    Everytime you were about to say something important, the sound cut out. 😱

  • @goldnutter412
    @goldnutter41211 ай бұрын

    18:12 almost

  • @jenkins9202
    @jenkins920211 ай бұрын

    Audio is terrible

  • @AidanHaddonWright
    @AidanHaddonWright11 ай бұрын

    I'm starting to think observers are the ultimate architectural pattern. They seem to be working for the frontend and game developers so why isn't it standard practice in backend CRUD apps. Our controllers would become simple event signallers that tell the app a particular action was done by the user. Then we just have a multitude of event handlers to act on those events. We can just group handlers by feature. You don't need to worry about crossing service boundaries because a service will just pick up on the events it wants to. It sounds like the app would be a tangled mess. But as long as you have good integration tests, you can rearrange handlers as much as you want because they're not directly coupled.

  • @JohnDoe-yc6nm
    @JohnDoe-yc6nm10 ай бұрын

    fire the sound guy -.-

  • @matthewwilson2369
    @matthewwilson2369Ай бұрын

    Nodding furiously about verical slices.

  • @parcanapp1193
    @parcanapp119311 ай бұрын

    Glory to Ukraine

Келесі