[HN Gopher] Why Use Onion Layering?
___________________________________________________________________
Why Use Onion Layering?
Author : thunderbong
Score : 64 points
Date : 2024-07-07 16:44 UTC (3 days ago)
(HTM) web link (garrettdbates.com)
(TXT) w3m dump (garrettdbates.com)
| theamk wrote:
| Reads like a middle part of the post... What exactly does author
| mean by "onion layering" and what are they being opposed to?
|
| The author supplies some examples (new API field, new
| microservice dependency, new library dependency) but their fixes
| seem to apply to any well-organized code - I don't see why you'd
| need to use some mysterious "onion layering" to create a wrapper
| around insane dependency and isolate it from the rest of the
| code.
|
| (Google searches show only a few results and they all seem
| slightly different, so I am guessing this variant of "onion
| layering" is something author made up but didn't share with
| anyone - their blog has only one post)
| 8note wrote:
| I think you're looking for
| https://jeffreypalermo.com/2008/07/the-onion-architecture-pa...
| theamk wrote:
| Except your link has layers as "(Infra / UI / Tests) ->
| application -> domain services -> domain model", with "core"
| cross-cutting via inner 3 layers
|
| While OP has "config -> (API / Infra) -> core"
|
| Seems pretty different... I don't think author was referring
| to that particular page.
| cjohnson318 wrote:
| Yeah, I was confused. This is basically just, "have well
| defined interfaces, and pass simple data through them", but
| with no concrete examples.
| DrMiaow wrote:
| Isn't this how everyone (competent) designs systems?
| efnx wrote:
| You would hope, but some folks don't have a background in APIs
| and don't really know when life could be better.
| barbariangrunge wrote:
| What do you mean by background in apis? You mean experience
| working with them?
| Sankozi wrote:
| No, you do not need to design system like that. Just because
| there is a chance that something might change (domain logic,
| library/REST API), does not mean you need to create anti
| corruption layers everywhere. They limit problems during the
| (possible but not certain) change but they make code less
| readable, less performant and harder to test.
|
| Always analyze and decide if it is worth it.
| whstl wrote:
| I feel like systems design is a bit like the Anna Karenina
| quote, every good software is alike, but the bad ones are
| different in their own way.
|
| The Gary Bernhardt talk "Boundaries" shows an end result that
| is very close to The Onion Architecture presented here. And
| Onion is of course very close to the also popular Clean
| Architecture and Hexagonal Architecture. Which at the end are
| very close to applications built using the principles that
| cjohnson318 mentioned: "have well defined interfaces, and pass
| simple data through them".
|
| This is all very close to some of the principles Bertrand Meyer
| teaches. For example, having different modules that make
| decisions and different modules that perform actions. Which is
| close to Event Sourcing and CQRS. Which once again is close to
| BASIC having SUBs and FUNs.
|
| Sure, under a microscope you will have different terminologies,
| and even apply different techniques and patterns, but the
| principles in the end are very similar. You might not have
| anti-corruption layers anywhere, as the sibling commenter
| mentioned, but that's missing the forest for the trees: the end
| goal and end result are virtually the same, even if the
| implementation is different.
|
| In the end happy families have different socioeconomic
| backgrounds, different ethnicities and religions, but they're
| still alike. It's the bad ones that have lots of special cases
| and exceptions everywhere in their design or whatever it is.
| tomck wrote:
| No, this is how everyone incompetent designs systems
|
| Layers of generic APIs required to be 1000x more complex than
| would be required if they were just coupled to the layer above
|
| Changing requirements means tunneling data through many layers
|
| Layers are generic, which means either you tightly couple your
| APIs for the above-layer's use case, or your API will limit the
| performance of your system
|
| Everyone who _thinks_ they can design systems does it this way,
| then they end up managing a system that runs 10x slower than it
| should + complaining about managers changing requirements 'at
| the last minute'
| vbezhenar wrote:
| I don't follow your reasoning.
|
| The point of abstraction is to limit blast radius of
| requirement changes.
|
| Someone decides to rename field in API? You don't need to
| change your database schema and 100500 microservices on top
| of it. You just change DTO object and keep old name in the
| other places. May be you'll change old name some day, but you
| can do it in small steps.
|
| If your layer repeats another layer, why is it a layer in the
| first place? The point of layer is to introduce abstraction
| and redirection. There's cost and there's gain.
|
| Every problem can be solved by introducing another layer of
| indirection. Except the problem of having too many layers of
| indirection.
| tomck wrote:
| Every layer you create is another public API that someone
| else can use in some other code. Each time your public API
| is used in a different place, it gathers different
| invariants - 'this function should be fast', 'this function
| should never error', 'this function shouldn't contact the
| database', etc. More invariants = more stuff broken when
| you change the layer.
|
| So let's say you have some 'User' ORM entity for a food
| app. Each user has a favourite food and food preferences.
| You have a function `List<User>
| getListOfUsersWithFoodPreferences(FoodPreference
| preference)` which queries another service for users with a
| given food preference.
|
| The `User` entity has a `String getName()` and `String
| getFavouriteFood()` methods, cool
|
| Some other team builds some UI on top of that, which takes
| a list of users and displays their names and their
| favourite food.
|
| Another team in your org uses the same API call to get a
| list of users with the same food prefs as you, so they loop
| over all your food prefs + call the function multiple
| times.
|
| Amazing, we've layered the system and reused it twice!
|
| Now, the database needs to change, because users can have
| multiple favourite foods, so the database gets restructured
| and favourite foods are now _more expensive_ to query -
| they 're not just in the same table row anymore.
|
| As a result, `getListOfUsersWithFoodPreferences` runs a bit
| slower, because the favourite food query is more expensive.
|
| This is fine for the UI, but the other team using this
| function to loop over all your food prefs now have their
| system running 4x slower! They didn't even need the user's
| favourite food!
|
| If we're lucky that team gets time to investigate the
| performance regression, and we end up with another function
| `getListOfUsersWithFoodPreferencesWithoutFavouriteFoods`.
| Nice.
|
| The onion layer limited the 'blast radius' of the DB
| change, but only in the API - the performance of the layer
| changed, and that broke another team.
| djeastm wrote:
| This is where command/query separation is strongest
| regardless of onion/layered architecture. Your
| queries/reads are treated entirely separately from your
| commands/writes so you're free to include/exclude any of
| the joined data a particular query doesn't need.
| tomck wrote:
| I have no idea what you're talking about, my example
| doesn't include any writes, only a read
| djeastm wrote:
| Forgive me for not tying it back to your example
| explicitly.
|
| Your example was a read. So in that case since there's no
| change in state (no need for protection of the
| data/invariants) there's no dangers in having different
| clients read the User records from the datastore however
| makes sense for them. They could use the ORM or hit the
| DB directly or anything, really. So
| getListOfUsersWithFoodPreferences and
| getListOfUsersWithFoodPreferencesWithoutFavouriteFoods
| living together as client-specific methods is absolutely
| fine. It's only when state changes that you need to bring
| in the User Entity that has all of the domain rules and
| restrictions.
|
| The idea is that while on Commands (writes) you need your
| User entity, but on Queries (reads) there's no need to
| treat the User data as a one-size-fits-all User object
| that must be hydrated in the same way by all clients.
| tomck wrote:
| > So getListOfUsersWithFoodPreferences and
| getListOfUsersWithFoodPreferencesWithoutFavouriteFoods
| living together as client-specific methods is absolutely
| fine
|
| Sorry; my point was that adding this function as a public
| API 'onion layer' in your code means you're less able to
| adapt to change. The fact this function returns a `User`
| entity isn't particularly important - it's the fact when
| you make a function public, other teams will reuse your
| function and add invariants you didn't realise existed,
| so that changing your function in the future will break
| other teams' code.
|
| Less public 'onion layers' means less of this
| usrbinbash wrote:
| > The point of abstraction is to limit blast radius of
| requirement changes.
|
| No, the point of abstraction is to make things easier to
| handle.
|
| At least that is the _original_ meaning of the term, before
| the OOP ideology got its hands on it. A biology textbook
| talks about organs before it talks about tissues before it
| talks about cells before it talks about enzymes. That is
| the meaning of abstraction: Simple interface to a complex
| implementation.
|
| In OOP-World however, "abstraction", for some reason,
| denotes something _MORE COMPLEX_ than the things that are
| abstracted. It 's a kind of logic-flow-routing-layer
| between the actually useful components that implement the
| actual business logic.
|
| And such middleware is perfectly fine ... _as long as it is
| required_. Usually it isn 't, which is where YAGNI comes
| from.
|
| Now, pointless abstractions are bad enough. But things get
| REALLY bad, when we drag things that should sit together in
| the same component, kicking and screaming, into yet another
| abstraction, so we can maybe, someday, but really never
| going to happen, do something like rename or add a field to
| a component. Because now we don't even have useful
| components any more, we have abstractions, which make up
| components, and seeing where a component starts and ends,
| becomes a non-trivial task.
|
| In theory this all seems amazing, sure. It's flexible, it's
| OOP, it is correct according to all kinds of books written
| by very smart people.
|
| In reality however, these abstractions introduce a cost,
| and I am not even talking about performance here, I am
| talkig about readability and maintainability. And as it
| turns out in the majority of usecases, these costs far
| outweigh any gains from applying this methodology. Again:
| There is a reason YAGNI became a thing.
|
| As someone who had the dubious pleasure to bring several
| legacy Java services into the 21st century, usually what
| following these principles dogmatically results in, is a
| huge, bloated, unreadable codebase, where business
| functionality is nearly impossible to locate, and so are
| types that actually represent business objects. Because
| things that could be handled in 2 functions and a struct
| that are tightly coupled (which is okay, because they
| represent one unit of business logic anyway), are instead
| spread out between 24 different types in as many files. And
| not only does this make the code slow and needlessly hard
| to maintain, it also makes it brittle. Because when I
| change the wrong Base-Type, the whole oh-so-very-elegant
| pile of abstractions suddenly comes crashing down like a
| house of cards.
|
| When "where does X happen" stops being answerable with a
| simple `grep` over the codebase, things have taken a wrong
| turn.
| seanhunter wrote:
| > The point of abstraction is to limit blast radius of
| requirement changes.
|
| The problem is in many/most? systems there's no way it can
| possibly do this, because the abstraction that looked like
| a perfect fit for requirements set 1 can't know what the
| requirements in set 2 look like. So in my experience what
| ends up happening with the abstraction thing is people put
| all sorts of abstractions all over the place that seem like
| a good idea and when requirements set #2, #3, etc come
| along you end up having to change all the actual code to
| meet the requirements _and_ all of the abstraction layers
| which no longer fit.
|
| To choose a couple of many examples from my personal
| experience:
|
| - One place I worked had a system the author thought was
| very elegant which used virtual functions to do everything.
| "When we need to extend it we can just add a new set of
| classes which implement this interface and it will Just
| Work". Except when the new requirements came in we now
| needed to dispatch based on the type of two things, not
| just one. Although you can do this type of thing in lisp
| and haskell you can't in C++ which is what we were using.
| So the whole abstraction ediface cost us extra to build in
| the first place, performance while in use and extra to tear
| down and rewrite when the actual requirements changed
|
| - One place I worked allowed people to extend the system by
| implementing a particular java interface to make plugins.
| Client went nuts developing 300+ of these. When the
| requirements changed it was clear we needed to change this
| interface in a way a straight automated refactor just
| couldn't achieve. Cue me having to rewrite 300+ plugins
| from InterfaceWhichIsDefinitelyNeverGoingToChangeA format
| to InterfaceWhichIsHonestlyISwearThisTimeAbsolutelyNeverGoi
| ngToChangeB format. I was really happy with all the time
| this abstraction was saving me while doing so.
|
| Most of the time abstraction doesn't save you time. It may
| save you cognitive overload by making certain parts of the
| system simpler to reason about, and that can be a valid
| reason to do it, but multiple layers is almost never worth
| it and the idea that you can somehow see the future and
| know the right abstraction to prevent future pain is
| delusional unless the problem space is really really well
| known and understood, which is almost never the case in my
| experience.
| redman25 wrote:
| I've experienced the same. It's difficult for frontend and
| backend to communicate because there's a "translation layer"
| in between. Shipping a new feature is 100x harder than it
| needs to be because everything has to be translated between
| two different paradigms.
| Quothling wrote:
| It was 10-20 years ago. Today nobody competent does it because
| it doesn't scale. A lot of the good parts of onion layering
| still exists in more modern architectures, especially in
| languages which are still very tied to the original OOP
| academic principles like Java or C# where you're likely to see
| interfaces for every class implementation, but as time has
| moved forward it's not really necessary to organize your
| functions inside classes, even if you're still doing heavy OOP.
| So today you're more likely to see the good parts of the onion
| layering build into how you might do domain based architecture.
| So even if you're doing models, services and so on, you build
| them related to a specific business domain where they live
| fully isolated from any other domain. Which goes against things
| like DRY, but if you've ever worked on something that actually
| needed to scale, or something which lived for a long time,
| you'll know that the only real principle that you have to care
| about is YAGNI and that you should never, ever build
| abstractions until you actually need them.
|
| Part of the reason onion still exists is because academia is
| still teaching what they did almost 30 years ago, because a lot
| of engineers were taught 30 years ago and because a lot of code
| bases are simply old. The primary issue with onion layering is
| that it just doesn't scale. Both in terms of actual compute but
| also in terms of maintenance. That being said, a lot of the
| ideas and principles in onion layering are excellent and as I
| mentioned still in use even in more modern architectures.
| You'll likely even see parts of onion layering in things like
| micro-services, and I guess you could even argue that some
| micro-service architectures are a modern form of onion
| layering.
|
| The more competent a system is designed, however, is often
| shown in how few abstractions are present. Not because
| abstractions are an inherent evil, but because any complexity
| you add is something you'll have to pay for later. Not when you
| create it, not a year later, but in five years when 20
| different people have touched the same lines of code a hundred
| times you're very likely going to be up to your neck in
| technical debt. Which is why you really shouldn't try to be
| clever until you absolutely need to.
| usrbinbash wrote:
| > you should never, ever build abstractions until you
| actually need them.
|
| This should be put on the cover of every programming
| textbook, in very bold, very red, letters.
|
| Right next to: "Measure before you optimize" and "Code is
| read 1000x more often than it is written"
| orthoxerox wrote:
| Yes and no. Onion is similar to IO-less Rust or "Functional
| core, imperative shell" in that it goes one step further from
| inversion of control/monadic effects and removes all
| control/effects from the inner layers.
|
| You get some benefits like being able to write very
| straightforward business logic, but in return you:
|
| - have to constantly fight the entropy, because every day
| you'll have to implement another corner case that is 2 points
| if you violate the layer isolation and 10 points if you
| reengineer the layers to preserve it
|
| - have to constantly repeat yourself and create helpers,
| because your API layer objects, your domain layer objects, your
| DB layer objects all look very similar to each other.
|
| Sometimes a transaction script (in Fowler's terminology) with
| basic DI scaffolding is easier both to write and maintain,
| especially when the domain isn't rocket science.
| pyinstallwoes wrote:
| Indirection?
| Etheryte wrote:
| > Imagine the most annoying possible client of our microservice.
| Suppose they want a new field, and they insist that it be named a
| certain way.
|
| This shows a fundamental misunderstanding of what code is for, at
| least in a production setting. Code isn't a marble statue that's
| supposed to be safely guarded in a museum, it's a way to get
| things done. Sure, for a hobby project you can polish it and
| perfect it like a diamond, but for business needs, the end goal
| of code is to do The Thing. That annoying client is why you're
| getting a high salary, if they didn't have their annoying needs,
| you wouldn't have a job.
| doctor_eval wrote:
| There is a lot more to meeting a customer's needs than blindly
| doing what they say. Sometimes, you need to write code to
| protect them from their own (sometimes-but-not-always rational)
| decisions - or to protect other customers and stakeholder from
| them.
|
| You also need to keep your own team nimble. I've seen plenty of
| systems that have just thrown code at the product, and they end
| up with SQL tables with 150 columns - most of which nobody
| uses, and which can't be removed, and the customer ends up
| pissed off anyway because you can no longer turn their requests
| around quickly.
|
| A good, layered design mitigates against this and makes it
| possible to continue to be productive even in the face of
| customer demands.
|
| Externalising customisations is a huge benefit to productivity.
| lexicality wrote:
| this looks like it's describing the typical java horror where you
| have to make a generic interface to every single dependency to
| pretend you might be able to swap them out at some point and then
| you drown in a sea of interfaces and indirection trying to
| abstract everything into purity
|
| please just write plain code that's easy to follow, easy to debug
| and easy to delete!
|
| you don't need the survivability onion
| seanhunter wrote:
| Yes exactly. Anyone who has worked on big java codebases has at
| least one horror story where there are 10s or 100s of classes
| each with "use once" interfaces wrapping them and there are
| bizarre consequences like for example, there is only one
| possible way to wire the application up but for "flexibility"
| you have to go through (and occasionally debug) a spring boot
| nightmare for some reason anyway because somebody read a blog
| post on dependency injection and thought that was a good idea.
| jpz wrote:
| This article doesn't define onion layering, I am none the wiser
| from reading it. There are near identical sentences within it, it
| gave me the sense I was reading AI generated content, or at least
| heavily AI post-processed content.
| Quothling wrote:
| Onion layering is a non-scalable architecture which was
| immensely popular in the 00-10's due to how it interacts with
| OOP and it's somewhat crazy principles. It's based on
| seperating everything by interfaces in a structure which is a
| little similar to a MVC architecture. So you're going to
| organize your project(s) into a structure where you centralize
| everything with a seperation based on what "something" does. So
| you're going to put your OOP models in a specific place, your
| services in another and so on. As you can imagine it scaled
| horribly and today it's made completely obsolete by domain
| based architecture which is basically Onion Layering but both
| more reasonably organized and actually scalable.
|
| A lot of CS academics still live in a world where OOP is the
| greatest thing ever. Where things like wrapping functions in
| classes are necessary and where things like the onion
| architecture is still "modern". So naturally a lot of
| inexperienced developers, or developers who've never had to
| work on large projects, still hail it as the holy grail.
|
| Note that this was a very opinionated post.
| mech422 wrote:
| >>Note that this was a very opinionated post.
|
| Bonus points for calling it out as opinion, instead of
| treating it as the 'one true way' :-)
|
| P.S. I still like OOP well enough, and I love formal
| interface support like Go/Rust use. (Just IMHO)
| NicoJuicy wrote:
| Onion, Hexagonal is pretty popular in the dotnet world and
| microservices.
|
| It's also overcomplicated for it's use-case and the main problem
| becomes mapping between layers and etc.
|
| Eg. One of the code-smells would be the Web.Abstractions layer.
|
| Just go with Vertical Slice Architecture. It dumbs everything
| down and if you need another technology as DB for example, you'll
| always need a migration of sorts, even if you have all the
| necessary abstractions.
|
| Note: Currently on a solo 4 month migration project going from
| Cognitive Search to Elastic, yes, we use "Onion".
| dgb23 wrote:
| I don't know what an onion is in programming terms.
|
| But each of those problems can be solved without one?
|
| ---
|
| 1. "Adding a field to our API"
|
| Parsing: You turn external input into an internal representation.
|
| 2. "Introducing a new downstream dependency"
|
| Essentially the same as above, but presumably bi-directional: You
| also turn your internal representation into something that is
| understood by your dependency.
|
| 3. "Introducing a new library dependency"
|
| I don't quite understand this example. Apparently writing a
| module that uses a third party library is an onion layer?
|
| ---
|
| Can someone explain what I'm missing?
| whalesalad wrote:
| Separation of concerns, essentially.
|
| https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-a...
| mmastrac wrote:
| The article is describing, in a less clear way than they could, a
| clear separation of concerns in code. This is a good practice,
| especially for complex code.
|
| There is a tradeoff though: adding too many layers of indirection
| makes changes just as complicated as if you wrote a big ball of
| spaghetti (oh, just propagate this field across all 10 layers!),
| and that your team needs to be diligent about making changes to
| the correct layers.
|
| With a small, high-quality team this absolutely pays dividends in
| terms of ease of migration and changes, but you need to ensure
| there is good knowledge of the architecture spread across
| multiple people.
|
| The ideal place for this is in code with unclear, or rapidly
| changing business requirements.
|
| Note that this doesn't prevent you from getting bogged down by
| excessive complexity -- it literally just limits the blast radius
| of this complexity and makes the inevitable future refactorings
| smaller in scope.
| chipdart wrote:
| > The article is describing, in a less clear way than they
| could, a clear separation of concerns in code.
|
| My take is a bit harsher. The article tries to reinvent the
| wheel -- poorly -- and fails to do the faintest and most
| superficial researches on a topic which is already covered in
| basic courses on software engineering.
|
| Layered architecture is a ubiquitous name in any work on
| software architecture, such as popular offshoots such as Uncle
| Bob's Clean Architecture. They describe the benefits of
| organizing software projects around layers, but go a step
| beyond and effectively solve the problem by also classify what
| kind of responsibilities should be assigned to each layer and
| how the dependency relationships between layers should be
| managed and enforced. I'm talking about basic principles such
| as internal/lower-level layers should contain code that changes
| the least frequently.
|
| There are also some software architectures which abandon the
| whole concept of layer and instead specify organizing the
| project in independemt submodules implementing/sharing common
| interfaces, and have root project handle only integration. This
| is often dubbed horizontal architecture as in all modules are
| laid out horizontally, as in they specify no dependency
| relationships with modules represented above or below, instead
| of vertically, as in modules are expected to comply with a
| fixed relationship archetype.
| mcphage wrote:
| > adding too many layers of indirection makes changes just as
| complicated as if you wrote a big ball of spaghetti (oh, just
| propagate this field across all 10 layers!), and that your team
| needs to be diligent about making changes to the correct
| layers.
|
| "Layers of abstraction can solve any problem in software
| design, except for having too many layers of abstraction" :-)
| dekelpilli wrote:
| Abstracting everything you use has a (high) cost, and doesn't
| always achieve what you want. This article repeatedly states
| things "go no further", but realistically, some dependencies will
| have worse inconveniences than a bad field name. If database you
| rely on is relational, has token based pagination, and has
| eventual consistency, chances are that swapping to a consistent
| timeseries DB with only limit/offset based pagination will impact
| code in your *.core.* package.
| usrbinbash wrote:
| > Imagine the most annoying possible client of our microservice.
| Suppose they want a new field, and they insist that it be named a
| certain way.
|
| Then I tell the client that I sent him the API specification 2
| months ago. If he isn't happy with it, he can write a wrapper
| himself.
|
| Of course, I could also change the API. Whether or not I do that
| depends on 4 factors in that order:
|
| 0) Do I have the time and resources to do so?
|
| 1) How important is the client?
|
| 2) How much does he pay me to do the change?
|
| 3) Exactly how annoying is the client?
| cangeroo wrote:
| The article is extremely short and by an unknown author, so there
| isn't much to discuss.
|
| But I've met many people who hated onion architecture with a
| passion.
|
| I have a few theories:
|
| - Maybe a lot of programmers have ADHD, are autistic, or suffer
| from dyslexia, and find planning, naming, designing abstractions
| as excruciating activities.
|
| - Onion architecture etc. is a long-term strategy that mainly
| benefits the company/project owner, but not the individual
| contributor. So it basically has to be forced upon programmers,
| who will resist it in every way possible, because they have no
| real incentive to use it.
|
| - It's supposed to make writing software easier. But it really
| requires an IDE that's designed for abstractions, such as
| IntelliJ, and also requires a different way of working with the
| code. It's also verbose. So it's really a different paradigm, and
| it won't work if you use a plain text editor. You'll drown in
| code and a vast number of files.
|
| - Onion architecture is not OOP, but often mixed in with
| enterprise OOP, and therefore bad associations that come with
| enterprise OOP.
|
| Any other thoughts on why people resist it so much?
|
| And what changes in how we work with code, would make onion
| architecture more practical?
| victorNicollet wrote:
| > Onion architecture etc. is a long-term strategy that mainly
| benefits the company/project owner, but not the individual
| contributor. So it basically has to be forced upon programmers,
| who will resist it in every way possible, because they have no
| real incentive to use it.
|
| Although I was aware of it for a while now, I had never seen
| this misalignment (between what I called ease-of-writing and
| ease-of-maintenance) stated so clearly in so few words. Thank
| you !
| djeastm wrote:
| >- Maybe a lot of programmers have ADHD, are autistic, or
| suffer from dyslexia, and find planning, naming, designing
| abstractions as excruciating activities.
|
| I don't know about the medical conditions, per se, but I think
| this does bring up a point that is often overlooked when
| discussing best practices: our brains are different and
| organize things in different ways.
|
| What works and makes sense to one group of people might not
| work or make sense to another group of people. I find that more
| literal-minded people are frustrated by what they see as
| unnecessary abstraction and are fine with duplicated code
| whereas people who think in abstractions have no problem seeing
| the bigger picture and are proponents of abstractions when the
| abstractions make sense to them.
|
| I have coworkers who will look at a codebase with a
| layered/onion architecture and immediately understand and reuse
| all of the abstractions without issue and others who will
| immediately want to simplify it and change it all into concrete
| implementations. I find myself to be fairly evenly split so I
| see it from both sides.
|
| I think it's often more about the nature of the latest person
| who looks at the codebase than the codebase itself. Eye of the
| beholder and all that.
| cangeroo wrote:
| Have you found anything that makes everyone happy and
| productive?
|
| I sometimes wonder if we'll replace traditional design
| patterns, especially OOP, with new patterns, that are neither
| OOP or FP, but perhaps a different paradigm (e.g. how Prolog
| is wildly different from C++).
| djeastm wrote:
| >Have you found anything that makes everyone happy and
| productive?
|
| Not really. It's kind of a constant push-pull and a lot of
| compromises. In the end it's just about getting things done
| and dealing with the friction in stride when it comes.
|
| I've often wondered what it would be like working at a
| workplace where everyone programs with the same mental
| models, but have never worked at such a place myself and
| I'm not even sure it's possible.
| mech422 wrote:
| >>does bring up a point that is often overlooked when
| discussing best practices: our brains are different and
| organize things in different ways.
|
| I really notice this when I first look at a code base...Its
| not that the code is 'bad' but more of a 'what were they
| thinking' when the code was laid out. Eventually you get used
| to it, but its a bit of a shock when you first encounter it
| as the organization, data structures, etc are so 'alien' to
| how you would organize it yourself...
| joshstrange wrote:
| I think layers are important (All internal data should be mapped
| onto DTOs to returned to a client IMHO) but it's also important
| to not have more than 2 layers to get to the core, ideally 1.
|
| I've worked places before where they have you call through a
| function that calls a function that calls a function (replace
| "function" with "api endpoint" in some cases) because "Well we
| know function X works and so just call it", then fast-forward a
| year or two "Well we know function Y works, which calls X, so
| it's safest if you call Y, don't call X" and so on. This leads to
| a complete mess and tons of inefficiencies. Often "X" over/under-
| fetches what you want so you either have to throw away some of
| the result or add to it. I've even seen cases of Z->Y->X where X
| over-fetches, Y only uses a subset, and then Z has to re-fetch
| the data that Y threw away. All because someone decided an
| arbitrary layer is the new golden standard that everything should
| be built on.
___________________________________________________________________
(page generated 2024-07-10 23:02 UTC)