One thing I really appreciate about your videos is that you speak clearly enough for RUclips's auto-generated captions to work accurately. Great information, thank you for the video!
Hey Tim, I was approached by a company for a senior position for the first time in my life, and the tech interview is tomorrow. I'm just going over the SOLID principles again and realized I never truly understood any of them. I'll probably get obliterated tomorrow, but still thanks a lot for this explanation! We use similar approaches in our current codebase, but now I'm able to at least put a name to the face of this principle.
Like Kaushik S, said you're the best when it comes to presentations. You always assume your audience may not know much or anything about the topic, so you go in details along the way. That's a wonderful approach. Thanks!
Loved this video, I have watched many videos and read many more articles on SOLID and C# and I haven't found an explanation that is as clear and concise as this one.
I really like these videos. I particularly appreciate the fact you show the actual implementation by showing/writing the code in a way that isn't overly abstract and simplified. Thanks a lot!
Thank you. You make sure to explain the reason behind every decision, and all the other details. I watch some a number of times, and am so glad to be learning C# and watching the contents of this channel.
Hi Tim! Thanks for a good video! Just wanted to comment - that while I do think you're explaining the concept of the open / closed principle good with your example. I also think it shows as why you should be cautious about implementing this principle in the real world. I consider the amount of complexity added to the application a worser tradeoff than a bug or two in the long term. The bugs can be easily fixed when identified while the added complexity might be there forever :)
Hi Tim, this specific example made things a bit muddy for me but I still liked the video because I believe I got the message you were trying to communicate through. A great example I came across of OCP is when we were working with certain libraries or assets and essentially in order to expand what the library offers we can simply use an interface they already used in advance. If I'm not mistaken we used this principal on a node based slide system that lets you add new slides without modifying the original library but simply using its ISlide interface. That way you have a new slide node you can employ in the graph as it easily fits the entire system and other slides are not affected since nothing core changes. If it ever comes to it I would love it if you showed us real life scenarios from work you do or you've done that use OCP. Thank you for the videos and greetings from the Netherlands!
These are things my degree has never taught me. Practical Software Engineering. Thank you for your videos. This is what separates juniors from more experienced programmers and you are helping me with that step! I'm applying these to code in my current job
Great execution Tim, thank you! I've definitely been violating the O/C principle for a while now, but not anymore. I'm seeing more of why interfaces are a godsend.
Software entites( classes, modules, functions, etc.) should be OPEN FOR EXTENSION, but CLOSED FOR MODIFICATION. With the Open Closed Principle, the code is more robust and more future proof. I understood it all! Thank you Tim!
Thank you for explaining these principles. Ive done software dev for a fortune 500 company for 3 years and I realized we dont use solid. At. All. Our architecture is gross. Ive been looking to sharpen our apps and these have been a great starting point. Thanks again!
Great job. Love that the application is not some abstract project. Making it as close as you can to real life helps to more easily understand the SOLID design pattern. Thank you.
This basically kinda explains why interface is needed. Also what happens if there was no interface in a project!! Learnt a lot. When you first taught about interface and the reasons behind using them, it was actually telling about this OCP. Now it's all clear
Another Great video from Tim. Tim looks at things step by step to show this principle and the important practical benefits. Also, lots of good tips along the way to save you getting caught in traps unexpectedly, thanks Tim.
Thank you very much, Tim. You explained SOLID pretty easy. I guess you've found the setting of interface\abstract autogeneration, but may be it will helpful for someone else:to avoid NotImplementedException for properties get;set; just go to Tools -> Options -> Text Editor -> C# -> Advanced -> Implement Interfaces or Abstract Class -> prefer auto properties. Thanks again!
Heads up: time stamp through @14:00 explains the problem Open/Closed is there to SOLVE. That segment highlights what you woudl do if we didn't have Open/closed principle, edit your classes all the time to add new features. From @16:00 and on, Tim shows how to implement OpenClosed. I recommend watching the first part as it's a great example of the anti-pattern.
Wow, you amazed me, you have amazing content, very informative and interesting to watch, and you even keep answering question after month have passed. Great job man, you are wonderful person!
I love this videos it so hard to find anything more than basic tutorials and this are just amazing. I understend everything, examples are practical and simple.
Ever since I started following you on RUclips, I’ve become a big fan of your teaching methods. I’m a WPF Developer and I really wanted to know more about Design Patterns. Thanks to your video tutorial using practical examples. Looking forward for upcoming videos on Design Patterns. More power to you!
As always, an excellent video! In your comment to me on the previous video regarding SRP, you mentioned making a follow up video and combining all 5 patterns in SOLID. I think it would honestly be a very good idea, since there is a massive difference between seeing all the "players in action at the same time" and then seeing each of them separately -- kind of like an orchestra; music always sounds better when you have more than one instrument, you know? You sure do explain this a lot better than my old teachers did back in the day. I had hoped that you would have explained the concept of Abstract classes and how they also tie in with interface, but given the way you went about this video, I sure can understand why you didn't -- there is more than enough "meat" on this bone as it stands -- which is good, there is a lot to cover! Also, regarding namespaces, you forgot to mention that when you use namespaces, the final point of the namespace, eg. "OCPLibrary.Accounts", then you cannot have a class called "Accounts" as those things will create conflicts. :-)
Yep, I think I'll start working on a full SOLID video. I think by the end, the videos will be mostly SOLID anyway but a good full example would probably be good. I'll probably do a separate video at some point on abstract classes.
I understand this is just a simple example to convey the principle, but I have two main issues with abiding to this principle for EVERYTHING: 1. In the real world, your IApplicantModel interface would represent some input for an Employees data table, so if you add a field to the Employees table, you now have to go through all of your Applicant models and add this new member, plus go through all the ApplicantAccounts and add the new logic for this new member and to me, that's defeating the purpose. 2. It creates file hell I use interfaces for all of my service methods, repository methods, and application models (NOT data entity models, those should be hard-bound imo). I ONLY use interfaces as a precaution and I even put my interfaces inside of my class files (at the top before the class declaration). I use interfaces just in case one day a change or addition shall warrant using the interface as shown here (but there has to be good reason for me, it has to warrant itself), in that case I take the interface out of my class file and put it into a file of it's own, then mass update reference. This may not be a "good" way but I've found it works best for me and that's what I love about programming. I love your videos, Tim . Cheers!
I definitely don't recommend applying OCP to everything. Software development is definitely about being knowledgeable about best practices while applying what works best for your project.
Very good. With regards to keeping your interfaces alongside your concrete classes. Once you are writing a large Prism or similar 'modular' application I have learnt that is not best practice to do this. Normally we will put interfaces in a separate 'Infrastructure' project. This way once you are leveraging dependency injection & using an IOC container to inject dependencies you do not have modules being dependent on other modules, rather modules that need to resolve those types can reference the 'infrastructure' interface module and the concrete types are then resolved at run time. This way a module can be used by another application and achieves real separation of concerns. Obviously this is out of the scope of this small example application...
Hi Tim, this is your customer. Thanks for providing the new software version, it's great! Anyway, we just now realized that humans can have middle names! Could you please add middle name support by tomorrow morning? I know it's a tough deadline, but since we spent the whole last year refactoring everything to be SOLID, I'd assume such changes can be done much quicker now and there are fewer places to touch, so less stuff can break. Thx and keep up the great work! ;-)
Thanx for the excellent explanation. Even though the changes ofcourse are still perceptible to bugs as you had to rewrite everything to interfaces, and then did not change the original names of the 'base' classes which might make it easy to mistake (like PersonModel should have be renamed to StaffModel and the Accounts to StaffAccounts because otherwise in the future it could be mistaken for anything else). Also it's easy to say, now you are confident to add a new employeeType.. But to be honest, if the original Accounts was implemented with the switch, I also would be confident to if I had to make a change, as it wouldn't really matter if I had to create the original PersonModel with EmployeeType set, or if I had to set a new Model. The problem now is that if there is one slight change to the 'PersonModel' you have to change ALL your other classes too instead of just 2 classes (PersonModel/Accounts), so it might introduce some more bugs.. So yeah, it solves one problem, but it also creates another which you wouldn't have with the first way of implementing multiple employeetypes.. But maybe it's just me that IS confident in making changes to things like switches etc. and wanting to actually see what happens in different cases at that point (for instance the differences between emailaddress creation). Also if this was a big application, it would have been hell if you went from everything in one folder with the OCPLibrary namespace to separate folders and NOT have it have OCPLibarary. namespace and then later have some folders to have it as a namespace. That would make it really confusing, and in the end, changing namespaces of the library after it is in production you get the problem of the other projects might have to be rebuild again and having problems with the namespaces. Also in this case you called the folder Accounts, but we did have a class named Accounts and it created problems with the TechnicianAccounts class which was created in the Accounts folder, and that made the original Accounts class get a problem with having the same namespace as the original Accounts class wasn't in the Accounts namespace. If the Accounts class would have been names StaffAccounts it wouldn't have this problem BUT you would have problems of some ...Accounts classes be part of the OCPLibrary namespace and some of the OCPLibrary.Accounts namespace which ofcourse is very confusing. (Just like my text here, LOL). So in the end, you always have to be careful if you change code/namespaces after it's already in production, no matter which principle you use.
Yep, every situation will be different but the best thing is if you architect your application with OCP to begin with (as much as it makes sense) rather than trying to change it after the fact.
Really crisp audio in this one, Tim. Very easy to follow along with ( I know you mentioned trying to slow down a bit in your videos before). Well this one was great from that regard!
I once came across a library that was zealously implementing open/closed. Each object had suffix number (some were on their 30th version). Each of these suffixed versions depended various suffixed versions from other objects. It instantly struck as the closest I’ve seen code come to being actual spaghetti. The documentation was 90% “object9 is deprecated”, please use object10. Then object10s documentation was “object10 is deprecated, please use object11”. In short you have to remember that open/close was created quite a long time ago. (Along with the rest of solid). If there is any principle you might disregard completely it’s this one. Make good automated testing instead.
Tim is polite in his answer but anyone would tell you that if you think having Object1 & Object2 is OCP, then you should probably watch this video again. Closed to modification does not mean it's impossible to make a change/fix. Object2 should have never existed in the first place. Instead, OCP is an 'encapsulation & polymorphism combined principle' that let you use objects through functionalities rather than definitions by associating them via what they are capable of.
@@hugogogo13 Sounds nice in theory, only the original definition according to Meyer is exactly how I described. Instead of modifying object 1 you extend it by creating object 2. Very few examples consider what happens when you have more modifications to make and have to create object 3. Even the modern interpretation using an abstract base or interface and then replacing the implementation with a new one instead of inheriting the previous object is a maintenance nightmare. You seem to have compiled your own version of the principle that makes it valid. but if you go and read the actual definitions of it online it is mostly as I’ve said. I would almost argue that the principle as you describe is entirely different and probably deserves a different name.
Thanks. I was hoping it was easy to understand. I was concerned it was getting a bit complex. I wanted to get past the examples that are simple but don't really apply to the real world, but that meant upping the complexity. Glad it came through clearly.
You can tell Visual Studio to not throw on implementing properties on interfaces in Tools -> Options -> Text Editor -> C# -> Advanced -> When Generating Properties -> prefer auto properties. Not really sure why they don't enable this by default honestly.
Wow, that's awesome! Thanks for pointing that out. I agree it should be enabled by default. I'll have to mention that to some people to see if they are willing to change the default.
Great explanation, really hit home on why extension is the way to go and why modification is so dangerous. Which is why I think you overlooked the concept of a base class and hierarchy a little too quickly. That’s exactly what child classes inheriting a base class are doing: extending. You were talking about violating DRY; a base class can do everything an interface could with the benefit of reusing code. If you need more logic in a particular function for a child class, then you create a new function with a call the base class function. And if base function(s) shouldn’t be reused on that child class, maybe you shouldn’t be extending off of that base class…? Interfaces are great for unit testing and guardrails, but anything else can be done with hierarchies. Yes you need to be careful (calling a base function from a child class when you meant to call the child function…yikes) but it’s a powerful tool.
Inheritance is a powerful tool, but it is also very limited. You need to be careful when you use it that you don't cause more problems than you started with. For instance, if you decide to improve a method, so you create a child class, everything seems good. But then what if you wanted to change a different method but use the original of the first method? Now you have two different children inheriting from the same base. That seems fine. But now what if you want both of the updated methods? Now you have a problem. You cannot inherit from either child class without duplicating the work of the other. Inheritance locks you in a lot more than you really want if you aren't really, really careful.
@@IAmTimCoreyyou’re correct of course, and careful designing and sticking to lose coupling-tight cohesion is a requirement for sure. But for that particular example one could argue the same implementation done with interfaces would also require duplicated code. In my opinion, you’ll have to violate DRY in the real world regardless. I think hierarchies do it far less, but you can get tighter coupling as your example illustrates.
Great lecture Tim! But there is one thing I don't like in this solution, and that's the property AccountProcessor. Its initialization violates LSP, and its sheer existence SRP. Sure, there is an extra implementation for any account type, but it's not the purpose of an applicant to provide any mapping functionality for translating his properties to the EmployeeModel or any other type.
Really great explanation. I now understand the concept much better 😊. Only thing that stands out in my view, is the line employees.Add(person.AccountProcessor.Create(person)). So person class injects itself as a parameter. This could be avoided if an abstract base class was used that had an applicant class passed as a parameter in the constructor.
Great explanation. And I finally understood the uses for interfaces. I mean, not how to use them for the advantages of using them. I'm looking forward to start implementing them from now on! Thanks, Tim. :D
[48:03] I'm quite glad you actually mentioned using base classes, since it's how I create quite flexible, extensive things. I was honestly starting to think you were just all about turning everything into interfaces. That's no better than turning everything in C++ into templates. LoL
Thank you very much for this video! This was very well explained, I have been able to make good notes from it, and I now feel ready to implement this principle in my future projects.
Great video! To speed up things when implementing the interface, one could select the excerpt "=> throw new NotImplementedException()" and CTRL + H then ALT + A 😅
Excellent video, thanks for explaining this, I was a little concerned with all the copy and paste of the same code, breaking the S in the series, but completely understand why in the lesson, normally as you said you would create a base class :)
Yeah, possibly a base class or maybe just a single class with the code and then calls to it from the multiple locations. The tough thing is that a lot of the code changes.
Isn't that illogical to put AccountsProcessor inside of person model? I mean, I don't process corporate changes if I am accepted to a company, rather it's done by some external processor upon my person... I feel like these patterns sometimes confuse and mess things up more than provide help.
I get what you're thinking. You're viewing things through a "logical" scope. The point is that every user has a own account management and not that they make their stuff by themselves.
Nice video, thanks! I think that writing code with OCP in mind, helps a lot, since it makes code a lot better. But if you start from a project that is already in production and not developed thinking about OCP, it will be really hard to make changes without changing what is already working. But, even if its working, you have to change code when you want to refactor. And, Unit Tests should be here to help us not to introduce bugs on working code. The point is, I think we have to write code with this principle in mind, but don't overthink or overdo it. Thanks for the video, it helped me a lot to clear this concept! :)
I am beginner on .NET which I just started December 2018 but it seems gradually change my style of learning process on how to do full stack .NET web/dev in standard and best practices, all videos are pointing to a very neat and precise coding style. Can't wait new videos from you. Maybe gang of four (GoF) principle? Which I just read 3 days ago.
Very nice video tutorials about the SOLID principles. Really liked and enjoyed. Could not refrain myself from subscribing your channel. Would love to see new things. Thank you very much Tim. Keep it up!!!!!
Hey Tim, I've been watching your SOLID videos and really enjoying them but I have one question. With the way we're structuring our classes, creating interfaces and dealing with inheritance, how would these same classes be stored in a database? Would a table for each be correct? What if I want to retrieve all Persons in my database, then they would be scattered in different tables. Would we have to define specific database Entities that map our Models and define database relationships through our ORM to get the database structure we want? I'm used to have more simple models which are easily mapped to a single entity and its respective repository, that's why I'm asking would would be correct to do in the scenarios described in the video :) Thanks in advance!
At 32:00 you could use “composition” and have ManagerAccounts take an Accounts class in its ctor which calls create. Could also be seen as a decorator.
I love your videos! I have a quick question: I have bingewatched your SOLID series for a second time to refresh it in my memory, and I can't help but notice that almost all of them favor the use of interfaces. However, I can't help but think that these interfaces implemented without an abstract BaseClass are always violating DRY. For example, here the applicants share some similar lines. It's not that big of a problem here, but in another video (I think it was ISP, with the DVD and Audiobook examples), the modules were sharing the same method but each implementing it on their own with the exact same lines. I just find it awkward to use interfaces because they seem to regularly create moments where you accidentally repeat yourself.
DRY isn't about not having any repetition. It is about not having the same exact logic more than once. The methods may have the same signature, but they may do different things. They may even do the same thing, but in a way that is not guaranteed to stay the same forever. In those cases, they aren't violating DRY. If you found that you did have exact repetition, you don't need to use a base class (inheritance isn't about code sharing, it is about a relationship - if there isn't a strong relationship, you shouldn't use inheritance). Instead, just create a class with a method that both locations can call. Interfaces are the primary OOP system used in modern development. They give you flexibility, testability, and more.
@@IAmTimCorey Thank you for your thorough explanation, that makes a lot of sense, especially the part about relationship/code sharing, gives me a lot of food for thought. I appreciate you took the time!
Pick and choose. In general, they will almost always apply but they may not always be helpful. You choose what is best for your application. Good question.
I love your chanel. Anyway, for those who don't know, Acme produced the anumation cells and its use in the Road Runner was an in joke by the WB animators.
If it wasn't obvious, I was heavily influenced growing up by their fictional production of anvils, catapults, and coyote-carrying rockets. 😆 Thanks for sharing.
@@IAmTimCorey In my opinion, it would be clearer if you used the same project since I already know what's in it and I wouldn't have to learn about the new project and try to imagine how you would implement all the SOLID principles into ONE project! This has been then problem for me. I can't find anyone using the one project thru all the SOLID principles and how the end should look like but instead, I'm given bits and peaces of it and then left to my own imagination to try and implement them all in one project. Problem is, I don't know if I did it right without having a few examples of the completed code in SOLID form!
@@Layarion Instead of inherit from a class for the use of certain base functionality. Put that Base functionality in another class and inject it in your constructor) from yout class and assign the instance to a private readonly field. You can now use the desired functionality by composition (private field with necessary class/functions) instead that you use the functionality because you're in a inheritance tree. Injection and private fields as Interface types of the desired class for loose coupling, i.e. you can change which implementation of the class you will inject to have as composite.
Hhhm, interesting point but for me that’s only really an argument when your faced with multiple inheritance scenarios (I do appreciate interfaces are preferred to inheritance for OCP and this is a demo so I am being "discussioney" rather than judgy). A Manager really "is a" Employee, and an Executive "is a" Manager. You really shouldn’t be copy/pasting FirstName/LastName around IMO. Okay, if you are then faced with a new requirement of Salesman (still okay) then a SalesManager (yeesh, possible multiple inheritance) then stuff breaks but, within reason, you shouldn’t design in requirements you don’t have. [digressing now but..] 20 years ago we used to spend weeks or even months meeting around whiteboards designing in what-ifs, only to find not only where they never asked for, 60% of the features they did ask for were never used! Refactoring tools are so quick and powerful now it’s just way better spending that time writing tests instead so you can safely refactor in change rather than spend that time trying to predict future change.
Great tutorial Tim. I know this video is old but if I can just make a small suggestion for future videos, at the end of these type of tutorials could you perhaps go to program.cs and explain how each line works by opening the classes and interfaces that each line is using. I think it would really help viewers understand how everything comes together. I understood it just fine, but I'm still trying to piece it together in my head. I'm downloading the source code now
I do not clearly understand whats the point of the EmployeeModel class or did i miss some explanation? To me it looks like it is only used to compare all the different IApplicant models. The EmployeeModel must contain the union of all attributes of the different types (namely isManager, isExecutive, firstName, ...) while the models only differ in their AccountProcessor attribute and do not contain any data except what is common among them (names). The accountprocessor just tells you how to create a common "base class" namely the EmployeeModel out of this type by using an additional indirection. Im not entirely sure but cant this approach be simplyfied by using an abstract base class instead of having the EmployeeModel as a separate class, let the different types of employees inherit from it and put the Create() codes into the constructors? You also wont need to change the child classes if you add executive or manager to the base class as these default to false just like in EmployeeModel. However both approaches do have problems in common: If we created the executive first and then the manager, we would have had to change the executive because bool does not default to true. Also Main and EmployeeModel have to always change if we add a new type of person that comes with a new attribute.
Hi Tim. I have a question about the S, not about the O in SOLID (sorry :D but you mentioned it here and it brings me to think about one thing). As you said - "SRP - Classes should have only one reason to change". Ok. When we change the way we create an account for a person it is just one reason. But what if we have other methods, e.g. Edit(), Delete() and many others. Then the account class has more reasons to change. When we change the way we Edit account, Delete account, etc. How does it refer to SRP? P.S. I want to thank you for your videos. You really pushed my learning C# forward :)
That does depend a bit on your interpretation of "reason for change". In order to not go crazy, I tend to think of methods as "one focused reason" and classes as "one general reason" to change. For instance, Person would not need to change generally unless how a person worked changed. Edit would not need to change unless the specific logic was altered.
Hi Tim, I'm working through your C# App From Start To Finish, and digesting some of these other videos, and this is all great stuff; thanks for this. I'm a long-time VB hobbyist (I can't say I'm a pro developer even though I have quite a bit of code here and there in macros and smallish apps at work) and I'm trying to transition to C# and to think more in OOP. I'm struggling with Interfaces (saw your Interfaces vid) and this compartmentalization of the code. (I come from a world where *everything* was in the frmMain module... ;-) In this particular video, I would have approached it as using an Employee object, and used an employee.ActivateAccount(applicant, empType) method, where the empType is an enum. Then, instead of adding an entire set of interfaces and models for a different type of employee, you just add a new entry to the EmployeeType enum, and add a new entry to your case or switch block to implement differently where necessary. You're not necessarily changing code flow nor are you touching existing logic, but you are adding sections in a somewhat safe manner. I get that this is just a simple example, but if you have to recover from not allowing for different employee types (i.e., a big requirements hole) you're gonna have to tear into some code anyway. Also, while I understand that you should have different classes to represent your various objects, to have different classes to do different *things* seems strange to me -- wouldn't you just implement different methods or properties for the class? I have a nagging feeling that I'm missing some higher level understanding or approach; perhaps you need a few PowerPoint slides after all... Keep up this great work. I was floundering until I discovered you. Regards, Renny
The issue with the enum is that you are making changes in multiple places then. Yes, it is only adding logic not altering it (for the most part) but it is a change. Besides, if you make that change and the new part of the enum has a problem, you break existing code. One of the things that will help is practice. The more you see these situations, the more you will understand the long-term implications. This is a rather hard one to jump into when transitioning over to a true OOP way of thinking. Great thoughts though. I'm glad you are thinking it through.
Great series of videos, very helpful, thank you! If I understand correctly, in your non-OCP approach early in the video you have only one Accounts instance. Once you've applied OCP you have some kind of IAccounts instance for each IApplicantModel instance. If you had thousands of applicants, you'd have just as many IAccounts instances. However, it seems to me you only really need 1 instance of each class that implements IAccounts. My instinct is to try to model the code on something analogous to real life. Having each person object have an account processor object doesn’t feel natural to me. Perhaps I would have a class to manage applicants (maybe called ApplicantsManager), which would take an IApplicantModel object and give back a reference to an IAccounts instance of the type relevant to the real type of IApplicantModel object. What do you think?
It doesn't matter if you use an IAccount interface or the Account class instance - either way you can choose how many instances of that class you have. Using the interface does not dictate how you create the object, just the requirements on the object.
Hi @IAmTimCorey, could one refrain from implementing variations of the Account class, - continue using it how you initially did, i.e.: accountsProcessor.Create(person), and overload its Create() method to take the various (new) IApplicantModel types... effectively all of your improvements are the same, except your variations of Create() are together in Accounts............. and still have "used OCP"? Would this be inferior or just another way to have applied OCP?
That would mean continually changing the Account class, which would violate OCP. It would also be quite messy. There may be certain circumstances where this is the right call (Console.WriteLine has a bunch of overloads like you are suggesting), but in our case it would probably be better to use child classes.
I come from Java world and I was always curious that, in C# why we like to name classes as XXXModel? What exactly a model class means? Is it a pure data class with getters and setters?
Each instantiation of a model(PersonModel, ManagerModel, and ExecutiveModel) call the new operator. Isn't this putting too much work on the GC? I think it will be better if every class, which implements IAccounts, was a singleton. Sure thing, the AccountProcessor property stays, but this way the GC will be relieved. With C++ as my main language, I always watch out for this kind of stuff haha. Also, I love your videos! You are amazing!
There are some semantic changes that you could make to improve the code. But that's not the point. The point is to demonstrate how to add functionality with minimal changes to existing code and this is a very good example.
Your explanation is SOLID! Thank you.
Glad it was helpful!
One thing I really appreciate about your videos is that you speak clearly enough for RUclips's auto-generated captions to work accurately. Great information, thank you for the video!
You are welcome.
Hey Tim, I was approached by a company for a senior position for the first time in my life, and the tech interview is tomorrow. I'm just going over the SOLID principles again and realized I never truly understood any of them. I'll probably get obliterated tomorrow, but still thanks a lot for this explanation! We use similar approaches in our current codebase, but now I'm able to at least put a name to the face of this principle.
Excellent! Best wishes on the interview.
How did the interview go?
Like Kaushik S, said you're the best when it comes to presentations. You always assume your audience may not know much or anything about the topic, so you go in details along the way. That's a wonderful approach. Thanks!
I appreciate the kind words. I'm glad you appreciate my approach.
This is not only MVP, I make it higher than MVP.
Loved this video, I have watched many videos and read many more articles on SOLID and C# and I haven't found an explanation that is as clear and concise as this one.
I am glad you enjoyed it.
Thanks for explaining this principle. All the other videos which try to explain it in 3 minutes fail to explain it completely.
You are welcome.
Excellent work, neatly and concisely explained
I wish my University had a teacher like you
I am glad it was helpful.
I really like these videos. I particularly appreciate the fact you show the actual implementation by showing/writing the code in a way that isn't overly abstract and simplified. Thanks a lot!
You are welcome.
Thank you. You make sure to explain the reason behind every decision, and all the other details. I watch some a number of times, and am so glad to be learning C# and watching the contents of this channel.
I appreciate the kind words.
Thank you for this series. I love the fact that you actually make a interesting example instead of only staying on the theory realm.
Tim has real world experience and thinks its important to share it. Viewers seem to agree.
Hi Tim! Thanks for a good video!
Just wanted to comment - that while I do think you're explaining the concept of the open / closed principle good with your example. I also think it shows as why you should be cautious about implementing this principle in the real world. I consider the amount of complexity added to the application a worser tradeoff than a bug or two in the long term. The bugs can be easily fixed when identified while the added complexity might be there forever :)
Hi Tim, this specific example made things a bit muddy for me but I still liked the video because I believe I got the message you were trying to communicate through. A great example I came across of OCP is when we were working with certain libraries or assets and essentially in order to expand what the library offers we can simply use an interface they already used in advance. If I'm not mistaken we used this principal on a node based slide system that lets you add new slides without modifying the original library but simply using its ISlide interface. That way you have a new slide node you can employ in the graph as it easily fits the entire system and other slides are not affected since nothing core changes. If it ever comes to it I would love it if you showed us real life scenarios from work you do or you've done that use OCP. Thank you for the videos and greetings from the Netherlands!
Thanks for the great feedback
These are things my degree has never taught me. Practical Software Engineering. Thank you for your videos. This is what separates juniors from more experienced programmers and you are helping me with that step! I'm applying these to code in my current job
Great to hear!
Great execution Tim, thank you! I've definitely been violating the O/C principle for a while now, but not anymore. I'm seeing more of why interfaces are a godsend.
Excellent!
Software entites( classes, modules, functions, etc.) should be OPEN FOR EXTENSION, but CLOSED FOR MODIFICATION. With the Open Closed Principle, the code is more robust and more future proof. I understood it all! Thank you Tim!
I am glad it was helpful.
Thank you for explaining these principles. Ive done software dev for a fortune 500 company for 3 years and I realized we dont use solid. At. All. Our architecture is gross. Ive been looking to sharpen our apps and these have been a great starting point. Thanks again!
Yep, that is fairly common. I'm glad these will be useful to you.
Great job. Love that the application is not some abstract project. Making it as close as you can to real life helps to more easily understand the SOLID design pattern. Thank you.
You are most welcome. Thanks for watching.
I have no word....its awesome, your tutorials changed my coding style.....Thank you Sir...Super Love for You
I am so glad they were helpful.
you really do clear up the confusion and the frustration around learning c#. xD
Awesome! That's the goal. I'm glad you feel like I am accomplishing it.
This basically kinda explains why interface is needed. Also what happens if there was no interface in a project!! Learnt a lot.
When you first taught about interface and the reasons behind using them, it was actually telling about this OCP. Now it's all clear
I am glad it is clear now.
Another Great video from Tim. Tim looks at things step by step to show this principle and the important practical benefits. Also, lots of good tips along the way to save you getting caught in traps unexpectedly, thanks Tim.
You are most welcome. Thanks for watching.
Agree with previous comments...exactly what the type of tutorials one needs. Thanks for this.
Glad it was helpful!
Thank you very much, Tim. You explained SOLID pretty easy. I guess you've found the setting of interface\abstract autogeneration, but may be it will helpful for someone else:to avoid NotImplementedException for properties get;set; just go to Tools -> Options -> Text Editor -> C# -> Advanced -> Implement Interfaces or Abstract Class -> prefer auto properties. Thanks again!
You are welcome.
Heads up: time stamp through @14:00 explains the problem Open/Closed is there to SOLVE. That segment highlights what you woudl do if we didn't have Open/closed principle, edit your classes all the time to add new features.
From @16:00 and on, Tim shows how to implement OpenClosed. I recommend watching the first part as it's a great example of the anti-pattern.
Thanks for sharing.
Wow, you amazed me, you have amazing content, very informative and interesting to watch, and you even keep answering question after month have passed. Great job man, you are wonderful person!
I appreciate the kind words.
Great Tim .... you are doing a great job in making C# easier for people
Thanks!
I love this videos it so hard to find anything more than basic tutorials and this are just amazing. I understend everything, examples are practical and simple.
Excellent!
Thank you for share your wisdom. This isn't an easy concept, but your class was crystal clear.
Love from Brazil!
You are most welcome. Thanks for watching.
Ever since I started following you on RUclips, I’ve become a big fan of your teaching methods. I’m a WPF Developer and I really wanted to know more about Design Patterns. Thanks to your video tutorial using practical examples. Looking forward for upcoming videos on Design Patterns. More power to you!
Awesome! I'm glad you're enjoying the series.
Hi Bharath, I'm also WPF developer. Which company you work for?. I stay in Bangalore. Can we connect on vinaypalaksha1@gmail.com
The video is published more than 2 years ago, but Tim still keeps replying to comments.
I like to know the videos are still adding value! Thanks for watching.
@@IAmTimCorey Created a repository following your tutorials. Open to pull-requests. Gonna finish in a week. github.com/Muhammadrasul446/SOLID_C-Sharp
That's why I love Tim!!
@@IAmTimCoreythanks for teaching 👍🎉
Practice! Practice! Practice its going to be my goal to be better programming, Thnks a lot Tim for this great video tutorial!
Yep, practice is really important. Glad you enjoyed the video.
Great teaching style Tim, so glad I've found this channel!💛💪
Awesome, thank you!
As always, an excellent video! In your comment to me on the previous video regarding SRP, you mentioned making a follow up video and combining all 5 patterns in SOLID. I think it would honestly be a very good idea, since there is a massive difference between seeing all the "players in action at the same time" and then seeing each of them separately -- kind of like an orchestra; music always sounds better when you have more than one instrument, you know?
You sure do explain this a lot better than my old teachers did back in the day. I had hoped that you would have explained the concept of Abstract classes and how they also tie in with interface, but given the way you went about this video, I sure can understand why you didn't -- there is more than enough "meat" on this bone as it stands -- which is good, there is a lot to cover!
Also, regarding namespaces, you forgot to mention that when you use namespaces, the final point of the namespace, eg. "OCPLibrary.Accounts", then you cannot have a class called "Accounts" as those things will create conflicts. :-)
Yep, I think I'll start working on a full SOLID video. I think by the end, the videos will be mostly SOLID anyway but a good full example would probably be good. I'll probably do a separate video at some point on abstract classes.
I understand this is just a simple example to convey the principle, but I have two main issues with abiding to this principle for EVERYTHING:
1. In the real world, your IApplicantModel interface would represent some input for an Employees data table, so if you add a field to the Employees table, you now have to go through all of your Applicant models and add this new member, plus go through all the ApplicantAccounts and add the new logic for this new member and to me, that's defeating the purpose.
2. It creates file hell
I use interfaces for all of my service methods, repository methods, and application models (NOT data entity models, those should be hard-bound imo). I ONLY use interfaces as a precaution and I even put my interfaces inside of my class files (at the top before the class declaration). I use interfaces just in case one day a change or addition shall warrant using the interface as shown here (but there has to be good reason for me, it has to warrant itself), in that case I take the interface out of my class file and put it into a file of it's own, then mass update reference. This may not be a "good" way but I've found it works best for me and that's what I love about programming.
I love your videos, Tim . Cheers!
I definitely don't recommend applying OCP to everything. Software development is definitely about being knowledgeable about best practices while applying what works best for your project.
Great and simple explanation of rather hard to get principle. Thanks for it.
Very good. With regards to keeping your interfaces alongside your concrete classes. Once you are writing a large Prism or similar 'modular' application I have learnt that is not best practice to do this. Normally we will put interfaces in a separate 'Infrastructure' project. This way once you are leveraging dependency injection & using an IOC container to inject dependencies you do not have modules being dependent on other modules, rather modules that need to resolve those types can reference the 'infrastructure' interface module and the concrete types are then resolved at run time. This way a module can be used by another application and achieves real separation of concerns. Obviously this is out of the scope of this small example application...
Yep, it does depend on how you intend to use them later on, good point.
Awesome approach of explanation - step by step and reasons presented why not to follow a specific approach.
Glad it was helpful!
Hi Tim, thanks for the great videos. I am new and thus these videos are a great help. Plan to enroll in your courses next.
I am glad they are so helpful.
I like the way you teach, it's easy to follow your thought process, the explanation of why and how, and not too many presumptions.... good work!
I am glad you are enjoying the content and my style.
U r d best .when it comes to teaching .Please 1 video on SQL performance tuning and mvc request life cycle
I will make sure those topics are on the list. Thanks for the suggestions.
@@IAmTimCorey are these videos prepared, i would love to watch that.
I enjoy watching ur videos, it shows a lot of in-depth stuff that we miss, and that u explain what are you doing in order not to get lost.
Excellent!
Hi Tim, this is your customer.
Thanks for providing the new software version, it's great! Anyway, we just now realized that humans can have middle names! Could you please add middle name support by tomorrow morning? I know it's a tough deadline, but since we spent the whole last year refactoring everything to be SOLID, I'd assume such changes can be done much quicker now and there are fewer places to touch, so less stuff can break.
Thx and keep up the great work! ;-)
That sounds about right. Good designs don't make up for poor planning.
Thanx for the excellent explanation.
Even though the changes ofcourse are still perceptible to bugs as you had to rewrite everything to interfaces, and then did not change the original names of the 'base' classes which might make it easy to mistake (like PersonModel should have be renamed to StaffModel and the Accounts to StaffAccounts because otherwise in the future it could be mistaken for anything else). Also it's easy to say, now you are confident to add a new employeeType.. But to be honest, if the original Accounts was implemented with the switch, I also would be confident to if I had to make a change, as it wouldn't really matter if I had to create the original PersonModel with EmployeeType set, or if I had to set a new Model. The problem now is that if there is one slight change to the 'PersonModel' you have to change ALL your other classes too instead of just 2 classes (PersonModel/Accounts), so it might introduce some more bugs.. So yeah, it solves one problem, but it also creates another which you wouldn't have with the first way of implementing multiple employeetypes.. But maybe it's just me that IS confident in making changes to things like switches etc. and wanting to actually see what happens in different cases at that point (for instance the differences between emailaddress creation).
Also if this was a big application, it would have been hell if you went from everything in one folder with the OCPLibrary namespace to separate folders and NOT have it have OCPLibarary. namespace and then later have some folders to have it as a namespace. That would make it really confusing, and in the end, changing namespaces of the library after it is in production you get the problem of the other projects might have to be rebuild again and having problems with the namespaces. Also in this case you called the folder Accounts, but we did have a class named Accounts and it created problems with the TechnicianAccounts class which was created in the Accounts folder, and that made the original Accounts class get a problem with having the same namespace as the original Accounts class wasn't in the Accounts namespace. If the Accounts class would have been names StaffAccounts it wouldn't have this problem BUT you would have problems of some ...Accounts classes be part of the OCPLibrary namespace and some of the OCPLibrary.Accounts namespace which ofcourse is very confusing. (Just like my text here, LOL).
So in the end, you always have to be careful if you change code/namespaces after it's already in production, no matter which principle you use.
Yep, every situation will be different but the best thing is if you architect your application with OCP to begin with (as much as it makes sense) rather than trying to change it after the fact.
Really crisp audio in this one, Tim. Very easy to follow along with ( I know you mentioned trying to slow down a bit in your videos before). Well this one was great from that regard!
Glad it was clear.
I once came across a library that was zealously implementing open/closed. Each object had suffix number (some were on their 30th version). Each of these suffixed versions depended various suffixed versions from other objects. It instantly struck as the closest I’ve seen code come to being actual spaghetti.
The documentation was 90% “object9 is deprecated”, please use object10. Then object10s documentation was “object10 is deprecated, please use object11”.
In short you have to remember that open/close was created quite a long time ago. (Along with the rest of solid). If there is any principle you might disregard completely it’s this one. Make good automated testing instead.
Overuse of any principle is a bad thing.
Tim is polite in his answer but anyone would tell you that if you think having Object1 & Object2 is OCP, then you should probably watch this video again. Closed to modification does not mean it's impossible to make a change/fix. Object2 should have never existed in the first place. Instead, OCP is an 'encapsulation & polymorphism combined principle' that let you use objects through functionalities rather than definitions by associating them via what they are capable of.
@@hugogogo13 Sounds nice in theory, only the original definition according to Meyer is exactly how I described. Instead of modifying object 1 you extend it by creating object 2. Very few examples consider what happens when you have more modifications to make and have to create object 3. Even the modern interpretation using an abstract base or interface and then replacing the implementation with a new one instead of inheriting the previous object is a maintenance nightmare.
You seem to have compiled your own version of the principle that makes it valid. but if you go and read the actual definitions of it online it is mostly as I’ve said. I would almost argue that the principle as you describe is entirely different and probably deserves a different name.
@@NickSteffen fair enough. That's okay then, SLID is still a catchy name 😉
Great video Tim. Easy to understand, good examples... Thanks for sharing that knowledge!!
Thanks. I was hoping it was easy to understand. I was concerned it was getting a bit complex. I wanted to get past the examples that are simple but don't really apply to the real world, but that meant upping the complexity. Glad it came through clearly.
Great video - you got through the video with out mentioning polymorphic once :)
I try to avoid confusing words that don't add to the discussion.
You can tell Visual Studio to not throw on implementing properties on interfaces in Tools -> Options -> Text Editor -> C# -> Advanced -> When Generating Properties -> prefer auto properties. Not really sure why they don't enable this by default honestly.
Wow, that's awesome! Thanks for pointing that out. I agree it should be enabled by default. I'll have to mention that to some people to see if they are willing to change the default.
Hehe i wrote this same. You are first.
Great explanation, really hit home on why extension is the way to go and why modification is so dangerous.
Which is why I think you overlooked the concept of a base class and hierarchy a little too quickly. That’s exactly what child classes inheriting a base class are doing: extending. You were talking about violating DRY; a base class can do everything an interface could with the benefit of reusing code.
If you need more logic in a particular function for a child class, then you create a new function with a call the base class function. And if base function(s) shouldn’t be reused on that child class, maybe you shouldn’t be extending off of that base class…?
Interfaces are great for unit testing and guardrails, but anything else can be done with hierarchies. Yes you need to be careful (calling a base function from a child class when you meant to call the child function…yikes) but it’s a powerful tool.
Inheritance is a powerful tool, but it is also very limited. You need to be careful when you use it that you don't cause more problems than you started with. For instance, if you decide to improve a method, so you create a child class, everything seems good. But then what if you wanted to change a different method but use the original of the first method? Now you have two different children inheriting from the same base. That seems fine. But now what if you want both of the updated methods? Now you have a problem. You cannot inherit from either child class without duplicating the work of the other. Inheritance locks you in a lot more than you really want if you aren't really, really careful.
@@IAmTimCoreyyou’re correct of course, and careful designing and sticking to lose coupling-tight cohesion is a requirement for sure. But for that particular example one could argue the same implementation done with interfaces would also require duplicated code.
In my opinion, you’ll have to violate DRY in the real world regardless. I think hierarchies do it far less, but you can get tighter coupling as your example illustrates.
Great lecture Tim!
But there is one thing I don't like in this solution, and that's the property AccountProcessor.
Its initialization violates LSP, and its sheer existence SRP.
Sure, there is an extra implementation for any account type, but it's not the purpose of an applicant to provide any mapping functionality for translating his properties to the EmployeeModel or any other type.
I don't really agree on the violations. Part of it comes down to the definition of what a responsibility is but we can apply LSP.
@@IAmTimCorey sorry, meant DIP, not LSP.
Really great explanation. I now understand the concept much better 😊. Only thing that stands out in my view, is the line employees.Add(person.AccountProcessor.Create(person)). So person class injects itself as a parameter. This could be avoided if an abstract base class was used that had an applicant class passed as a parameter in the constructor.
Great explanation.
And I finally understood the uses for interfaces. I mean, not how to use them for the advantages of using them.
I'm looking forward to start implementing them from now on!
Thanks, Tim. :D
Glad it was helpful!
Very nice how you show how to not mess with existing code-base.
Thanks!
[48:03] I'm quite glad you actually mentioned using base classes, since it's how I create quite flexible, extensive things.
I was honestly starting to think you were just all about turning everything into interfaces. That's no better than turning everything in C++ into templates. LoL
Yep, just be careful not to use abstract classes to do too much.
Oh yeah, abstract classes can run code.
Actually, that is handy.
Wowwww!!! What an amazing explanation. Highlight is practical examples, which makes this sooooooo goooooood!!!!
Glad it was helpful!
@@IAmTimCorey Is there any possibility for doing videos in C++. It would be really helpful. Consider it as request.
Thank you very much for this video! This was very well explained, I have been able to make good notes from it, and I now feel ready to implement this principle in my future projects.
Glad it was helpful!
Great video!
To speed up things when implementing the interface, one could select the excerpt "=> throw new NotImplementedException()" and CTRL + H then ALT + A 😅
Thanks for theTIP!
Really good and well explained with the code. Excellent work! Loving the series.
Thank you!
Excellent video, thanks for explaining this, I was a little concerned with all the copy and paste of the same code, breaking the S in the series, but completely understand why in the lesson, normally as you said you would create a base class :)
Yeah, possibly a base class or maybe just a single class with the code and then calls to it from the multiple locations. The tough thing is that a lot of the code changes.
In my project we are not following OCP principle properly , we are keeping modifying exiting class and functions. Thanks for this nice video
You are welcome.
Isn't that illogical to put AccountsProcessor inside of person model? I mean, I don't process corporate changes if I am accepted to a company, rather it's done by some external processor upon my person... I feel like these patterns sometimes confuse and mess things up more than provide help.
I get what you're thinking. You're viewing things through a "logical" scope.
The point is that every user has a own account management and not that they make their stuff by themselves.
You're the best teacher. Period.
Thank you!
Nice video, thanks!
I think that writing code with OCP in mind, helps a lot, since it makes code a lot better. But if you start from a project that is already in production and not developed thinking about OCP, it will be really hard to make changes without changing what is already working.
But, even if its working, you have to change code when you want to refactor. And, Unit Tests should be here to help us not to introduce bugs on working code.
The point is, I think we have to write code with this principle in mind, but don't overthink or overdo it.
Thanks for the video, it helped me a lot to clear this concept! :)
Yep, that is very true. You have to be careful how you optimize your code. The key is to make things a little better than you found them.
@@IAmTimCorey Nice advise! :)
I am beginner on .NET which I just started December 2018 but it seems gradually change my style of learning process on how to do full stack .NET web/dev in standard and best practices, all videos are pointing to a very neat and precise coding style. Can't wait new videos from you. Maybe gang of four (GoF) principle? Which I just read 3 days ago.
GoF is coming (at least some of them) in the future.
Very nice video tutorials about the SOLID principles. Really liked and enjoyed. Could not refrain myself from subscribing your channel. Would love to see new things. Thank you very much Tim. Keep it up!!!!!
I appreciate the kind words. I'm glad you are enjoying my content.
Thanks Tim! This video I liked a lot and I learned a lot from it.
Awesome! I love it when people learn something from my videos.
Hey Tim, I've been watching your SOLID videos and really enjoying them but I have one question.
With the way we're structuring our classes, creating interfaces and dealing with inheritance, how would these same classes be stored in a database? Would a table for each be correct? What if I want to retrieve all Persons in my database, then they would be scattered in different tables.
Would we have to define specific database Entities that map our Models and define database relationships through our ORM to get the database structure we want?
I'm used to have more simple models which are easily mapped to a single entity and its respective repository, that's why I'm asking would would be correct to do in the scenarios described in the video :)
Thanks in advance!
At 32:00 you could use “composition” and have ManagerAccounts take an Accounts class in its ctor which calls create. Could also be seen as a decorator.
There are usually different ways to tackle problems in development. This way demonstrated the topic best.
You made a helpful explanation. Thank you, it was easier to understand.
Glad you found it helpful. Thanks for sharing.
I love your videos! I have a quick question: I have bingewatched your SOLID series for a second time to refresh it in my memory, and I can't help but notice that almost all of them favor the use of interfaces. However, I can't help but think that these interfaces implemented without an abstract BaseClass are always violating DRY. For example, here the applicants share some similar lines. It's not that big of a problem here, but in another video (I think it was ISP, with the DVD and Audiobook examples), the modules were sharing the same method but each implementing it on their own with the exact same lines. I just find it awkward to use interfaces because they seem to regularly create moments where you accidentally repeat yourself.
DRY isn't about not having any repetition. It is about not having the same exact logic more than once. The methods may have the same signature, but they may do different things. They may even do the same thing, but in a way that is not guaranteed to stay the same forever. In those cases, they aren't violating DRY. If you found that you did have exact repetition, you don't need to use a base class (inheritance isn't about code sharing, it is about a relationship - if there isn't a strong relationship, you shouldn't use inheritance). Instead, just create a class with a method that both locations can call.
Interfaces are the primary OOP system used in modern development. They give you flexibility, testability, and more.
@@IAmTimCorey Thank you for your thorough explanation, that makes a lot of sense, especially the part about relationship/code sharing, gives me a lot of food for thought. I appreciate you took the time!
Very well explained. I was wondering the same thing..
The best explanation on RUclips!
Thanks!
So with these SOLID principles, are you supposed to use all of them all the time, or pick and choose from them depending on the situation?
Pick and choose. In general, they will almost always apply but they may not always be helpful. You choose what is best for your application. Good question.
I love your chanel. Anyway, for those who don't know, Acme produced the anumation cells and its use in the Road Runner was an in joke by the WB animators.
If it wasn't obvious, I was heavily influenced growing up by their fictional production of anvils, catapults, and coyote-carrying rockets. 😆 Thanks for sharing.
Please create video on design smells and suggested refactoring for each smell
Thanks for the suggestion. Please add it to the list on the suggestion site so others can vote on it as well: suggestions.iamtimcorey.com/
I really like the clear explanation and the examples used. Have a better understanding of open Closed Principle
Glad it helps.
Can you please make an example of a code that implements all the principles at the same time
I would love that too!
Noted and added to the list
Hi, Just want to commend your work. I've learned a lot from you.
Thank you!
15:40 think i will record part Tim saying "oook" and play it, each time i get new task at work haha
LoL - The boss may not see the humor
Tim, Thank you for making this video. Very clear explanation with examples.
You are most welcome. Thanks for watching.
HUGE EXPLANETION!! Like a lot your videos. Greetings from Cuba
Thanks!
Wish you had kept with the same project as your SRP explanation! I want to see you turn spaghetti code into a SOLID project! Thanks!
I tried to keep things as clear as possible for each lesson. I agree it would be cool to do though. Maybe for an "Applying SOLID" course.
@@IAmTimCorey In my opinion, it would be clearer if you used the same project since I already know what's in it and I wouldn't have to learn about the new project and try to imagine how you would implement all the SOLID principles into ONE project! This has been then problem for me. I can't find anyone using the one project thru all the SOLID principles and how the end should look like but instead, I'm given bits and peaces of it and then left to my own imagination to try and implement them all in one project. Problem is, I don't know if I did it right without having a few examples of the completed code in SOLID form!
Bravo, composition over inheritance and use of the strategy pattern ;)
Thank you!
what is composition?
@@Layarion Instead of inherit from a class for the use of certain base functionality. Put that Base functionality in another class and inject it in your constructor) from yout class and assign the instance to a private readonly field.
You can now use the desired functionality by composition (private field with necessary class/functions) instead that you use the functionality because you're in a inheritance tree.
Injection and private fields as Interface types of the desired class for loose coupling, i.e. you can change which implementation of the class you will inject to have as composite.
@@Layarion scottlilly.com/c-design-patterns-composition-over-inheritance/
Hhhm, interesting point but for me that’s only really an argument when your faced with multiple inheritance scenarios (I do appreciate interfaces are preferred to inheritance for OCP and this is a demo so I am being "discussioney" rather than judgy).
A Manager really "is a" Employee, and an Executive "is a" Manager. You really shouldn’t be copy/pasting FirstName/LastName around IMO. Okay, if you are then faced with a new requirement of Salesman (still okay) then a SalesManager (yeesh, possible multiple inheritance) then stuff breaks but, within reason, you shouldn’t design in requirements you don’t have. [digressing now but..] 20 years ago we used to spend weeks or even months meeting around whiteboards designing in what-ifs, only to find not only where they never asked for, 60% of the features they did ask for were never used! Refactoring tools are so quick and powerful now it’s just way better spending that time writing tests instead so you can safely refactor in change rather than spend that time trying to predict future change.
Great instruction. Excellent, practical but not incomprehensible example app/code! Thanks!
I am glad you found it useful.
A big thank you for your awesome tutorials. God bless you. Love and Respect from India.
You are most welcome.
During your lessons i improve not only programming skills, but english skills too)
Great!
Thank you very much !! your example helped me solve a problem in real life
You are welcome.
Great tutorial Tim. I know this video is old but if I can just make a small suggestion for future videos, at the end of these type of tutorials could you perhaps go to program.cs and explain how each line works by opening the classes and interfaces that each line is using. I think it would really help viewers understand how everything comes together. I understood it just fine, but I'm still trying to piece it together in my head. I'm downloading the source code now
I've done this in other videos. I can't do it in every video, though.
I do not clearly understand whats the point of the EmployeeModel class or did i miss some explanation? To me it looks like it is only used to compare all the different IApplicant models. The EmployeeModel must contain the union of all attributes of the different types (namely isManager, isExecutive, firstName, ...) while the models only differ in their AccountProcessor attribute and do not contain any data except what is common among them (names). The accountprocessor just tells you how to create a common "base class" namely the EmployeeModel out of this type by using an additional indirection. Im not entirely sure but cant this approach be simplyfied by using an abstract base class instead of having the EmployeeModel as a separate class, let the different types of employees inherit from it and put the Create() codes into the constructors? You also wont need to change the child classes if you add executive or manager to the base class as these default to false just like in EmployeeModel.
However both approaches do have problems in common:
If we created the executive first and then the manager, we would have had to change the executive because bool does not default to true.
Also Main and EmployeeModel have to always change if we add a new type of person that comes with a new attribute.
Hi Tim. I have a question about the S, not about the O in SOLID (sorry :D but you mentioned it here and it brings me to think about one thing).
As you said - "SRP - Classes should have only one reason to change".
Ok. When we change the way we create an account for a person it is just one reason. But what if we have other methods, e.g. Edit(), Delete() and many others. Then the account class has more reasons to change. When we change the way we Edit account, Delete account, etc. How does it refer to SRP?
P.S. I want to thank you for your videos. You really pushed my learning C# forward :)
That does depend a bit on your interpretation of "reason for change". In order to not go crazy, I tend to think of methods as "one focused reason" and classes as "one general reason" to change. For instance, Person would not need to change generally unless how a person worked changed. Edit would not need to change unless the specific logic was altered.
@@IAmTimCorey I was thinking if SRP could be related to methods in classes, not just to classes. Thanks for your answer, it lightened my mind 🙂
Mesmerizing video. You have made my day.
I am glad it was so helpful.
Hi Tim,
I'm working through your C# App From Start To Finish, and digesting some of these other videos, and this is all great stuff; thanks for this. I'm a long-time VB hobbyist (I can't say I'm a pro developer even though I have quite a bit of code here and there in macros and smallish apps at work) and I'm trying to transition to C# and to think more in OOP. I'm struggling with Interfaces (saw your Interfaces vid) and this compartmentalization of the code. (I come from a world where *everything* was in the frmMain module... ;-) In this particular video, I would have approached it as using an Employee object, and used an employee.ActivateAccount(applicant, empType) method, where the empType is an enum. Then, instead of adding an entire set of interfaces and models for a different type of employee, you just add a new entry to the EmployeeType enum, and add a new entry to your case or switch block to implement differently where necessary. You're not necessarily changing code flow nor are you touching existing logic, but you are adding sections in a somewhat safe manner. I get that this is just a simple example, but if you have to recover from not allowing for different employee types (i.e., a big requirements hole) you're gonna have to tear into some code anyway. Also, while I understand that you should have different classes to represent your various objects, to have different classes to do different *things* seems strange to me -- wouldn't you just implement different methods or properties for the class? I have a nagging feeling that I'm missing some higher level understanding or approach; perhaps you need a few PowerPoint slides after all...
Keep up this great work. I was floundering until I discovered you.
Regards, Renny
The issue with the enum is that you are making changes in multiple places then. Yes, it is only adding logic not altering it (for the most part) but it is a change. Besides, if you make that change and the new part of the enum has a problem, you break existing code. One of the things that will help is practice. The more you see these situations, the more you will understand the long-term implications. This is a rather hard one to jump into when transitioning over to a true OOP way of thinking. Great thoughts though. I'm glad you are thinking it through.
Great series of videos, very helpful, thank you!
If I understand correctly, in your non-OCP approach early in the video you have only one Accounts instance. Once you've applied OCP you have some kind of IAccounts instance for each IApplicantModel instance. If you had thousands of applicants, you'd have just as many IAccounts instances. However, it seems to me you only really need 1 instance of each class that implements IAccounts.
My instinct is to try to model the code on something analogous to real life. Having each person object have an account processor object doesn’t feel natural to me. Perhaps I would have a class to manage applicants (maybe called ApplicantsManager), which would take an IApplicantModel object and give back a reference to an IAccounts instance of the type relevant to the real type of IApplicantModel object.
What do you think?
It doesn't matter if you use an IAccount interface or the Account class instance - either way you can choose how many instances of that class you have. Using the interface does not dictate how you create the object, just the requirements on the object.
Good Explanation with real time
Thanks!
Hi @IAmTimCorey, could one refrain from implementing variations of the Account class, - continue using it how you initially did, i.e.: accountsProcessor.Create(person), and overload its Create() method to take the various (new) IApplicantModel types... effectively all of your improvements are the same, except your variations of Create() are together in Accounts............. and still have "used OCP"? Would this be inferior or just another way to have applied OCP?
That would mean continually changing the Account class, which would violate OCP. It would also be quite messy. There may be certain circumstances where this is the right call (Console.WriteLine has a bunch of overloads like you are suggesting), but in our case it would probably be better to use child classes.
Really great series..."As always"...I come away learning something new.
Glad to hear it!
I come from Java world and I was always curious that, in C# why we like to name classes as XXXModel? What exactly a model class means? Is it a pure data class with getters and setters?
Yes, that is typically the meaning. A model is a class whose primary purpose is holding data.
Good videos! I need to write more code to get into problems which requires this decoupling
Thanks!
Each instantiation of a model(PersonModel, ManagerModel, and ExecutiveModel) call the new operator. Isn't this putting too much work on the GC? I think it will be better if every class, which implements IAccounts, was a singleton. Sure thing, the AccountProcessor property stays, but this way the GC will be relieved. With C++ as my main language, I always watch out for this kind of stuff haha. Also, I love your videos! You are amazing!
There are some semantic changes that you could make to improve the code. But that's not the point. The point is to demonstrate how to add functionality with minimal changes to existing code and this is a very good example.
Thank you!
I just realised that I never subcribed... I am sorry Tim!! Done!
Thanks!