În our hearts, we all know that isPublished was just fine.
@billy65bob5 ай бұрын
I think I would've just made the Published Date nullable 🤣
@zoran-horvat5 ай бұрын
@@CrossbowBeta Let me modify that: We all keep dear memories of the days when isPublished was just fine.
@zo1dberg5 ай бұрын
@@zoran-horvatOk, somehow my comment got deleted, so here it is again. What you've done here was provide an over engineered solution to a simple problem. The flag is fine, and in fact it is probably reflected this way in the database anyway, so why make it different? If you prefer, you could make IsPublished read only and just return true when DateTime. Now is >= PublishedDate. Or, make PublishedDate nullable as suggested above, but nulls are bad these days, apparently.
@bobweiram63215 ай бұрын
@@billy65bob Null should be avoided whenever possible. Nullable is fake safety. It also adds to code bloat since it requires checking every time you access it.
@smathlax5 ай бұрын
@@bobweiram6321 Why is nullable fake safety?
@91DevilDriver914 ай бұрын
0.75x speed to listen to Uncle Iroh coding.
@lwazinkasawe38874 ай бұрын
class Winter { } class Spring { } class Summer { } class Fall { }
@jorgerangel23904 ай бұрын
Hahahaha
@kevinhougesen14734 ай бұрын
This is crazy 😂😂 I cannot unhear it.
@W0lfbaneShikaisc00l4 ай бұрын
Uncle I don't have time for your nonsense: I need to capture the Avatar! This entire method is just a simple link expression, Imagine another request coming to test whether two books have the same publication status! The method would test whether both are published or both not published. To cut a long story short: I would consider both these methods as an abuse of static methods. That is another trait of programmers, they believe that these static methods capabilities to the book class! (Zuko flips a Tea set tray and storms off) What's with him? I didn't even cover the part about counting books!
@theevilcottonball4 ай бұрын
I program in C. it's so funny that I don't have to worry about these choices :-)
@Davtd.4 ай бұрын
same here
@Jocke1554 ай бұрын
Same
@vedqiibyol4 ай бұрын
Same
@Davtd.4 ай бұрын
no time to waste by thinking 5 hours for a good oop concept
@martijnb33814 ай бұрын
I was about to mention "Just let the data be the data". So a struct will do 😊 It blows my mind why people want to be programmers these days, 80% of the time you are shuffling papers around not solving the actual problem, thats not fun to me.
@leptosurreal4604 ай бұрын
Sign you are truly a Senior Programmer: you appreciate simplicity.
@zoran-horvat4 ай бұрын
@@leptosurreal460 Only provided it satisfies the requirements. Many commenters who criticized the examples from the video fail to see that the "simple solution" they like - doesn't work.
@leptosurreal4604 ай бұрын
@@zoran-horvat Saying it doesn't work is unfair in my eyes, as there isn't enough context. If you are paid to make something work, then write it as simply as possible but keep it scalable and flexible. There is no need to spend hours overgeneralizing.
@zoran-horvat4 ай бұрын
@@leptosurreal460 This video is the test, not the explainer. Other videos on my channel go into substantial depth explaining each of these individual fallacies. Those videos combined are dozens of hours long, plus 80+ hours of my earlier courses. The sheer size of the field makes it impossible to do more than touch five topics in one video. Therefore, regarding this video in isolation, I would stay at its proposition: do you see why initial designs are bad and the second/third versions are good? The fallacy of many commenters is that they don't see the next step in using each of the initial, simple designs. They just don't work. You don't need requirements to see that. They will fail on the first requirement, whatever it is. It's your homework to see how.
@MaxLa104 ай бұрын
@@leptosurreal460simple but scalable and flexible. also write it as fast as possible but have it make as much money as you can. it'd be great if it were just that easy lol
@CjWork-ny5ox4 ай бұрын
Quantity does not equal quality@@zoran-horvat
@dimitriscollier99184 ай бұрын
While it feels natural to write OOP like this and I do agree on all of your points, you're presenting it in a way as if to say "If you don't do this you suck/if you do this you're not a junior" and neither of those are true. A junior developer isn't someone who doesn't understand how to model their classes. It's someone who is inexperienced and needs more guidance to complete their work and they often get assigned easier work to do. Because of this definition, the technical ability of a junior lies on a huge spectrum and there are even times where a junior can write beautiful code, but still be a junior. There are also plenty of seniors that can write terrible code, but they're still seniors deserving of their title. That's because good code doesn't necessarily imply seniority (i.e. it can but that's not always the case), it comes from continuously studying code and having enough time to write the code. Your coworkers will love you if they read your code and they can both understand and be able to modify it easily when requirements change, and you will love your past self if you made things easy for your current self reading your code. You don't get a title change because you now apply more theory into your code, or because you've stopped using static members when you don't need to. You get a title change when you become more independent and reliable to your team, so for the juniors reading this, that's probably what you should focus on. Good code will come naturally as you get more exposure to good code, with experience and as you study.
@zoran-horvat4 ай бұрын
My intention was exactly as I said it: do you see why the second form is better than the first one? It is not the question of style. In all five examples, the first form doesn't work. It can be the most beautiful piece of code - it doesn't work.
@dimitriscollier99184 ай бұрын
@@zoran-horvat We need to model 3 different states of publication and yeah you've shown the most natural approach to model this. But there are other approaches to this that are functional, but of suboptimal code quality. IsPublished like you said, is simply wrong and I'm not arguing against that. With IsPublished you end up with 4 possible states, one of which is impossible to reach, and you never model the planned state. You only get the planned state if you allow for a nullable date, but you end up with 2 states impossible to reach. However you could get all of the three states by using just one nullable date and compare it to the current one. If it's null, the book is not yet published, if the current date is less than the date we saved on that model the book is published, otherwise it's planned to be published. But I prefer your approach over a nullable date because your code is easier for me to read and it just feels better. What makes me happy to read however, is a matter of style.
@zoran-horvat4 ай бұрын
@@dimitriscollier9918 On the other hand, I do agree with your analysis of seniority.
@АртемБаляница4 ай бұрын
Good luck storing your books in a database with your hierarchies. Instead of having one property, you will end up having tons of classes and tons of type checks. Overengineering. Developers of any level, please, don't do that everywhere, just because someone from KZbin told you that if you don't, you are still a junior! Always think before making any abstractions. They are good, but not everywhere.
@zoran-horvat4 ай бұрын
@@АртемБаляница I've already got a dozen videos with this same domain model persisted using EF Care almost without effort. If you only learned how relational persistence works, you would save yourself writing one stupid comment.
@mariusgurau85 ай бұрын
It feels like sometime it's over designed and not easy to understand... Basically it makes your code unreadable.
@zoran-horvat5 ай бұрын
@@mariusgurau8 This was not about readability but about correctness. You can choose the form that looks readable to you, but which doesn't work. That doesn't make it a matter of choice, does it?
@kevinhougesen14734 ай бұрын
@@zoran-horvatYou can write readable code that works if you didn’t know.
@zoran-horvat4 ай бұрын
@@kevinhougesen1473 Which example from the video is that?
@Davtd.4 ай бұрын
@@zoran-horvat i prefer readability over constructing the look of code. usually i like to engineer a program not the src. most concepts here are way to specific and overthought. Also the resulting binary wont have any benefits at all and readability is also suffering? pls let me know what am i missing.
@zoran-horvat4 ай бұрын
@@Davtd. The hidden gem in all five examples in the video is that the first form exhibits one of the serious drawbacks: cannot implement a request; implements a request at the place where that code does not belong; contains a bug that could manifest later, when an unrelated request is implemented.
@yannisgoogleapps92495 ай бұрын
Sorry, I usually like your videos but there too much generalization in this one. Sure, in theory, most of this sounds good but getting better is also to know when to make exceptions that improve the system. Also, a non-LINQ four-liner is fine and should IMO pass a code review, that’s a nitpick.
@zoran-horvat5 ай бұрын
@@yannisgoogleapps9249 Fair enough.
@muonneutrino4 ай бұрын
I have to say that I never used LINQ. For me it looks so alien compared to imperative code and doesn’t contribute to readability. I’m 20+ years in the industry
@minma022625 ай бұрын
I can think all 5. Problem with 3, 4 and 5 depends on the language you use. Some language makes it easier than the other.
@drdrummie12 күн бұрын
Koliko god uživam gledati Vaša videa, toliko sam nakon njih isfrustriran činjenicom koliko zapravo - "ne znam".. Svaka čast, samo nastavite!
@cxarra4 ай бұрын
I feel like the true seniors are able to evaluate the ask for scoping and make decisions on many of these concepts. Perfect OOP is not always the most readable nor is it always worth the time. Also, the concept of “perfect OOP” is certainly lang dependent despite the many shared paradigms you typically encounter
@zoran-horvat4 ай бұрын
@@cxarra The tests in this video are far from seeking perfection. In all five cases, I have displayed design blunders, those that can pass with no damage only in the most trivial designs, where knowledge does not even make a difference. In any regular case, you need to know the difference.
@dmitryye47565 ай бұрын
And what are the drawbacks of just declaring public DateOnly? PublishingDate { get; init; } for instance? In my opinion, it does the job and not overengineered in our model when book has a unique publishing data in all country / project is country-specific Null value means it is not scheduled, Date in the future is scheduled, current and past date means it is published.
@zoran-horvat5 ай бұрын
@@dmitryye4756 The drawback is in the very next line of code, so please write it. I want to see how you use this property when the book is published. P.S. "Date in the future" is a very tricky category. Such sloppy constructions are reserved for junior programmers.
@focl20037 күн бұрын
@@zoran-horvat Thank you.
@oscarfriberg76615 ай бұрын
I’ve subscribed to these ideas for a while. The problem is to convince the rest of the team as well. I’m getting there. I’ve managed to show how a bit of restructuring can make the difference between “ugh this is going to require a huge refactor” and “this unexpected feature request is trivial to add”.
@zoran-horvat5 ай бұрын
@@oscarfriberg7661 That is exactly where these techniques are pointing to. It is difficult to see their good sides on a small example. But as the project grows larger, they all show great potentials.
@AstonJay5 ай бұрын
It feels like I'm being lectured by Dracula😅😂 (I do not mean to offend), imposing thousands of years of knowledge in a few minutes... Still learning to program, so not all of this makes sense yet.
@Dalamain4 ай бұрын
Thats what made me subscribe - there is darkness to this and it makes me want to be a better programmer 🤣🤣
@rafaelsaboia910Ай бұрын
The examples of modeling requirements that change are great; I love them. I enjoy every case presented.
@Diamcreeper4 ай бұрын
I feel like in a real world application the Book class would likely be ORM mapped or used for serialization/deserialization, and in that case I'd try to avoid any sort of polymorphism until I'm sure it is really needed. It's a pain to map that stuff to database and to figure out what types should be used when parsing. Immutability doesn't make sense in that case either, unless you are really sure you want a duplicate of the book in the DB. I'm assuming that the class was supposed to be used in a different way, but I'm struggling to think of an architecture where the Book as you describe it would make sense
@zoran-horvat4 ай бұрын
@@Diamcreeper Why would you sacrifice domain modeling for the sake of persistence and serialization? That only works in very small models, and certainly not on the central model of a significant business. For example, many programmers believe that the model should be serializable. But if you think carefully, there is no justification for that. The most important reason is that other systems will literally never ask for the exact model this system has. Why would they? If those systems needed the exact same models, they would be this system! You will likely need to serialize several different parts of the model, which immediately tells that serialization is the responsibility of other classes in the solution. Regarding persistence, you can certainly do it, at the expense of one class mixing both purposes - data modeling and domain rules. As the domain model grows large, the number of rules will grow quadratically. Why constrain them with the artificial requirements of a persistence library? At one point, you will have to choose which is more important to the business, and it will invariably be the model. That is where the money is.
@sVieira1514 ай бұрын
As someone who struggled to remember terminology i found myself worrying a lot at the start of each point, but as you explained each situation it made sense and reminded me a lot of the same thought processes i go through when designing solutions, and i always felt better at the end 😂
@programmingwithimran4 күн бұрын
Great Video, We always learn from Zoran! Test Number # 5 is simple Violation of the Liskov Substitution Principle (LSP)!
@tmjones2125 ай бұрын
Your videos have a way of simultaneously making me feel a lot dumber but get a lot smarter. It's really quite impressive.
@oglothenerd4 ай бұрын
This was not a very good video. You didn't set up the plot enough for it to be clear.
@zoran-horvat4 ай бұрын
@@oglothenerd This was "in your face" kind of a video.
@oglothenerd4 ай бұрын
@@zoran-horvat No... it was just kind of a "you are not a senior because you don't know what I am doing" kind of video. It was frankly confusing. I did understand what you were saying about composition over inheritance, and I 100% agree. But this video could've been set up a bit better.
@MrDavibu4 ай бұрын
I really don't get this problem, just make a const isPublished method that check if the publishing date was in the past. If you want a requirement for the publishing date, then solve it before the construction. If the publishing date is based on some other book data, it could be solved through a method like getNextValidPublishingDate(Date date). If the required data isn't inside the book class, the book class should either get the valid date or only have a interface for aquiring the date (but an interface would simply add an abstraction layer without any benefits, but you seem to like useless dependency injections). If the publishing date is not clear at creation of the book you could make the publishing date an optional, that could be set through a setter. If you want a publishing event simply filter the books with the date in question and you are good to go. Quite honestly this code at the end looks messy, just because of adding a "publishing event" without specifying what that is or why it need to exist.
@zoran-horvat4 ай бұрын
@@MrDavibu There must be the state in addition to operations, some of which cause altering the state, either mutable or immutably. The operations you listed are the consequence, and only constitute a lesser part of the model. So, the question in your largely incomplete design is: how is the state represebted, and where is the behavior implemented.
@MrDavibu4 ай бұрын
@@zoran-horvat The state would be derived from the publication date. In pseudoCode ( I don't know the C# syntax): // return if the book is already published bool isPublished(){ // if publicationDate is not set => treat as unpublished if(!publicationDate.hasValue()) return false // publication date is in the past return (time.now() > publicationDate.value()); } With this being derived, the published status will always be up to date. You could also use a tribool or another return type if you want a special case for books without a publication date.
@rodrigodanielvittoriali66295 ай бұрын
These are exactly the kind of talks I'd love to have with a TL. I'm currently teaching OOP (without industry experience, sadly only fl xp sp far) and this video humbled me on the vast amount of practice I still need to undergo. Thank you Zoran.
@germanoller44184 ай бұрын
I think this guy is right, its just that the idea was presented in a way that we all felt insulted and dumb. Good sir, may I ask where can I learn more about this? Aside from experience what book or resource would you recomend to learn more about this? Thank you.
@germanoller44184 ай бұрын
Also some of the problems metioned like "abusing static methods" are not what they seem. I feel that by saying abusing static methods you mean "violating single responability principle by filling entitiy with static methods" Why should the Book entity be responsible for counting books in a colletion? It is not the job of one book to count other books!
@zoran-horvat4 ай бұрын
@@germanoller4418 Other videos on my channel cover these topics in greater depth.
@focl20037 күн бұрын
@@germanoller4418 I agree.
@vonn97375 ай бұрын
I disagree with not writing methods for linq queries in SOME cases. For example, someone might write a LINQ query for checking published status which checks "type is Published" AND date
@cvbattum4 ай бұрын
There are some very good reasons to hide linq queries behind static methods. I wouldn't do it if it's a one-off thing you need to check, but if you run the query in several different places and it's important that each shows the same result at all times, I'd at least consider aliasing the query with a plain method, for the exact example you gave. Someone makes a change in one place, and none of the others, and now you've got a bug. The whole point of methods is that they are single points of failure and linqs with potentially variable predicates are not equivalent.
@drxyd4 ай бұрын
Might be worth benchmarking linq and reconsidering when and where it makes sense.
@zoran-horvat4 ай бұрын
@@drxyd Did you do it? I agree it makes sense, and I also did it - in a few other videos.
@martinrodriguez13294 ай бұрын
As an electronic programmer, all I'm seeing is hieroglyphics
@AMMIN135 ай бұрын
The simple, the better. (when it works, don't touch)
@zoran-horvat5 ай бұрын
@@AMMIN13 Simple yes, but never simpler than the problem it solves. That is the detail that escapes too many developers. Regarding the don't touch part - how do you implement changed or expanded requirements if you don't touch that which works? Both wisdoms you quoted turn into fallacies in the blink of an eye.
@SG_014 ай бұрын
I would like to note that structs in c# are not immutable, only readonly structs are. Though you cannot mutate a struct through a normal property reference, as that will create a temporary copy on which the mutation is performed.
@zoran-horvat4 ай бұрын
@@SG_01 That is a tricky question. You can only mutate the local instance of the struct or the one you obtain by reference without boxing. As soon as you obtain the copy of a struct, you are detached from the original instance which makes it immutable for you.
@SG_014 ай бұрын
It's actually a bit of a misconception that comes from the fact that properties are functions in that look like fields. You can change structs that are public fields no problem, or if the function / property returns a reference to the struct using the ref keywords. Otherwise, since they are value types they are copied in and out of functions and properties by value. If you make a property return a reference you also no longer need a setter to assign to it.
@asagiai49654 ай бұрын
One of the true signs of a senior programmer is knowing the Data they are working with. Once you know how to properly manage and use your data conveniently and efficiently. You'll become a senior. In game programming , we were taught about this concept of sword making. (Though technically, it can be any objects in the game) Like creating a single sword, or dual wielding sword, or elemental sword, etc etc. (Imagine you have more than 500 different types of swords with different attributes or properties) But the challenge is you have to make your classes etc. Simple, Convenient, Efficient, Easy to maintain, updatable, etc. If you conquered this challenge, you are either a senior or almost there.
@zoran-horvat4 ай бұрын
Makes sense.
@ryoukaip4 ай бұрын
As a college student, thanks for this video!
@claucirmaci22694 ай бұрын
I usually try to make some of the properties of a model class immutable, depending on the business you might need to mutate some information, to then send the updates to the database. A process that handles thousands of large objects in lists and batches might run quick out of memory if you are creating a new object for each mutation.
@zoran-horvat4 ай бұрын
@@claucirmaci2269 That is a fallacy. Do you believe that functional programs are less useful on a database? That is just false.
@Davtd.4 ай бұрын
first point i already disagree i see no problem or disadvantage by using a bool. I think both ways are different approaches but none of them is the approach you should use. Actually I think it be very likely to just use a bool instead of another class for simplicity also for people reading your code they get a faster overview over 1 class than 2. i think in this example provided i would definitely not use a extraclass for one flag.
@zoran-horvat4 ай бұрын
How can you not see a disadvantage when less than a minute later the request was to add the third state? Also, not explained in the video but I have no doubt you can see it: Where do you implement domain behavior? Not on the bool, I am sure. This video is the litmus test. If you don't see the reasons why the second version is better than the first one, then start paying attention to learning that. It doesn't help to deny the second form is better.
@Davtd.4 ай бұрын
@@zoran-horvat I think you didnt exactly get what i tried to say. What I meant is that the point to learn is to differentiate when to use the first case and when the second. A bool can sometimes be just enough and my example was that the second case might be a more complex implementation where you could fall back to a bool or just set a date to zero. I see advantage in the second usage but not in general. Its case specific what the implementation is used for to decide in my opinion. I hope this clears it up.
@okmarshall4 ай бұрын
@@Davtd. Good response. I usually like these videos but this misses the mark a bit. It's way too general. In that way it's exactly how some seniors behave, my way or the highway, but I know from experience that it's not as clear-cut as that.
@ghevisartor60055 ай бұрын
These are all good points, the number 4 especially in a recent project, i had a concept of Ranges with StartPosition and EndPosition. I've added instance methods for comparisons and operations like adding or subtracting returning new instances. Using these as the caller becomes so easy, also these small building blocks eventually will allow you to make more complex classes. I still make a mess sometimes on some other classes that gets bloated but it might depend by design choices elsewhere.
@22Epic4 ай бұрын
It's when you don't use C# anymore, easy.
@zoran-horvat4 ай бұрын
@@22Epic Yeah, the design issues magically disappear in other languages, so the bigot's wisdom goes I've heard.
@lobotomiepraktikant11284 ай бұрын
Although C# is not my mothertongue, I make a lot of sense of your video. Many concepts probably apply universally and to some there are explicit exceptions to the rules.
@razkuff5 ай бұрын
OMG, seems that after 7 years of using C# I am still a junior. I make all of the mistakes that you talked about in this video. I need to step my game up. Didn't knew I was so behind.
@zoran-horvat5 ай бұрын
@@razkuff Then let me tell you a secret. Many experienced programmers keep making these beginner mistakes all their life. It is because mainstream learning and the industry itself teaches them that this is the way to do programming. Then everybody cries about how messed their projects are, but nobody tells them to review the basic programming principles that were applied in development.
@razkuff5 ай бұрын
@@zoran-horvat I started to watch and digest your content last week. There's so much content on your youtube channel, and most of the time, for each video of 10-15 minutes, I have to spend atleast 2-3 hours on it, to understand and to try creating a scenario where I would use it in my job project. I already adopted some of the things I learned from your videos. Thank you, for your videos. Best regards from Romania.
@stupidhinoto5 ай бұрын
Don't worry man. I know all of this and I'm unemployed😂. Not even be to viewed as qualified for fresher or intern level. No CS degree and no coding interviews passed. I stopped finding dev jobs. 🎉
@gaby2323234 ай бұрын
@@zoran-horvatwell that is because the code reviewers just dont want to mess much with other's work , 60% of the work places i been , literally say "if it works don't. Touch . It. No. Thanks!"
@Esgarpen5 ай бұрын
Question(s) for all "seniors": What is your stance, when you need to implement a change-request / bug-fix / .. which has something like 30min-2h estimation, in a place where you when sitting down to do it realize 'bad code' is present. i.e., someone came up with a design but maybe not the most optimal. --Do you sit down and refactor / clean the 2.500 lines they wrote before you, or do you continue down your predecessors line of thought and add to the spaghetti? --If someone thought in one way you don't "agree with it", do you change the entire code-base or do you just implement the change needed and move on?
@zoran-horvat5 ай бұрын
@@Esgarpen There is the whole world in between the extremes you suggested to choose from.
@degrauxmaxence88715 ай бұрын
Well, i would say this : 1. Be consistent -> do the change in the same way that the code has been done. 2. Log somewhere (jira, trello, whatever you use) that this part of the code need a refactoring, explain why and the benefit that the team will. -> If the payer when to pay for the refact, there you go
@QueirozVini4 ай бұрын
This question is much trickier to answer than one would imagine. I believe Martin Fowler has a couple of articles on his website on this matter. In summary, you have to know how the project stands for your stakeholders at that point in time. For example, if the stakeholders are not yet convinced that your project is worth going on, if you say that you need to spend a couple months without implementing ANY new features, just to get the code on the right track back again, then this might scare your stakeholders, and they might even kill your project and fire everyone on the team in some cases. If your team is big enough so that features might be added in parallel to the rewriting/refactoring, or the project is consolidated enough financially-wise than it might be a good time for a rewrite of some parts of the code. You also have to decide of you are going to rewrite the most critical parts of the system, or the less critical ones. Anyways, that is NOT an easy task, and a bad decision can put everyone on the streets, so it should be deliberated as a team, not only as a Tech Lead, or as a single dev. I've worked on two separate projects that started for 1 or 2 years before I got into the project. The code and design were made by people with no knowledge at all of clean code, software engineering, clean architecture, etc. One of the projects was killed because of a bad timing of a code refactoring, that took over a month. The other project highly benefitted from the rewriting, because it had a better timing and planning, and the benefits were also not only in cleaniness, but also in performance (600x increase of performance, actually). So, unfortunately, there is no right or wrong answer for your question - you will only know if it was the right decision afterwards, when you retrospectively analyze the results of the rewrite/refactor.
@thebuffman55975 ай бұрын
1. Basically use interfaces and favor OOP 2. Visibility should help you program, public and private are your frenemies, but static is like the guy who handles everything, but forgets about it when you ask them how they did it. 3. again public private, just "thought out". (for gms2 users: if instance exists) 4. Understand allocation (pointers? barely recalling them from C++) 5. Making an object a constant is valid and nothing's wrong with it lol.
@mikicerise62504 ай бұрын
*if it's legit constant. Which experience is beginning to show me is less often than you'd think. 😛
@shikyokira30654 ай бұрын
I see static functions differently as bank clerks that handle things outsiders have no access. One great example is constructing an object with a private constructor
@jrs_devs3 ай бұрын
Basically, that PublicationInfo is kind of a simplification of the state pattern, right? We could add behaviour dependant on the publication state, and the book would delegate that responsibility to it.
@psychic88723 ай бұрын
I have seen the locator injections in a codebase. This will certainly help me understand their purpose. People here seem to miss the point. They have learned to use a hammer and try to claim that the hammer can solve all their problems even if other tools are more appropriate.
@vedqiibyol4 ай бұрын
I don't even use classes! Most of the time... Yeah anyways, some people would say we could use an optional wrapper around the date, or you can set up a null value for the date, like 9999-99-99, is not valid therefore it's planned. Or, if you think a bit further, you can just have any valid date, a check the saved date against the current date of the server or whatever it is the program is ran on. Now you can also know when the book will be published. As far as I'm concerned your solution has like, 10 times more boilerplate.
@zoran-horvat4 ай бұрын
@@vedqiibyol Who would implement domain behavior in those designs?
@vedqiibyol4 ай бұрын
@@zoran-horvat Okay so I've made some research about Domain-Behavior, I first noted that it's not widely recognized and so this makes the whole thing a bit harder to understand. But, to answer your question, I would not implement domain behavior, or anything, because I would rather not use OOP to start with, or at lesat limitedly. In a more general scenario, I guess that your product is an application or service that can provide the user books. Books are stored in libraries under collections, and sometimes under an author. I would rather use an approach like this, I would have two databases, a book database which would contain collections of book, which are just glorified lists, or maps, and an author database, which for each author would in this case hold a list of all their published books, as their keys, keys are unique, because of database design principles. Now I have a database that holds all the informations about the books I store, so I have a foundation. Say I am running a service on my server which checks for books, maybe I want to promote newly released book, so I'll add a third table which will store the key of each upcomming books. The client would ask the server for upcomming books and the server would return the entries of the database, and not the keys, in this case the server can even sort them for recommendation. And in this case, there isn't a lot going on, I just have as many tables for featuring things so that I have less disk reads, which is my primary concern since I'm working with a database. I may have a service, that would run every once in a while, that would query the database and in this case there is not much, all the service needs is, the table it needs to look in and something to compare things to. You can have any instance of the same service, basically. If we extend this to a system for a real life library, then I would also have a loaning system, in which case I would have have say, either another column in my tables to store each users borrowing X book, or a borrower tabler, either with the book key and the members key, because I will likely have many copies of the same book or a member key and its borrowed books. I don't believe that the latter is very useful, for the librarian it's better to have a clear view on his inventory than the people having the book, so to get the latter, there will have to be a query. And if there are no books with a certain key, I can still query the database for stuff like the title, the editor, where we obtained the books, so this also acts as a record. I don't think Behavior Domain has its place here, I don't think it has it's place anywhere, I mainly see it as unecessary boiler plate for what are essentially services and microservices. The thing that I think you are missing when you are asking me how I would implement X in Y, is that there are a lot of ways to do the same thing.
@zoran-horvat4 ай бұрын
@@vedqiibyol What do you mean you don't implement domain behavior? If you keep a piece of data, like a date, then where is the behavior on that date implemented? The date will certainly not implement it, so it must be some place else. Where is that?
@vedqiibyol4 ай бұрын
@@zoran-horvat Operator overloading, function overrides, casting, etc. You know that this is just putting very fancy and unrecognizable words on something that's very simple that is already quite a lot to take in, which is OOP, right? I'm not going to store a date object, I'm going to store a 64 bit integer with Unix time, a glorified struct, which a bunch of methods. Why? Well methods are not stored in the data itself, methods are prettier to read functions. Python is interesting in that reguard, you always pass the class self, because Python passes objects by reference and that's a good way to teach people. C++ is essentially hiding the first function parameter, of the method, Object* this, where Object is our object, our struct, or class. I believe that it should be a pass by reference but the guys who made the standard had other ideas xD. In C# and Java it's the same thing. In practice, it should look something like database read, getting the date and instanciating a new object with the date. Oh and, the implementation is going to be either in the standard library I'll be using or in my include directory in my project.
@zoran-horvat4 ай бұрын
@@vedqiibyol My point is much simpler than that, that's what I'm trying to drive you to. Simple types cannot do anything. Then, there are two places left: The structure that holds them, or the behavior that uses them (the caller). In the first case, that is the book object in this example. Before you blink, it grows to 1000 lines of code and becomes unmanageable. The second case is even worse, as the domain is implemented where it cannot be controlled - at the consuming end. It is an extremely simple error you find in procedural, object-oriented, and functional programming all around.
@damianradinoiu43145 ай бұрын
the most problematic to follow even for experienced devs is Test 5 in my opinion because you need to understand how to properly do a 'split' of the code literally
@dinch19915 ай бұрын
Top video as always,. I figured out i stuck at a certain level (i cant determine exactly if it was #3 or #2..) somehow... Well i think it's time to create private projects after official work to improve...
@seremptos4 ай бұрын
I would have made a IsPublished function that return true if the publishing date is today or before and false otherwise
@zoran-horvat4 ай бұрын
@@seremptos That is the point towards I am driving this story. A Boolean is an answer to a question, not the model. The model usually involves at least one additional field, and often more. Manipulating those fields in all the ways possible quickly becomes non-maintainable and full of bugs.
@nekil81295 ай бұрын
Question 5 is great and really gets you thinking about your language of choice in a deeper level. I generally prefer an immutable first approach for most cases, since I find it more readable, but making the conscious decision between either should definitely be an end goal for any dev. These things aren't religions to follow, just tools to use.
@zoran-horvat5 ай бұрын
@@nekil8129 Yes, that's why I was very careful about that statement. I had to mention that the developer should know when immutable design is effective as well.
@mcxMakerx4 ай бұрын
I don't really agree with making the Book class immutable here. With the idea that different countries have different publishing services, I think that calls for traits relating to the release of a book to be encapsulated within the PublishingService. Each book should be blind to when it was published, its state in the publishing process, etc. for the sake of simplicity. I think it's okay to have a mutable dictionary inside of the publishing service that returns an immutable/read only result so outside users can't modify the dictionary without using a publishing service's declared method to do so. Returning an immutable book in the example presented; however, seems wasteful especially if the date is a property on the book class. What if the book class also includes information such as a short biography by the author, the name of the author, the title, the index in the book's series, etc.? Better yet, using a property setter you can inform other entities interested in the book that the publishing date changed. To me, again, it makes more sense to have a different class representing publishing properties that a publishing service keeps track of. For the arguments about IsPublished, if the outsider looking in only cares about if the book was published or not, sure that flag works or a method returning a boolean. On the other hand, replacing that boolean with an enum state makes more sense for the subsequent examples.
@brotherzero3 ай бұрын
About number 2, in my company if I use chained linq expresions they tell me to change it to foreach statements in code review so it looks "cleaner" 🙄
@Norinot15 ай бұрын
This video is a big slap in the face, I do exactly this kind of stuff, I mean that I complicate thing, and now that I watch someone else do it, I feel stupid. The bell curve really is the following: isPublished -> Derive madness -> isPublished. Also I do feel like less is always better, we today tend to use a lot of code for a lot of simple things that we want to achieve, and I do feel like sometimes less is good, hell... most of the times less is better.
@zoran-horvat5 ай бұрын
The only mistake here is that you don't end up with a Boolean flag in the end. The greatest fallacy of people who claim they know simplicity is they propose solutions that are simpler than the problem. Didn't I demonstrate that bool cannot model the publishing status because there are three states in it? It came one line of code later.
@ScrotoTBaggins5 ай бұрын
@@zoran-horvat Exactly -- This is similar to how I find that people with limited exposure to advanced modeling concepts are quick to call something "overengineered".
@FXK234 ай бұрын
Wow, that abstract record type with three record impl's is very nice. Looks pretty much like the data type in haskell (disc. union?)
@zoran-horvat4 ай бұрын
@@FXK23 Yes, that is exactly the intended use. C# is probably going to get discriminated unions soon, similar to what proper functional languages have.
@AngelEduardoLopezZambrano4 ай бұрын
OOP is so powerful, but having to worry about all these little details makes me think we took it too far
@zoran-horvat4 ай бұрын
@@AngelEduardoLopezZambrano You have to think about those in FP, too.
@leos-clockworks3355 ай бұрын
As I am a Unity developer, a lot of the more proper C# pattern just don't fit well with how Unity handles things, which is a shame. I love passing records as DTOs, great for storing immutable data, send it somewhere and get it done, but Unity doesn't know how to serialize records so some won't want to use it. Also, abstracting is always so much fun, there is nothing like seeing good abstraction paying off, like when I get a feature request to just add a completely new user that does everything differently, but what is this? I just implement the interface, and it just works with all the systems? Just the best feeling. My company works heavily with 3D maps and last week our map provider shut down without notice, good thing a year ago I abstracted out our map provider and took us 2 days to implement a new map provider. Knowing how to use DI, abstraction, and good code design and structure is just so very satisfying. Your videos are a great source for learning, it's great to see some quality C# content!
@zoran-horvat5 ай бұрын
I rarely hear that someone has managed to interoperate with Unity without playing by its (not so nice) book entirely. Glad to hear about your achievement.
@leos-clockworks3355 ай бұрын
@@zoran-horvat It is indeed not simple, as Unity really forces you to write bad code. If it interests you: What I usually do is I split the project into 3 assemblies, Core, Infrastructure and App. I try and maintain Core as a pure abstraction of the system, Infrastructure the implantation using Unity's systems and App is pretty much all UI. Like this, the project is more flexible and as long as you keep the boundaries, it's pretty easy to implement a new solution. Of course at the end it really depends on the project and each one has its own use cases and requires a different approach, but as a base this helps mitigate Unity's bad habits.
@jmbrjmbr0005 ай бұрын
Thank you so much for this video. I have been in this company and we don't use object oriented programming at all. We have thousands of lines of code in one method. Actually I found you from jetbrains channel, you were refactoring a thousand line method XD I'm going to lose my mind here, I only learn good things from videos like this :( thank you
@neonmidnight62644 ай бұрын
I'm usually of poor opinion on all kinds of youtube lessons but wow this is very clear and highlights terseness of newer C# versions, and is pleasant to listen to. Now, if only we already had type unions to avoid having to model them with records heh
@zoran-horvat4 ай бұрын
@@neonmidnight6264 It seems like discriminated unions are on their way at last. That will save us from working around them in C#.
@MixturaLifeАй бұрын
I would say, the service locator in the example could be called factory, the it’s not scary anymore)
@zoran-horvatАй бұрын
@@MixturaLife You can call it a chandelier, too, but if it looks up and locates services then it is a service locator.
@technovikingnik5 ай бұрын
Mr Horvat thanks for valuable lesson.
@xwize4 ай бұрын
As a C++ dev I feel like a biker being condescended at by a bicyclist
@zoran-horvat4 ай бұрын
@@xwize Do you develop line of business applications in C++ and why not?
@DavidSmith-ef4eh5 ай бұрын
Immutability was a real big issue for me when I started programming at first. I didn't get it and it caused a lot of bugs. But once you burn yourself several times, you learn to deal with. Now, I could still see it being an issue for people starting out. But not a big fan of oversimplifying things, tbh, just for the sake to be able to hire cheaper developers.
@zoran-horvat5 ай бұрын
@@DavidSmith-ef4eh Immutable design is one of the hardest things in programming. However, with all the infrastructure offered by C# and the runtime, it is often straightforward and surprisingly efficient. My designs today are typically immutable at the outset and I don't remember having a performance or other issues because of that.
@DavidSmith-ef4eh5 ай бұрын
@@zoran-horvat I can see it being beneficial in multi thread environments to prevent bugs. But even then, you rarely want 2 threads operating on the same data at the same time. From my experience, the frontend frameworks like react, opened a lot of doors to new programmers after switching from OOP to some sort of functional approach. And nowadays we have to struggle with bootcamp programmers, who can use react effectively, but don't adhere to any other programming principle. Don't have too much experience regarding FP and OOP on the backend, besides some friends telling me that they had to switch back from languages like SCALA because they can't find people who are efficient at it. Basically two contradicting viewponts, it seems easier and harder at the same time. I am open to learning anything dotnet team adopts form other FP languages. If they add it to the core language features, it must have some merit, even if I can't see it right away.
@olivetom15994 ай бұрын
I don't like specific implementation at 6:20. "HasSamePublicationStatusAs" will return true when publication is "Planned" or "NotPublishedYet" But yeah, got the idea.
@zoran-horvat4 ай бұрын
@@olivetom1599 There is nothing to like - it is the requirement. Whenever in doubt, ask the customer and write it down as a requirement.
@vbachris5 ай бұрын
as much of a Zorat fan i am, can you imagine the persistence nightmare involved in this approach?
@zoran-horvat5 ай бұрын
@@vbachris That is an overstatement. Trust me.
@krccmsitp28845 ай бұрын
You still work a lot with generic repositories, right?
@VanDameDev5 ай бұрын
Agree with the nightmare part, especially when people insist on collating Domain models with Persistence models :)
@okmarshall4 ай бұрын
@@zoran-horvat Could you go into a little more detail why that's an overstatement please? I had the same thoughts as @vbachris whilst watching this. All seems fine until you need to persist these books somewhere.
@carlogustavovalenzuelazepe57744 ай бұрын
I know this is wrong but sometimes I write the code in a KISS way and the i write the hard to understand few lines solution commented and ask a senior to evualuate it, most of the time.they keep the simple solution just because maintenance
@zoran-horvat4 ай бұрын
@@carlogustavovalenzuelazepe5774 But I have shown five situations where simple solution cannot be maintained. The question was: do you see how?
@99svd265 ай бұрын
I would like to see how to store these hierarchies in database. Btw great video!
@zoran-horvat5 ай бұрын
@@99svd26 Persistence and serialization are a separate concern when the model is taken as the most important concern. You can approach that problem from different angles. For example, the choice of the database affects possible solutions much more than the model itself.
@antonzhernosek55525 ай бұрын
@@zoran-horvat I'm genuinely curious how you would approach the storage of the first example in a relational database. Would you have one generic book table and use additional columns for all possible implementations of PublishingInfo? Would you have a dedicated table for every PublishingInfo variant with some elaborate key? What would be the advantages/disadvantages of implementing either as a solution? Is there some other better solution that I'm too junior to see?
@zoran-horvat5 ай бұрын
@@antonzhernosek5552 In small cases (and virtually all such cases in my projects are small) I prefer table per hierarchy storage. All PublishingInfo instances would end up in one table with a discriminator column. If you can compose an object out of a number of smaller objects, like Book is at the end of the demo, then EF Core would support it out of the box. Even a manual implementation via Dapper would be straightforward. Things become more interesting with a truly complex domain. That would put EF Core to a real test. At some point, you would have to give up maintaining one model and pull out a separate persistence model. The breaking point is typically when many-to-many relationships become prominent, which happens pretty early in any large project. I just don't like many-to-many inside domain models and that naturally leads me to overriding EF Core mappings.
@antonzhernosek55525 ай бұрын
@@zoran-horvat Thank you for the answer!
@SrIgort4 ай бұрын
0:50 I would probably have solved this by checking if the publication date is in the future instead of the past 😅, but I guess this isn't ideal too
@zoran-horvat4 ай бұрын
@@SrIgort Worse. It is wrong! :)
@elraito5 ай бұрын
I have metaphorically shot myself in the foot with extremely similar solution as shown the first bad version. First it was boolean but then the boolean needed to be calculated based on other data sequence and had to refactor my code. Sort of like if you had BookIsBorowedOutToSomebody boolean at first and then you have to calculate the result later by iterating through wheter book was lent out, returned, lent out returned, went to restoration because its old book, returned to library to be rented out again etc.
@zoran-horvat5 ай бұрын
@@elraito Exactly. Booleans serve the purpose perfectly so long as it is a true/false, orange/apple, cat/dog problem. The problem is that almost none of the problems we solve is true/false or cat/dog. They may be so for a limited period of time, until the third and the fourth option are discovered. The more code depended on the boolean model at that time, the greater refactoring work it will be to advance to the next stage.
@gaby2323234 ай бұрын
In C++ this wouldn't be much of a problem but it would allocate memory use up resource if not properly inspected. Long live mutex.
@kokito-kokoa4 ай бұрын
If you need to handle publised and unpublised books why not just add a property on the Book class called "publicationDate" which is a date, if the day has not happen the book was not publised yet, if the date already happened then the book is published? (It is a real question)
@zoran-horvat4 ай бұрын
@@kokito-kokoa The day could pass without the publishing actually happening. Also, the planned date should be editable, but actual publication date not. The date is not enough.
@dxs19715 ай бұрын
well, we can go like this... is Book a book when it is not published yet? If the answer is no, then you can have a Manuscript model with a date of CreatedAt, ModifiedAt and so on. Only when the Manuscript is published, it become a book PublishedDate can be null, or iPublishedDate can be an interface, and then we can have NoPublishedDateYet class or something similar.
@zoran-horvat5 ай бұрын
@@dxs1971 It's not the manuscript but a prepared book. I agree that there will surely be room for the manuscript model in a publishing business. I have taken part in publishing of a few books before and you would be surprised to learn how long before the actual publication day a proper book appears in the process.
@dxs19715 ай бұрын
@@zoran-horvat Hvala, kolega, moze puno da se nauci od vas
@asagiai49654 ай бұрын
A book, is still a book even if it is not published. Wdyem?
@zoran-horvat4 ай бұрын
@@asagiai4965 Let me rephrase: A book object represents a book even in its pre-published state.
@asagiai49654 ай бұрын
@zoran-horvat sorry ah, the comment was intended for the op of the post. Because for some reason he thinks that if a book is not published it is Manuscript. Which makes it confusing. Because a book is a book even if you have not published it yet. It is not a manuscript. Sure, it can have a manuscript, but they are different objects.
@ParkourGrip4 ай бұрын
Im not a C# dev. But isnt all of this overcomplicated oop modeling nessecary just because C# does not have tagged unions. Publication is just s tagged union that is composed inside of the Book struct. Thats it.
@zoran-horvat4 ай бұрын
But I did implement it as a tagged union, didn't I?
@ivandrofly5 ай бұрын
Thank you :)
@palapapa02014 ай бұрын
5:16 You are checking if the true type of an object is a derived class. Isn't that also bad practice? You are coupling all the derived classes to the base class, which means they shouldn't have been separate classes in the first place?
@zoran-horvat4 ай бұрын
@@palapapa0201 I am using a type-test-and-set functional pattern, not a type check in object-oriented sense. That object a record.
@palapapa02014 ай бұрын
@@zoran-horvat So what you are saying is that it's OK to use inheritance to make invalid states irrepresentable?
@zoran-horvat4 ай бұрын
@@palapapa0201 That's not what I am saying. I have used records in the implementation. When discriminated unions are added to C#, I will use them. Inheritance is but a technical implementation in the language.
@dampfwatze4 ай бұрын
The title should end in "in Microsofts Opinion". Because real senior devs know about other (and in my opinion better) environments and paradigms too. What really makes a senior dev a senior dev is his/her wide experience across many different approaches and solutions to a problem. I think this Video falls way to deep into the rabbit hole of C# for this title. You can't generalize C# specific considerations, for example if something lands on the stack or heap in C#, because someone manly using Typescript for example, really does not care! And C++ works completely different anyways! But this shows that C# is just too convoluted with language features no one cares about, when you just want something to work.
@zoran-horvat4 ай бұрын
@@dampfwatze Fun fact: Everything said in this video applies to assembler, too.. "Blame it on C#" tells how little you understand C#. What else have you failed to know with that attitude?
@MynecraftCZ4 ай бұрын
@@zoran-horvat Yeah, dependency injection in assembler is my favourite design...
@zoran-horvat4 ай бұрын
@@MynecraftCZ Cynical but shallow. Do you code in assembler?
@MynecraftCZ4 ай бұрын
@@zoran-horvat sometimes
@pavloburyanov58424 ай бұрын
First case: published: date today
@zoran-horvat4 ай бұрын
@@pavloburyanov5842 Nope. You missed a few possibilities.
@harisimer4 ай бұрын
On the first task I dont understand the requirement in context of your discussion. Lets say PlannedBook has PlannedPublishingDate = 01.01.1999. How can it be a PlannedBook? It is clearly published because we have 2024
@zoran-horvat4 ай бұрын
@@harisimer It could have been planned on the date in the past but never published.
@xijnin4 ай бұрын
Using inheritance is always a skill issue for me :v
@MasterQuestMaster4 ай бұрын
Me who would just make the Publishing Date a Nullable: 😅 Edit: I guess it doesn’t work well with planned books. Also I found out that Records exist thanks to this video, so thanks for that.
@zoran-horvat4 ай бұрын
@@MasterQuestMaster Fine. And how would you implement behavior?
@johanrojassoderman55904 ай бұрын
In the first example it feels better to create two separate hashmaps "published" and "planned" and use the location of the book as indication. Creating multiple child classes seems to add horrifying complexity for the information equality of 1 bit. Edit: it quickly went from poor towards satisfying and quickly turned around to end up at quite messy 😂
@zoran-horvat4 ай бұрын
@@johanrojassoderman5590 It's not one bit of information. Didn't I have to model three distinct concepts, each with a different state representation? The question of publishing a book lies far beyond a frivolous yes/no question. I thought I made that clear in the video.
@johanrojassoderman55904 ай бұрын
@@zoran-horvat yeah, I commented somewhat prematurely at the 2nd stage. The rest of the steps would still have greatly benefitted from keeping the books in separate containers though. Then you don't have to loop through the container to get the planned ones for starters. The publish date logic itself would not have been made any easier by it though.
@zoran-horvat4 ай бұрын
@@johanrojassoderman5590 How do you separate books into containers when the question is "published by certain date" instead of just "published"?
@johanrojassoderman55904 ай бұрын
@@zoran-horvat well, you'd still have to look through the containers, but at least you'd only have to look through one of them (only really beneficial if you look at future releases though).
@zoran-horvat4 ай бұрын
@@johanrojassoderman5590 There would be more containers than books. Why don't you just ditch that artificial idea and work the model out normally?
@gizmoomail5 ай бұрын
it is nice, but could you please show how to store that in a database and work with it using EF core?
@zoran-horvat5 ай бұрын
That is a long story. That story begins with the question: Which is more important in the component/project you are developing: The domain model or the persistence model. Both answers are valid, in their own time. Whichever you choose, the other one will bend to adapt, often with sacrifices. Therefore, if your aim is to develop a deep domain model, then persisting it with EF may range from using as much EF can offer, to the extreme of dropping EF altogether. All options are valid, and each has the time when it is the best option possible.
@iankirkpatrick20224 ай бұрын
Personally, I tend to simplify the model in the database. I often have multiple models in the domain stored together in the same row. So like all the publishing data might (depending on complexity) go in the book table. It limits the amount of joins I need and makes queries simpler. Of course it also means data migrations if relationships change but I factor that in when deciding when to split tables (how likely is it that this will become a 1 to many)
@iankirkpatrick20224 ай бұрын
I even go so far as to duplicate data sometimes for performance (again , less joins cause I'm basically caching properties of other tables). I'm careful about it but I've never had serious issues with it to make me rethink it.
@zoran-horvat4 ай бұрын
@@iankirkpatrick2022 I can relate to what you are saying. I plan to show in a future video how that can be accomplished with this model and using EF Core. It is funny that EF Core now supports all these seemingly extravagant little models I used - none of them would cause the creation of a new table, and yet they would all be individual objects in the in-memory model.
@iankirkpatrick20224 ай бұрын
@@zoran-horvat Oh I have always just loaded in and translated manually... I didn't realize ef Core had built in support for that. I'm curious so I'm looking forward to your video about that. In the meantime, I have some investigating to do I suppose.
@markusfassbinder82754 ай бұрын
oh this is OOP. I'm still stuck in procedural. well, at least I have fun programming in assembly for outdated systems ^w^
@nangld5 ай бұрын
Sweetie, you first plan a database and only them write the code to process it. If you follow the normalization rules, you will endup with proper code. Nowadays people use columnar structures, instead of classes. Like in ECS. You're converting a usual object into a component object, that is okayis for very small projects, but wont scale and get out of hand on something more complex than a Tetris game.
@zoran-horvat5 ай бұрын
@@nangld Sweetie, your mind is fixated to one design method which is largely deprecated for almost 20 years back. Figure why.
5 ай бұрын
3:24 Why default for Publication property is new NotPublishedYet(), not NotPublishedYet.Instance?
@zoran-horvat5 ай бұрын
I didn't implement that record as a singleton. That would be a premature decision because it is not clear that it will not attain some components later. Someone might incautiously depend on the singleton promise, making the upcoming refactoring a nightmare. I generally keep away from decisions that are hard to revert.
5 ай бұрын
@@zoran-horvat Using "premature" word makes you a great consultant, I liked it.
@zoran-horvat5 ай бұрын
I could get away without it, too. The whole truth is that I have built habits that protect me from concluding too much upfront. If it is the cost of creating one side object per book object, then I know I can survive that. Hence, that question never gets my active attention. And since it is highly unlikely that that precise detail, creating a few superfluous objects, will ever get to the radar during some performance optimization, my bet is that that record would remain as it is forever.
@parlor31155 ай бұрын
Also as a senior dev, I would never have more than one declaration in a single file like you're doing here
@zoran-horvat5 ай бұрын
@@parlor3115 Don't be silly, this is the demonstration.
@parlor31155 ай бұрын
@@zoran-horvatNot an excuse. Plus it made the video more difficult to keep track of
@zoran-horvat5 ай бұрын
@@parlor3115 I guess switching between three-lines-long files every 15 seconds makes it more readable than when all relevant core is on the screen? Yeah, there are channels that do that. But don't worry. They will learn.
@okmarshall4 ай бұрын
@@zoran-horvat Don't be so absolutist man, it's not a good look. I agree with OP, this is harder to follow because no-one writes prod code like that. We're used to new lines, curly braces etc, so it would be way clearer for you to follow good programming guidelines as well. It's longer but quicker to read, because we're used to it...
@mohammadtoficmohammad35944 ай бұрын
Thank you
@zoran-horvat4 ай бұрын
@@mohammadtoficmohammad3594 Any time!
@metallixbrother5 ай бұрын
I was a little confused about the example about class derivation. I will admit that I did something similar recently (although I was under the gun on a project). When is that sort of derivation (either via an abstract base class or an interface) inappropriate?
@zoran-horvat5 ай бұрын
@@metallixbrother The first variant, in which a derived class modifies its base, is plain wrong. It can cause a failure in design in so many ways that it doesn't make much sense to consider it. The second case is a typical method of implementing an abstract base followed by derived classes. It rarely causes troubles if that is the only level of derivation. Multiple levels of derivation quickly start to show catastrofic drawbacks. On the other hand, if there are other components in the base class that are not related to the criterion that caused derivation, it makes more sense to turn derivation into composition.
@metallixbrother5 ай бұрын
@@zoran-horvat thank you, that's definitely helped my understanding.
@mohnedahmed25054 ай бұрын
What if I am not working with OOP, That means I will be junior forever. 🤔
@zoran-horvat4 ай бұрын
@@mohnedahmed2505 No. All these examples map 1:1 to functional programming, too, as well as to procedural, with no modification other than syntactic. Telling how - that would put your understanding of your favorite style to a test.
@mohnedahmed25054 ай бұрын
@@zoran-horvat Okay, Got it. 👍
@marceorigoni66145 ай бұрын
Well on 4th about not using static methods basically lol... I mean of course just to iterate over a list, which some languages also have functions for it. Is kind of useless. But the predicate, probably should be on the class. Like, you dont want to modify the preidcate If there is any changes. Also wonder what the people that think you should not ask about class types and/or do ifs.... are thinking.
@zoran-horvat5 ай бұрын
Is this automatic translation to English? I can't understand the meaning of a single sentence here.
@JayMaverick4 ай бұрын
I'm so junior I have no idea what he's talking about.
@rauberhotzenplotz77225 ай бұрын
My general rule: classes should be either abstract or sealed, nothing between.
@zoran-horvat5 ай бұрын
@@rauberhotzenplotz7722 My guess is that you also have a rule when it is not so. That is how silver bullets work. They don't.
@pl4gueis5 ай бұрын
While I like the Videos I feel like sometimes I can't follow the unspoken train of thought. I can't read your mind especially if you assume we have the same Domain Knowledge while in reality we don't. For example the caller2 with the comment // TODO Feel free to implement this comment. I have no idea what you had in mind for that part. Sometimes it would be nice if you would go into more depth. For instance saying class inheritance is bad and then immeditialy defining records with inheritance. I know the difference but a video thats somewhat adressed to juniors is too shallow in some regards.
@zoran-horvat5 ай бұрын
@@pl4gueis All three callers do the same thing, but each does that using only the arguments it has. That was my intention. The entire domain model is that one method - Schedule. I understand your concerns, but KZbin is like that. If I just stopped every time I needed to take new breath, 30% of viewers would leave within two minutes. Additional explanations cut views to a half... I do make them, honestly, but then cut them out during video production. My channel would die if I didn't.
@pl4gueis5 ай бұрын
@@zoran-horvat Thanks for clarifying the caller topic. That part about the viewers is interesting insight I didn't have and really sad. I wish people would appreciate work more and have the drive to learn things more deeply but then again I know a lot of software engineers that don't even read a single book a year :(
@parlor31155 ай бұрын
Your keyboard glows when you write code and it's not rgb lit
@zoran-horvat5 ай бұрын
It's the fingers :)
@jm68495 ай бұрын
When would you ever use enumeration? It seems to me that the PublicationInfo class would potentially be a good enum but then you wouldn't have properties. It seems that enums would potentially run into the same problem you describe with isPublished (in that it's not really future proof). Should you always use classes/records instead of enums?
@zoran-horvat5 ай бұрын
@@jm6849 Both bool and enum share the same deficiency: they don't do anything. Whatever there is to do with them, it is likely that someone will do it on the calling end, which quickly grows into an entanglement that is impossible to maintain, let alone that it will surely be swarming with duplicate code. It is for this reason that we normally avoid modeling state with discrete classes, such as bool or enum, and use proper interfaces and classes very early in the design.
@MunyuShizumi4 ай бұрын
I feel this video is critically missing a real problem to solve and is instead shuffling paradigms around for the sake of pointless discussion. There is no inherent reason for IsPublished to be considered a bad or "junior" practice. Depending on what the end goal is, it might easily be the most straightforward solution without any downsides. We don't know what the service or class is actually supposed to do, so an argument can be made in either direction. The Book class is then "improved" through inheritance, to which I can just say "You also planning to derive your derived classes 7 levels down for every additional trait we add to this struct?". But wait, subverted expectations: what was labeled as an "improvement" at 2:16 is entirely discarded a minute later and we're back to our non-abstract Book class. So why even label derived classes as a better solution with the whole "If you understand the brilliance of this approach..." mantra? This is like saying that knowing recursion is a Mark of an Experienced Programmer™, only to label everyone using recursion a junior cause of stack overflow (pun not intended, but I'll take it). If you're just trying to demonstrate what a concept is for absolute beginners, you can use an abstract example. But if you're trying to demonstrate why, when, and how it's better, you need to focus on a real problem and show how it's better solved with a different approach, not just authoritatively state "If you were a senior, you'd agree". I could also say that not being stuck in OOP hell is a senior move.
@zoran-horvat4 ай бұрын
@@MunyuShizumi The video does not call derived classes a better option. It identifies object composition as a better option.
@F.M6714 ай бұрын
Plot twist - You get assigned to an unmaintained and unmaintainable codebase with no documentation and write code so it "just works" waiting for your next paycheck and year to pass so you can get a new position. I kid. This probably is a good video but a lot of people miss the fact that you don't need to be a "good" programmer. You need to be the person the company seems to think they need at the time.
@poleve54094 ай бұрын
some of these I don't think are possible in C or C++ lol
@zoran-horvat4 ай бұрын
@@poleve5409 Except immutability, which requires garbage collection, everything else applies. What is the lol part?
@weluvmusiczАй бұрын
Creating millions and millions of object copies because oneself is a immutable fetish is no good coding either. RAM has limits and garbage collection is costly!
@zoran-horvatАй бұрын
@@weluvmusicz Check your facts.
@lenickramone5 ай бұрын
Do you have some course with this content? I'm interested
@zoran-horvat5 ай бұрын
@@lenickramone There is a bit less advanced one on Udemy, called Beginning OOP with C#. There is the link in the description.
@lenickramone5 ай бұрын
@@zoran-horvat thank you so much
@Buutyful5 ай бұрын
hi zhoran, thx for the video, i have a question, how does object composition maps to a sql db?
@zoran-horvat5 ай бұрын
@@Buutyful Persistence and serialization is a separate concern. In any complex domain, domain modeling is the most expensive part. Then you adapt other concerns to what you have. The relational concept that is the direct correspondent to child objects is child tables. Sometimes they exhibit 1-1 relationship making it possible to only use one table. On another day, you might decide to develop a separate persistence model. But again, you design persistence to support the domain model you have. That is the order of priorities.
@Folsets5 ай бұрын
@@zoran-horvat Hi, I would like to see an example on how to adapt complex domain model into persistence model/models
@zoran-horvat5 ай бұрын
@@Folsets I plan a few videos on that theme, but I don't have the schedule for them, yet.
@henriquedelben4 ай бұрын
Okay, now I know I’m not even a junior
@LordErnie5 ай бұрын
Great video, opinionated but great non the less. I disagree with you on 4:50 where you talk about abuse of static members. I think that counting and compairing stsatusses could be static when we look at the concept of hiding the implementation behind abstraction. What if during the counting something should be ignored due to a business rule? What if checking the publication status has certain factors or rules that change the outcome? Instead of having those checks everywhere in your code, you could just define the counting in a method and use that method instead. If the rules or logic ever change, it won't be spread all over your codebase. LINQ is nice, but even LINQ queries can be encaptulated. This abstracts away the how, and only exposes the what. Another simple solution that I have seen you use before is introducing a custom book collection that gives its own implementation of counting published works. But statics are not bad in this case. It just depends on how big the code base is going to get. Extension methods for an IQueryable could work to.
@zoran-horvat5 ай бұрын
@@LordErnie What you have described looks more to me like a static method on a separate class, not on the model class.
@MasterSergius5 ай бұрын
When we're making db model (especially with frameworks) and there is a column "published", then I guess you'll see "isPublished" :)
@zoran-horvat5 ай бұрын
@@MasterSergius Yes, but what if it has more than two states?
@MasterSergius5 ай бұрын
@@zoran-horvat then model should be redesigned, maybe some Enum or something like that
@zoran-horvat5 ай бұрын
@@MasterSergius What is the difference between an enum and a bool?
@MasterSergius5 ай бұрын
@@zoran-horvat you can represent more than 2 states, no?
@zoran-horvat5 ай бұрын
@@MasterSergius "Represent" is not the best choice of a word in domain modeling. We do not represent the state, but rather implement behavior. So, what is the difference between enum and bool in a method that depends on the fact that it is having one value or another?
@Tracing00294 ай бұрын
You could have just made the publication date nullable tho?
@zoran-horvat4 ай бұрын
@@Tracing0029 The error is in "just". Did you forget the consuming code?
@Tracing00294 ай бұрын
@@zoran-horvat maybe, I commented on this at the beginning. If there are only 2 states (published and unpublished) that would be a valid and good solution. In a relational database you would mark it as nullable unless you had a table with a connection to the Book table to represent other states. For a minimal solution it is perfectly ok.
@zoran-horvat4 ай бұрын
@@Tracing0029 It's not about state, but state and behavior. You cannot ignore the implementation and only model the state - that is what storage does. In that light, it could be perfectly sufficient to persist the model using a nullable date field. That depends on other things. But it is perfectly insufficient to do so in a domain model.
@Tracing00294 ай бұрын
@@zoran-horvat Thanks for clarifying!
@the_mister_magister5 ай бұрын
I'm just watching this to boost my ego and confirm that indeed i'm mid to senior dev lmao