When NOT to write an Abstraction Layer

  Рет қаралды 9,130

CodeOpinion

CodeOpinion

Күн бұрын

Пікірлер: 53
@SteveYeager
@SteveYeager 2 жыл бұрын
There's more benefits to abstracting 3rd party libraries though. - Wrapping calls to the library with common functionality like logging, metrics, circuit breakers, etc - Encapsulating certain features of the SDK (ie: I don't want a class that should only have read-only access to a DB to have a reference to a DbContext) - Can be easier to mock out for testing Not saying that you should always write abstraction layers but I generally have seen the above reasons as incentives rather than the mentioned ability to swap the library for another one. It can be a difficult choice to make for sure.
@stevep2513
@stevep2513 2 жыл бұрын
Another great one. I save ALOT of time writing raw sql in my application services layer + integration testing. Simple CRUD and transaction script where things are simple, swap to CQRS/ES when things get complex. I find when using lots of mocks/abstraction layers it makes "unit tests" very brittle and a mirror of the implementation. Adhere to YAGNI, you won't need to replace your database ( if you choose Postgres (: )
@sathyajithps013
@sathyajithps013 2 жыл бұрын
I've thought about this. Haven't implemented abstraction for 3rd party service though. I went with their own SDK.Thanks for giving a lecture on this.
@CodeOpinion
@CodeOpinion 2 жыл бұрын
There isn't a right or wrong because it depends on your context.
@codiguard
@codiguard 2 жыл бұрын
I would still go with abstraction in example you have shown. To be honest I haven't used Message Brokers, but I assume that when done wisely we still can abstract a lot of things and most of the API will remain intact on the client side in case of message broker "provider" change. Of course there still can be changes to the contract when replacing underlying implementation as you said, but in case of abstraction we need to change part of the API - not all API in case when there is no abstraction at all. Thanks for the video!
@hectorluisbarrientosmargol9303
@hectorluisbarrientosmargol9303 Жыл бұрын
Totally agree, if inversion of control and interfaces are used wisely I think abstraction can be applied in almost all cases
@walidlezzar2357
@walidlezzar2357 2 жыл бұрын
Thanks for the video! For me the idea has never been to abstract the technical functionalities of a sdk. I wouldn't expose the outbox pattern, stateful messaging etc. in my abstraction. Instead, the idea for me is to abstract the functionality part: in the case of the messaging example, my abstraction would very likely be an interface with a single method "sendEvent" and that's it!
@CodeOpinion
@CodeOpinion 2 жыл бұрын
If your abstraction is as simple as exposing one method, then sure. Often times, it's much more than that however. As an example with messaging, if you wanted to have encrypted messages or properties, that's going to be implemented in a very opinionated way by the library you're using.
@berkes
@berkes 2 жыл бұрын
I concur about the reason for abstractions. So I keep another rule of thumb for when to apply or forego: if the abstraction does not simplify the library or make it more concrete, just use the library/SDK/orm. An abstraction would have a chargeCard(), rather than a Card.changeAttribute(chargedAmount: 1337).save(). This makes it more concrete and simpler. But a AuthLib.isAllowed(user, 'update', profile) is hardly made simpler or more concrete by an abstraction layer. Obviously, benefit of less dependencies, unstable third parties, testability, etc still apply, so even if an abstraction does not simplify or concretise the lib, it may still be a good idea.
@evancombs5159
@evancombs5159 2 жыл бұрын
This is what I see as the primary purpose. Simplify the use of the dependency by hiding all of the ceremony and/or repetitive code. I don't want my code to have to worry about how it works.
@DaveRogersEsq
@DaveRogersEsq 2 жыл бұрын
I kinda agree with this. It's a case-by-case basis. The MS logging abstraction is a good example where you WOULD use the abstraction. And many loggers make it easy for you to do this by putting out a package that implements that abstraction itself.
@johnf7755
@johnf7755 2 жыл бұрын
As usual Derek I appreciate your content but have to respond because while what you're saying is true it's a bit like "If you're going to do abstraction wrong - don't do it". Here's an idea. Instead of trying to abstract all the functionality of the 3rd party library, how about just making a "small client specific interface". Now your code can depend on that, and through the magic of the adapter pattern, not even know that the 3rd party library exists. And the implementation of that interface can use all the features of the 3rd party library. The driver for this is never that I might want to substitute an alternative implementation later. It's so that my code (my business logic, not all the code I need to write to call the 3rd party library) can be pure and deterministic and live in a project with minimal package dependencies. It isolates business logic into one place. It prevents coupling between 3rd party dependencies. Unit tests on that project build fast. As an example, say your class wants to read a file, process the data, and write a file. There's no need for System.IO.Abstractions, just an interface with 2 methods. The implementation of which can just call File.ReadAllText etc.
@CodeOpinion
@CodeOpinion 2 жыл бұрын
Well the issue is that you don't know you're doing it wrong. If you're creating an abstraction that starts off small and you keep adding to it to expose more underlying functionality from the dependency, as you need it, you only know you're "doing it right" if you have multiple different underlying implementations. Now as we both mentioned, yes creating an indirection/abstraction to prevent direct coupling has a lot of benefits and should be a goal, absolutely. My point is that that's not always the case depending on the tool your abstracting. Is it beneficial, most of the time, likely. All the time, no. My concrete example of a messaging library is one that you shouldn't abstract. If you were using NServiceBus, you'll cause yourself more complexity by abstracting it. Appreciate the comment, John.
@johnf7755
@johnf7755 2 жыл бұрын
Fair point if the interface keeps growing but this is less likely if you're sticking to the client (class) specific interface (ISP). And I maintain that the interface is the contract between your code and the dependency. Other possible implementations are irrelevant.
@marna_li
@marna_li 2 жыл бұрын
I used to believe in ”best practice” by wrapping everything, but for things that you will not change it is quite an useless overhead. Libraries that themselves are abstractions, like EF Core, is a good example. There are case when you want to wrap, but as you lean towards, they are few. Of course, unit testing is a valid reason for abstracting away certain dependencies.
@CodeOpinion
@CodeOpinion 2 жыл бұрын
Ya, I forgot to mention testing. That being said, don't take a dependency on something (if you can) that has no good testing story.
@marna_li
@marna_li 2 жыл бұрын
@@CodeOpinionBefore ILogger, I have seen a lot of less than ideal abstractions on top of logging frameworks. Nowadays, I just expect the de-facto interfaces to be implemented.
@codiguard
@codiguard 2 жыл бұрын
There are some scenarios when abstracting data access layer still make sense. For example in case if you don't know what underlying data structure will be - DB, simple file, etc. Of course this is rare case because we usually go with databases for the most part, but still - something to keep in mind. For example "Uncle Bob" in one of his books mentioned that he started some project with simple files as a data structure for testing purposes and then he found out that they actually don't need DB at all and text files are enough also for production environment :)
@marna_li
@marna_li 2 жыл бұрын
@@codiguardI would create services that abstracts away everything that I don’t consider standards and things that rarely change in a project.
@bobbycrosby9765
@bobbycrosby9765 2 жыл бұрын
I still like to add a layer when I only use a tiny subset of features of a library. For the swap it out argument, it's the most lazy one I encounter. Anyone that says this I ask "oh, how many different libraries did you test to see if your abstraction layer works?" The answer is almost always 1. This is one of my big problems with over-abstraction. It's false flexibility, and it turns your code into a lie. When you create an interface, as a reader of code, it should be a contract of "I thought about this, I made my code flexible, here, use it". In a lot of enterprise software, it's actually "I looked at one scenario, layered an interface on top of it because I could, good luck using it in any other scenario".
@CodeOpinion
@CodeOpinion 2 жыл бұрын
"I looked at one scenario, layered an interface on top of it because I could, good luck using it in any other scenario". 😆 Very true.
@0x7273
@0x7273 2 жыл бұрын
I love wacthing your videos and having those 'Aha' moments when things click in my head.
@ddddddddd345
@ddddddddd345 2 жыл бұрын
The rule of thumb for abstractions/interfaces is that their value is equal to volume of things abstracted out divided by complexity & area of interface surface required for the interface to work. In other words: you want to abstract large amount of "stuff" (complexity; logic, whole external systems, etc.) using as small & simple interface as possible. Utility libraries with complex APIs are in practice in-abstractable: they have huge and often complex surface of which most will be used directly by your code.
@brandon9247
@brandon9247 9 ай бұрын
Perhaps the issue comes from a tendency to conflate the bridge and adapter patterns? When I was following along, it was unclear whether we were talking about an abstraction vs. adapter.
@donflamingo4325
@donflamingo4325 2 жыл бұрын
The Abstraction Layer in big enterprise applications is one of the fundaments. If You are using the N-Layer architecture, You must separate the application, from the infrastructure. From experience, the best way to get it is through abstractions. Why? 1. Infrastructure can be replaced, if You must use technical edge cases in Your abstractions, You did something wrong. 2. Directly working on core SDK is dangerous, when the external library will be updated, Your code can be broken or may have a lo changes.
@Zikakoo
@Zikakoo 2 жыл бұрын
On point 2. But if you are updating the SDK then your abstraction might not work. So then you must update your abstraction and now you are most likely slowly coupling your abstraction to the the underlying SDK
@donflamingo4325
@donflamingo4325 2 жыл бұрын
@@Zikakoo But You need only change to one place, not the whole application :-). That's a little difference Friend :-)
@CodeOpinion
@CodeOpinion 2 жыл бұрын
This is why I lean towards vertical slices rather than layers. At the end of the day it's about limiting coupling and increasing cohesion. Almost everything I talk about on this channel is rooted in coupling. FWIW, if you haven't already, check out the video on Vertical Slices. kzbin.info/www/bejne/mYe5fpWrgNKBm9U
@rickpowell1311
@rickpowell1311 2 жыл бұрын
This is great! Thank you for all your advice Interesting that you gave the outboxing pattern as an example of something you might look to 3rd party libraries to manage the abstraction. I'm yet to find a decent package in .Net however. Any recommendations?
@CodeOpinion
@CodeOpinion 2 жыл бұрын
NServiceBus, MassTransit, Brighter, CAP
@MaxPicAxe
@MaxPicAxe 2 жыл бұрын
No abstraction is better than a bad abstraction imo. At the same time, it is a good exercise for learning to try to build abstractions. Anyway, you learn most from your mistakes.
@MuhammadAdam-ko8my
@MuhammadAdam-ko8my 2 жыл бұрын
abstraction layer ought to be implemented when you want your code to interact with specific set of APIs which will be remained same or minimal change whatever implementation added behind that APIs .. If changing implementation affecting exposed interface to be changed greatly or the abstraction layer is mostly driven by implementation then I think it is better to use it directly rather add more complexity.
@CodeOpinion
@CodeOpinion 2 жыл бұрын
Pretty much sums up what I was saying!
@sarabwt
@sarabwt 2 жыл бұрын
@@CodeOpinion The problem is that the abstraction is thought as implementation. If I create a Repository interface and I define query as Repository.query(String sql, Class result) this means that my abstraction is not an abstraction. I know the example is kind of exaggerated, so it is obvious, but it can be way subtler and bite you after. When you gave the messaging example I think you are talking about doing something like MessageAbstraction.send(topic, payload) (tied to implementation) and not something like EventRepository.somethingHappened(context) right? I think that the problem comes from doing abstraction over a library/framework/tool/technicality and not over something that has to be done.
@bronekjelonek3323
@bronekjelonek3323 2 жыл бұрын
You also might want to have an option: use X or use Y (like in-memory/file based/fake). For tests, for the demo, etc. That's why I like intermitent layer, not sure abstraction is the name. I want to just, i.e. send the message. The same I use for filesystems, for event store, where I have my own implementation on files... However event store is quite complex thing and it took me some time to make something not very buggy.
@brandonpearman9218
@brandonpearman9218 2 жыл бұрын
I disagree with your base reasoning for abstraction. Abstraction should reveal the required functionality. There for any tech or 3rd party library should be able to fulfill that requirement, ie if the lib/tech has more feature that what your abstraction allows for, it is irrelevant because you dont require that anyway. I think the problem you are describing is not fundamental to abstraction but a result of architects trying to create company wide abstraction that can cater for 100 different teams. Then all they are doing is trying to expose all the functionality of the underlying tech/lib... leading to all the problems you are discussing. Abstraction done right allows easy change of tech, change/upgrade of libs, can offer more functionality by combining multiple techs/libs and simplifying tech/libs to your specific use case.
@CodeOpinion
@CodeOpinion 2 жыл бұрын
Thanks for the comment! I agree pretty much. "Done Right" is the interesting part there though.
@brandonpearman9218
@brandonpearman9218 2 жыл бұрын
@@CodeOpinion Yeah any pattern is good or bad depending on implementation and use case. The moment a pattern becomes popular it gets misused, then everyone says its bad and moves to the next shiney pattern... until that becomes misused... and the circle continues. You do videos on how to do CQRS right, but that is becoming an abomination in many orgs. Same goes for microservices. :( but dont think they are throw away ideas, because of bad implementations.
@brandonpearman9218
@brandonpearman9218 2 жыл бұрын
@@CodeOpinion Also not trying to be difficult or combative on the idea, but I personally think its a serious problem in the industry. DDD is another one, which i have seen you do a video on. We need some unpopular ideas.
@CodeOpinion
@CodeOpinion 2 жыл бұрын
@@brandonpearman9218 No, I appreciate the comment and discussion. The point of my video was be careful what you abstract because it can turn into a net negative. I'm not saying don't abstract, that would be insane. I'm saying not everything needs to be abstracted. In a different context, per Sandi Metz, prefer duplication over the wrong abstraction.
@iliyan-kulishev
@iliyan-kulishev 2 жыл бұрын
The more reusable we try to make something, the less usable it gets.
@CodeOpinion
@CodeOpinion 2 жыл бұрын
Often very true.
@jaroslavsurala1537
@jaroslavsurala1537 2 жыл бұрын
What about MassTransit library it is some kind of abstraction from real event bus. It is bad?
@CodeOpinion
@CodeOpinion 2 жыл бұрын
MassTransit, like NServiceBus, are abstractions over a transport that also provide implementation for various messaging patterns (like I mentioned).
@frotes
@frotes 2 жыл бұрын
MassTransit is exactly like the messaging library mentioned in the video. Just use it Plus it’s OSS, so you aren’t going to get burned if it goes away. You can also grab it and make modifications as needed
@jayhey2577
@jayhey2577 2 жыл бұрын
So what is alternative???
@jimhart5797
@jimhart5797 2 жыл бұрын
How does impact testing? Say I wanted to implement RabbitMQ. Typically I would creat an interface abstraction for the dependency, and use DI so it is testable.
@CodeOpinion
@CodeOpinion 2 жыл бұрын
It doesn't. Don't use a dependency that doesn't have a good testing story behind it. The RabbitMQ client returns interfaces I believe so fake that rather than your own interface. Or better yet, don't use the RabbitMQ SDK directly and use a messaging library that has a full blown testing story.
@FlaviusAspra
@FlaviusAspra 2 жыл бұрын
Before watching the video: Once you have your regular hexagonal architecture, do not introduce abstractions which are not used in at least two different parts of the code. Still, stronger principles: keep your domain free of any vendors by using pure fabrications. Also stronger: if the new dependency is a whole adapter, then do introduce that, and inside it use your new vendor. An adapter/port provides enough isolation. Don't forget: a microservice has in itself also an architecture, so you can have a set of microservices, each of them following hexagonal.
@iliyan-kulishev
@iliyan-kulishev 2 жыл бұрын
What kind of things you still abstract in your projects?
@CodeOpinion
@CodeOpinion 2 жыл бұрын
Database is often abstracted in a lot of places. File/Blob storage is usually abstracted since the API surface is very limited. Sending to an email service is abstracted if not using SMTP but rather say the API to AWS SES. Again, limited API surface. Using an Messaging Library to abstract a transport.
@yasinnabi
@yasinnabi 2 жыл бұрын
wow wonderful channel... I enjoyed watching. SUBBED ! a fellow creator ...;;;
@philmarlin6204
@philmarlin6204 Жыл бұрын
cap always abstract
CRUD API + Complexity = Death by a 1000 Papercuts
12:40
CodeOpinion
Рет қаралды 17 М.
Is an ANEMIC Domain Model really that BAD?
10:36
CodeOpinion
Рет қаралды 17 М.
Fake watermelon by Secret Vlog
00:16
Secret Vlog
Рет қаралды 15 МЛН
А ВЫ ЛЮБИТЕ ШКОЛУ?? #shorts
00:20
Паша Осадчий
Рет қаралды 2,8 МЛН
МЕБЕЛЬ ВЫДАСТ СОТРУДНИКАМ ПОЛИЦИИ ТАБЕЛЬНУЮ МЕБЕЛЬ
00:20
My daughter is creative when it comes to eating food #funny #comedy #cute #baby#smart girl
00:17
Clean Architecture Example & Breakdown - Do I use it?
15:25
CodeOpinion
Рет қаралды 183 М.
Eventual Consistency is a UX Nightmare
11:23
CodeOpinion
Рет қаралды 15 М.
Event Sourcing Example & Explained in plain English
18:23
CodeOpinion
Рет қаралды 115 М.
HTTP APIs don't magically remove Coupling (Part 2)
11:02
CodeOpinion
Рет қаралды 4,5 М.
Multi-Tenant: Database Per Tenant or Shared?
8:55
CodeOpinion
Рет қаралды 14 М.
Cursor Is Beating VS Code (...by forking it)
18:00
Theo - t3․gg
Рет қаралды 95 М.
Restructuring to a Vertical Slice Architecture
17:50
CodeOpinion
Рет қаралды 30 М.
My First look at .NET Aspire. What's with the Hype?
12:16
CodeOpinion
Рет қаралды 15 М.
Fake watermelon by Secret Vlog
00:16
Secret Vlog
Рет қаралды 15 МЛН