This BIG Modeling Mistake Is Ruining Your Performance

  Рет қаралды 11,002

Amichai Mantinband

Amichai Mantinband

4 ай бұрын

Get the source code: / amantinband
My courses on DomeTrain: dometrain.com/author/amichai-...
In todays video we'll talk about one of the biggest performance mistakes your app is likely making today. I've encountered this mistake in almost all applications I came across.
In this video we'll see what the problem is, how to fix it, and how significant it is in terms of performance.
Connect with me on 'em socials:
Twitter: / amantinband
LinkedIn: / amantinband
GitHub: github.com/amantinband
Thanks for watching, don't forget to like & comment & subscribe! ❤️ 💻

Пікірлер: 40
@pazzuto
@pazzuto 3 ай бұрын
Most value from this video: "Create an object small enough that contains what's needed to make a business decision." I wrote that down! 😁
@yardeZ93
@yardeZ93 3 ай бұрын
1) You started displaying an implementation which is actually a good implementation, then you asked about the problem with it. There isn't any problem with it actually, at least without a context. What you provided is just an performance optimization. So you solution is actually not needed if the app isn't suffered from performance issues. 2) What about DDD, if your User class is an aggregate root, and you want to apply action on the reminders via different flow, you still need it fully in the User class, if not consistency can't be accepted. 3) Appreciate your videos, as always 🙌
@AndersBaumann
@AndersBaumann 3 ай бұрын
I am complete agree on both points. If there is a performance problem then separate the write from the read. In general DDD and an ORM should only be used for writes. Use Dapper or full CQRS for reads.
@Forshen
@Forshen 4 ай бұрын
Thank you so much! I see this so much as well. In my experience, I see a lot of project that use an ORM system do this. That just get the relation/child entities (so full select and maybe other child entities) and do a count or whatever b.s. performace hit with it. Instead just a simple query to the db. I always encourage to use the database because in most scenario's the database is a lot faster, but don't over use it like that. P.s. I am a query builder guy. I don't use EF core, i use sqlkata.
@quicoll14
@quicoll14 2 ай бұрын
What if you need now to fetch the user with the Reminder object? Would you need to query it separately since your model does not have it together anymore? Or would you just use your DB models?
@Fikusiklol
@Fikusiklol 4 ай бұрын
Good point! But Im wondering to hear your opinion. What if you'd take DDD approach to mutate only 1 AR per transaction and eventual consistency is not an option at a first glance, aka 1) validate if you can add a reminder in the first place 2) create Reminder and publish an event 3) User picks it up and increments that count Would you lean towards idempotency to make it happen or something else?
@amantinband
@amantinband 4 ай бұрын
The single aggregate that should change in your example is the user. This is because the atomic decision is made by the user aggregate. Storing the reminder in the database can happen in a following transaction. Check out my clean architecture template, it implements exactly this using single AR per transaction and eventual consistency.
@Fikusiklol
@Fikusiklol 4 ай бұрын
​@@amantinband Just watched it, thanks. Cool stuff, but it really feels off for a User to produce another AR event. I was thinking more like User AR would validate and create Reminder AR using some internal static factory of Reminder class. So basically my thoughts are: 1) Why would a user produce another AR event? 2) What topic/queue would that event be published? Users or Reminders? Should be reminders, right? But again feels off to me. 3) What event type would Reminder class store in domainEvents? Its own or the one user created? 4) Would that Reminder's event even be published or not? 5) And if we add CQRS/ES on top of that it will become even more messy. Because initial event that would have been stored along with User AR would contain data that he (user AR) doesnt need at ALL to be recreated, but is needed for Reminder. Maybe because im not expereinced enough, thats why I asked. Thanks for the good content tho
@syedjunaid7846
@syedjunaid7846 3 ай бұрын
Hi Amichai love your vids and your style of teaching! Could you share what drawing tool you use for the vids? Its like powertoys but its looks so good! :)👍
@amantinband
@amantinband 3 ай бұрын
Presentify (it's macOS only though)
@parlor3115
@parlor3115 4 ай бұрын
Would it also be possible to have a reminderIdMap? I think this way, we'll be able to have a single source of truth for reminders on the user object.
@amantinband
@amantinband 4 ай бұрын
Yeah definitely
@EdwinMartin
@EdwinMartin 3 ай бұрын
I like how you consistently write remidner 🙂
@amantinband
@amantinband 3 ай бұрын
😂
@PeriMCS
@PeriMCS 3 ай бұрын
How about lazy loading? All Reminders would load only when you ask for them. And when you count it would count objects in dB without loading them. What I'm missing here is how you are going to save both User and Reminder now.
@Noceo
@Noceo 4 ай бұрын
Any particular reason why you don’t add a UserId to a reminder instead of the other way around?
@vivekkaushik9508
@vivekkaushik9508 4 ай бұрын
User 'has' reminders not the other way around.
@Noceo
@Noceo 3 ай бұрын
@@vivekkaushik9508 I get that. Another way of saying that, would be that a reminder belongs to a user. Represented by a user id.
@pazzuto
@pazzuto 3 ай бұрын
@@Noceo I guess he just didn't in this example, but yes, that's required, otherwise how would you retrieve the reminders for the user from the database.
@FFKangoroo
@FFKangoroo 2 ай бұрын
@@pazzuto Hmm, to follow his approach through the reminderIds list. Which has some drawbacks. To store this User Object in a DocumentDB will probably provide issues sizewise as most have document size limits(see explanation further down.). In a relational DB it could be moddeled as a reference table (reminderId, userId) which would result in an N:M relation, which would probably not be what he wanted. So yes in his example he probably should have added the UserId to the Reminders except he wants to make them shareable. I personally think that what he describes is not a good solution, and he also pointed this out by himself with another example, look at users over time. The RemindersMap and the _remindersIds is still growing indefinitely the longer the app runs for a specific user. So when Fetching the User Object, it not only can get large in size but also the computation which is needed for the aggregation grows aswell. Which obviously can be mitigated by looking only into the future. But the future itself is indefinitely large. So size wise, and this is for what he claims to optimise, reminders are no good candidate to get fetched preemptively with the UserObject. Considering the possible absolute size they should be fetched/calculated at will, which will probably not throw OutOfMemory exception in some SuperUser Cases and be more responsive on startup, but which might be slower on per Operation basis, although this can then be optimized in the Storage Engine through proper indexing (baiscally what he tried to do in the application itself)
@Linkario86
@Linkario86 3 ай бұрын
Yeah our applications suffer terribly from this. It's old and the exuse of "historically grown" is used a lot. Data-Access is from hell and huge amounts of Data is joined and loaded many times. None of the original devs is around anymore and nobody really dares to touch it, and if you do, the superiors won't accept the change out of fear it breaks the app. It's a legit fear though, but it really does feel like we're stuck with this. Reason I wanna become an Architect is that I have seen terrible Applications in a whole line-up of companies I worked for, and since I can't trust others to make somewhat stable applications, I figured I'll do it myself. Long way to go, and a cargoship load to learn, but I'll get there and just keep going. It benefits me as a Developer either way already.
@thibaultlesuisse8650
@thibaultlesuisse8650 3 ай бұрын
Completely argee. That why I like to use my DbContext inside my Application layer instead of reusing the same repository and fetching way too much data. Using my DbContect directly in my application layer forces me to think about what data I really need for this exact business use case.
@nayanchoudhary4353
@nayanchoudhary4353 3 ай бұрын
Well, this makes sense for RDBMS. On the flip side, retrieval of data will require joins which can be slow. So, creation is fast, but retrieval is slow. 😊 In general, a computer spends 60% of it's time searching. So, retrieval should always be faster than creation.
@PeriMCS
@PeriMCS 3 ай бұрын
If reminders are stored inside User this is still join. This only complicates saving.
@georgehomorozeanu
@georgehomorozeanu 3 ай бұрын
Hey Amichai, what drawing tool do you use? It’s not zoom it, right?
@amantinband
@amantinband 3 ай бұрын
Presentify (only available on MacOS though)
@kmcdo
@kmcdo 4 ай бұрын
I just noticed that this guy Vims. (I just started learning, it’s one of my 2024 goals to really build that Vim muscle memory)
@amantinband
@amantinband 4 ай бұрын
Best investment you’ll ever make
@benatmartinez1365
@benatmartinez1365 3 ай бұрын
When did he use it?
@Vreth6
@Vreth6 3 ай бұрын
He is using VsVim which is an extension to Vscode that lets you use Vim movements and commands.
@kmcdo
@kmcdo 3 ай бұрын
@@benatmartinez1365 he’s using some Vim plugin in vscode I believe
@PeriMCS
@PeriMCS 3 ай бұрын
​@@benatmartinez1365entire video. Vim plugin in VS code. There is Vim plugin for every IDE. I can't type anything without it.
@kevinlloyd9507
@kevinlloyd9507 3 ай бұрын
How do you handle the argument that "You're duplicating data by storing the counts of reminders, when it can be derived from the data by querying the actual list of reminders. You should look to tune your database indexes instead."
@amantinband
@amantinband 3 ай бұрын
It all depends what you're optimizing for. Optimizing for database storage will lead to different decisions than optimizing for cost or performance
@ibrahimkoz1983
@ibrahimkoz1983 3 ай бұрын
I think this is not very accurate. First, you violate liskov substition rule. AddReminder should accept only required fields, not the whole object. There is an atomic invariant between these objects, if you were to merge them into one document, then you wouldn't need to rely on a transaction primitive. Also, data access patterns should be noted.
@fifty-plus
@fifty-plus 3 ай бұрын
I know that was just a trivial example but why have a public list of data on your record, that's also internal, and why not just use a check constraint so your application logic doesn't need to concern itself with transactional locking and concurrency? While the example was simple, I think it was too contrived to be realistically complex enough to illustrate a real scenario. I also wouldn't encourage using exceptions for control flow - it's not exceptional to consider the user has reached their daily threshold.
@amantinband
@amantinband 3 ай бұрын
Check out my videos on the topics you touched and you'll see I more than agree. This was just a trivial example to get the underlying idea across
@vivekkaushik9508
@vivekkaushik9508 4 ай бұрын
1st rule of programming - Never prematurely optimizer your code. 😅 I'll need another US for enhancement boss so that I can justify my man hours and charge you extra what could've been done in the first time only. 😂😂😂
@yardeZ93
@yardeZ93 3 ай бұрын
That's exactly what it told to my self when he asked about the problem with the initial code
REST API Design Best Practices
18:57
Amichai Mantinband
Рет қаралды 1,5 М.
Why Developers Are OBSESSED With Obsidian
11:26
Amichai Mantinband
Рет қаралды 29 М.
НЕОБЫЧНЫЙ ЛЕДЕНЕЦ
00:49
Sveta Sollar
Рет қаралды 8 МЛН
Зу-зу Күлпәш. Стоп. (1-бөлім)
52:33
ASTANATV Movie
Рет қаралды 1,1 МЛН
Don't eat centipede 🪱😂
00:19
Nadir Sailov
Рет қаралды 21 МЛН
Clean Architecture vs Domain-Driven Design (DDD) - Understand the Difference
11:26
5 Rules For DTOs
17:56
Ardalis
Рет қаралды 35 М.
Nextjs Abstractions & Common Mistakes
6:25
Ljupche Vasilev
Рет қаралды 323
Winglang in 10 minutes
11:39
Amichai Mantinband
Рет қаралды 9 М.
Stop Calling Your API a "REST API"
17:42
Amichai Mantinband
Рет қаралды 11 М.
Swagger is Going Away in .NET 9!
10:48
Nick Chapsas
Рет қаралды 64 М.
#NoEstimates (Allen Holub)
37:45
Allen Holub
Рет қаралды 226 М.
Understand Clean Architecture in 7 Minutes
7:02
Amichai Mantinband
Рет қаралды 74 М.
iPhone green Line Issue #iphone #greenlineissue #greenline #trending
0:10
Rk Electronics Servicing Center
Рет қаралды 4,4 МЛН
Обзор игрового компьютера Макса 2в1
23:34
Best Gun Stock for VR gaming. #vr #vrgaming  #glistco
0:15
Glistco
Рет қаралды 10 МЛН
Nokia 3310 versus Red Hot Ball
0:37
PressTube
Рет қаралды 1,3 МЛН
Готовый миниПК от Intel (но от китайцев)
36:25
Ремонтяш
Рет қаралды 426 М.