Abstraction Can Make Your Code Worse

  Переглядів 594,327

CodeAesthetic

CodeAesthetic

Рік тому

Support me on / codeaesthetic . Access to code examples, discord, song names and more at / codeaesthetic
Adding abstraction to your code always feels like the right thing to do. But when you add abstraction, you add coupling which can often undermine the value of the abstraction.
#programming #code #design #softwaredesign

КОМЕНТАРІ: 1 100
@charlestolley2294
@charlestolley2294 Рік тому
The one design principle every programmer learns is "Don't Repeat Yourself", and it's not very helpful on its own. I wouldn't broadly say that abstraction increases coupling, but you can't make design decisions simply by looking for repeated code. Your abstractions should represent real concepts in the system that allow you to speak about them using natural language. Done properly, this actually decreases coupling, in a way that not only makes it easy to add new behavior, but also makes it easy to isolate each component for testing.
@matias-eduardo
@matias-eduardo Рік тому
There's an interesting constraint that you can place on yourself that makes DRY good: don't use functions to DRY up your code. It sounds extremely counter-intuitive, but it forces the coder to think about queuing things up and doing them all at once further down the flow. There's a good talk by Mike Acton that can help understand the value in doing this.
@jalendixon5894
@jalendixon5894 Рік тому
Idk what you eat for breakfast but I want some.
@zostaw9421
@zostaw9421 Рік тому
@@matias-eduardo do you remember the title by any chance? I would love to listen!
@matias-eduardo
@matias-eduardo Рік тому
@@zostaw9421 ukposts.info/have/v-deo/qohhfaqNfIybqZc.html
@matias-eduardo
@matias-eduardo Рік тому
@@zostaw9421 I revisit it every year and learn something new. Everything from min 40+ is timeless.
@nikogj9495
@nikogj9495 Рік тому
This video made me recall a book from Sandi Metz "Practical Object Oriented Design in Ruby" where she wrote: "Code duplication is far cheaper (in terms of technical debt) than a wrong abstraction". Even if the book has been published years ago, I still find this sentence particulary true and relevant today. (I advice any curious programmer about OO to have a look at the book, even if you don't code in Ruby, that's my case, or even videos of her).
@cmdrsocks
@cmdrsocks Рік тому
This is wise advice, code duplication is little more effort in most languages than Ctrl-C, Ctrl-V then change external names of the duplicated section. A well-designed abstraction on the other hand takes a deep knowledge of the problem domain and the intended end-user experience of the software. Often decisions about abstractions can only be made using feedback on the behaviour of the code in production. A premature abstraction will cost far more to unwind than the slight loss of efficiency caused by duplicate code. I design software for legal professionals at my current job and we are right now putting in some abstractions that have taken 2 years of use in production to figure out (i.e. will the time and money spent result in a meaningful improvement in workflow efficiency for users?) All textbooks ignore the two great limits in business: time and money. Outside the classroom you never have enough of either to do all the things, so often quick and dirty gets the product delivered to the paying customer and my paycheck delivered to my bank account. There is more inelegant dirty code that would fail any exam on software design out in the world than you will ever want to know about.
@awesomemix7777
@awesomemix7777 4 місяці тому
most of the time I am like: "FU I don't care if it's repetitive (with some minor differences), I am not paid enough to write an error-proof abstract class"
@sfulibarri
@sfulibarri Рік тому
To me this is the most significant difference between new programmers and very experienced ones. Being able to identify and choose the most valuable abstractions in a given context is what drives business value from raw development. Its troublesome because the emphasis on OOP in programming education leads many newer devs to implicitly value abstraction above all while not understanding the complexity they may be incurring. Choosing the right abstractions takes a lot of experience and must be informed by context. Even an apparently 'correct' abstraction may not be the right choice when considering the business context, general experience of the team, and even delivery deadlines; software engineering doesn't happen in a vacuum.
@ecm9251
@ecm9251 Рік тому
I don't believe experience will make a programmer being capable of using abstraction. It takes abstract thinking and it seems like a lot of people struggle with this. Most programmers might never in their live be able to use abstract programming, no matter how long they try. Some will be able to use it with very little experience in programming. It might sound harsh, but we all know that people are different and abstract programming isn't for everyone.
@sfulibarri
@sfulibarri Рік тому
@@ecm9251 Abstraction is one of the 3 basic mechanisms of any programming language. In most common languages once a programmer learns how to write functions or classes they are already using abstraction. Programmers may be better or worse at leveraging abstraction to create better software but the idea that some programmers are somehow incapable of one of the most fundamental aspects of the craft is absurd.
@TheIllerX
@TheIllerX Рік тому
Well written. Especially in those first classes in OOP, one often get the impression that everything should be an abstraction and you should do inheritance structures of everything just because you can. Very little is said about avoiding to create couplings and reducing complexity of your code.
@ecm9251
@ecm9251 Рік тому
@@sfulibarri Your comment is placed under a video that is considered popular. It's popular because a lot of programmers are struggeling with this basic case of a basic concept.
@sfulibarri
@sfulibarri Рік тому
@@ecm9251 Well the video is about one of the pitfalls of making unnecessary abstractions, not about abstraction itself, a person searching for 'what is abstraction in programming' is probably not watching this video. I agree that some may struggle with abstraction in the sense that they may make abstractions that are counterproductive, but you seem to be suggesting that 'most' programmers fail to understand and/or use abstraction at all which is just categorically untrue; any programmer who has ever extracted a few lines of code into a function has used abstraction. In my career I have worked with many jr developers and I never met one who simply could not grasp how or why they should extract a function or class. I maintain that the difficulty of abstraction comes from knowing how and when to use it effectively, not understanding the foundational concept itself.
@AleksanderFimreite
@AleksanderFimreite Рік тому
In my experience. The fun thing about programming, is that it does not matter how much you are aware of. Or how many suggestions you have gotten. You will still end up making regretable mistakes reguardless. Whether this is poorly abstracted elements or just flat out wrong architechture, it always happens. I struggle more with accepting that my code is good enough and actually finish the project when I know I could improve it. Rather than the coupling issues themselves.
@dennisjungbauer4467
@dennisjungbauer4467 Рік тому
I think clear requirements and thinking a bit about what the most fitting implementation seems to be before starting with it can help quite a bit. If you're working in a team and use a ticket system it's rather important in my experience to think tickets through and question them as well before working on the implementation and noticing logical inconsistencies or potential problems that were not touched upon. Thinking a bit about the near future/setting boundaries can help as well finding the balance between abstraction and a more concise/simple but tight code. You can't prevent needing to make changes later on or rewriting some stuff mid-implementation, though, that's par of the course.
@AleksanderFimreite
@AleksanderFimreite Рік тому
​@@dennisjungbauer4467 I'm guessing there also are significant differences between different branches of programming. I work with a small team of game devs. And in the beginning our programmers all discuss togather and agree on benefits and acceptable limits of a system. And then about half a year into development, it turns out our current system did not feel good enough to players. So the designers modify the core specifications 1 month before delivery. Usually with too major differences to justify just a rework. So we end up having to do a half-assed system temporarily and make it from scratch again later. So there are definitely also deminishing returns on planning ahead in my field. We basiclly just do uses imaginable expansions for the current system. Reworks are too unpredictable to support sadly. While I can imagine in system applications, the core behaviour is much more set in stone from the get go, and the front and back end can be dealt with separately.
@SI0AX
@SI0AX Рік тому
@@AleksanderFimreite IMO, reworks should only be done if modifying the existing code will take a lot longer than doing a rework in a different, more modern/efficient language or tool.
@DigitalViscosity
@DigitalViscosity Рік тому
I'm just glad we are out of abstraction hell of 2010, my god every API and codebase back then.
@BramHeerebout
@BramHeerebout Рік тому
I remember when I was taught programming long a ago, one of the first thing the professor told us is that sometimes, maybe often, it is better to start over. Learn to accept that. [edit] And to add to that, abstract classes, especially does that are written with reusability in mind tend to take some time to polish. However, I learned in practice that code often has an expiration date. This 'saver' class is a good example. The xml code gets ditched for json. Don't think the json will last forever. It too will be obsolete. And unless you are working on something like the space shuttle, it won't take decades.
@TinusBruins
@TinusBruins Рік тому
In my experience abstraction isn't about removing repetition, though it does work for it. I think its most important job is to remove dependances. As is in your example with the IntervalSaver. The actual saving might happen in a different library. And you don't want the main code to be dependent on all the possibilities of saving.
@lachlanstanding7386
@lachlanstanding7386 Рік тому
exactly, the class becomes reliant on an interface instead of the actual implementation, thus *reducing* coupling
@StephensCrazyHour
@StephensCrazyHour Рік тому
This. Proper dependency extraction can lead to code that is simple to test. Testable code is good code.
@rybakostis
@rybakostis Рік тому
100%
@leonardomangano6861
@leonardomangano6861 Рік тому
I am mostly against this. Creating interfaces that won't have more than one implementation at the same time are a waste. Except in cases where the code is talking to an external system like an API or a DB. Removing dependencies just to create a mocking hell is not a good approach to me. Test the unit with its dependencies every time you can
@charlesm.2604
@charlesm.2604 Рік тому
@@leonardomangano6861 When you introduce dependency it goes down hill. Even if you only implement your interface in one class, it allows you to introduce loose-coupling in your codebase through Dependency Injection and Inversion of Control which make your project extendable and testable. In other words, when you start implementing new features, instead of coupling the actual implementation you can simply reference to its interface.
@vikingthedude
@vikingthedude Рік тому
I love this style of video where you walk us through various ways the code could be written and weigh their pros and cons. So many teachers either show only contrived examples, or just one big "correct" implementation. But your exploratory way of teaching is so helpful. Please keep making these in this style!
@freedom13245
@freedom13245 Рік тому
3:53 is a good example of polymorphism, a good abstraction that’s worth it would be a Save interface which both classes implement with their different way of saving, and you’d call the save method on the interface so you don’t have to add and “if” statement check the type and using a different implementation for each type
@SamuelLopez-mr5br
@SamuelLopez-mr5br Рік тому
I think it's a good approach, but how will you handle the exception without violating Liskov subsitution principle ? Personally, i think the code smells overall... What I would do is create interface let's call it Saver, then use your GameConfig to store your Saver (new GameConfig() { saver = new SaveXML() }), finally all you have to do in that save method shown in the example is fetch the saver and call some save method with the state and name of the file. This removes the need for an exception to handle invalid save format.
@lachlanstanding7386
@lachlanstanding7386 Рік тому
@@SamuelLopez-mr5br handle what exception? Your XML saving class shouldn't be throwing XML specific errors back to the consumer of your GenericSaverInterface. It should be throwing a GenericICouldntDoIt exception. If your XML saver class can't handle your XML error, what makes you think your GameObject is going to fair any better? Problem solved, Liskov satifisfied.
@RitchieDiamond
@RitchieDiamond Рік тому
@@SamuelLopez-mr5br Catch the specialized errors inside each class and reraise them as an error common to both
@diskpoppy
@diskpoppy Рік тому
yeah, "if" (and "switch") statements scary!
@minhan4444
@minhan4444 Рік тому
@@diskpoppyif you want to avoid if, switch statements, then you can think of strategy pattern or factory method for solving it ❤
@ShilohFox
@ShilohFox Рік тому
In “bad” abstraction like you had shown with the Save classes, coupling can become a problem. The purpose of abstraction is to remove coupling where there could be quicker, easier ways to process and store data as well as provide ways to represent concepts in code. The byproduct of abstraction is removing repetition in data structures. In a case where you’re holding multiple blobs of data, and they all have similar (but not the same) shapes, and the way you interact with them is all the same, abstraction can actually remove coupling by making the handling of that data independent of what the data under the hood actually is. Interfaces are a good example of abstraction that does not care for what kind of data you are handling. In Java, if you want to get a list of objects, then using the abstracted “List” as a return type versus specifying an ArrayList or LinkedList makes the handling implementation agnostic to the underlying implementation, and making changes under the hood does not affect how the code is written in the handling of that data.
@ultimatesoup
@ultimatesoup 8 місяців тому
Yep, abstractions inherently remove couple contrary to what this video says. The video just has bad and poorly thought out abstractions which is why there is coupling. I would have a save interface that takes no parameters. Other classes implement it and any parameters they need to actually do the save are passed in at construction to the subclass constructors. All coupling is removed
@64BitLamp
@64BitLamp Рік тому
In my opinion abstraction isn't necessarily about code reusability. I would argue it's really about shared generics. The big trope that most programmers never learn is abstract to interface coupling. What I mean is defining an interface for an abstraction, and using interface methods within implemented abstract classes. By defining an interface for abstract classes, you can call upon non existent implementations (that the implementor later has to make). Think of it more as "hot swapping black box functionally".
@gloweye
@gloweye Рік тому
The big trope is actually that people abstract far too much. Plenty new programmers hear a couple buzzwords and go ball-deep into making interfaces for every little thing, even if there's no good reason to believe it needs it.
@64BitLamp
@64BitLamp Рік тому
@@gloweye I remember in college they enforce that every class needs like 5+ interfaces. I agree there is no need for this but saying abstraction should be avoided is kind of ignorant. I've worked on codebases that have lived for 20+ years with both scenarios and I can tell you too many are far easier than too few.
@humanrye8696
@humanrye8696 Рік тому
And this by itself takes testability to whole another level. Using example from the video: to test your high level functions you do not need to actually save the file. All you need to make sure (i.e. using mocks) that correct "saver" call was executed.
@muhammadharis2205
@muhammadharis2205 Рік тому
Fuck this interface and class stuff.
@animanaut
@animanaut Рік тому
@@humanrye8696 exactly, fully agree. having proper interfaces almost eliminates the need for some fancy mocking frameworks that do some voodoo like shit (reflections and stuff). if you have an interface you can simply program your own mocks by impementing the interface.
@AlanD20
@AlanD20 Рік тому
I want to say, I agree small codes don't need to be abstracted to interfaces and many inherited classes, such as a todo app don't need 10 interfaces with 20 classes just to achieve the goal. Most people do abstractions because it makes the code maintainable and easier to read with consistent naming conventions. Let's say in your example that you want to add saving as JSON. When someone decides to add this class. First off, you think, what if we need to add another file mode? such as CSV? pdf? HTML? or any other file modes. When you work in a team of people, and each of those implementations has to be done by other people, You are going to use an interface or a parent class, that has all the functionality, and the one who implements the new mode knows what the new file mode must implement and where to implement their code without breaking any changes. Everyone on the team had agreed that the interface has to have a function that returns the file name, another function to save the file, and so on... In summary, it's more about maintainability and working on one large codebase with more than 3 people. Because it will be hard to make communication as someone might use saveAsJSON, someone else might use save_as_json, and someone else goes for saveJsonFile. There will be no consistency and an interface gives the developer a contract to follow those rules without breaking any other codes with no communication, other developers understand how the new file mode must have a function name called save which returns in different file modes. You have to know when and where not to abstract, everything doesn't need abstraction but on a large scale, you have to abstract. Otherwise, you will make the entire codebase a place where no one likes to debug nor to add new functionality because there are so many duplications and you don't even know if those are really duplicate or if they may do a different task but with the exact same process that looks duplicated.
@rcnhsuailsnyfiue2
@rcnhsuailsnyfiue2 Рік тому
Great comment. Interfaces also make unit testing much easier, some frameworks will automatically resolve mocked implementations of things like filesystem drivers to ensure safety.
@AlanD20
@AlanD20 Рік тому
​@@rcnhsuailsnyfiue2 Agreed. Interfaces are very useful when you start implementing Service or Repository patterns in your project. Overall, it makes complex projects that require a lot of maintainabilities much easier to handle in the long term. One thing I forgot to talk about is that most applications nowadays are very complex and aren't meant to be deployed once and for all. One of the most important parts of current application development is maintainability, and how can you grow the application over time without wasting time on redundant complex logic that could've been avoided at the start with better project architecture. Also, another crucial and significant parts of any project's development is the extendability of prior features without breaking them.
@SkyLee91
@SkyLee91 Рік тому
Yes abstraction or interface, will help you to maintain the code in future. Yes it will be coupling but it is what we want right? If you get the handover source code from someone and you want to fix a bug that happened at Saving, you will look at FileSaver base class and see which are the child class, analysis the impact of changes. If your design s individual class as shown in the video, you need to change each of the individual classes' method one by one, which is what we saying DONT REPEAT YOURSELVES.
@wydx120
@wydx120 Рік тому
You could use a wrapper that transparently chooses between the different savers, you know. No need to create a skeleton abstract class without any meaningful shared logic
@AlanD20
@AlanD20 Рік тому
@@wydx120 You missed the point. I explained why there will be a need to create a skeleton abstract class.
@tonnoz
@tonnoz Рік тому
I usually try to avoid inheritance as much as possible and use composition instead. By embedding functionality you can still retain the meaning of "shared functionality" while separating the differences in separate classes. Of course only if it's worth it. The code you shown are a good example (more than two choices etc.).
@JamesPhipps
@JamesPhipps Рік тому
This. Inheritance is one small part of OOP programming that somehow became the dominant aspect instead of polymorphism, composition, and encapsulation which were the focus of its original advocates. I’m not a big Uncle Bob guy but he’s dead on about this.
@cryp0g00n4
@cryp0g00n4 11 місяців тому
There is nothing wrong with inheritance. Even a composition maybe a type of base class with a standard interface. The key is to decompose and organize functionality at a data/protocol level... that is work with properly describing the data and then focus on the protocol (i.e., abstractions etc). Just think OSI model... perfect example of proper design principles. All design principles come from the desire to elegantly design protocols.
@aoeu256
@aoeu256 10 місяців тому
@@JamesPhipps You can have "polymorphism" in Python, JS,Ruby,Lisps(Clojure), Smalltalk by just passing in functions and passing arguments through, ne need to use inheritance, classes, or even even interfaces. def save(saveFunc=Save.XML, *args)
@jayocaine2946
@jayocaine2946 5 місяців тому
@@cryp0g00n4 there is everything wrong with inheritance if you're writing a shader, and in a lot of cases with systems programming, hell even game programming inheritance adds extra bloat. Like anything else in life and programming, it all depends on the situation and talking about some general idea of "inheritance" and "abstraction" is really quite useless and only intermediate devs do it
@ttcc5273
@ttcc5273 3 місяці тому
I once wrote a file parsing toolkit that relied heavily on inheritance. It was super powerful and you could parse new formats with just a few lines of code. The only problem was that I was the only developer who knew the hierarchy well enough to write those few new lines. Lesson learned: inheritance is great when you are the one designing and using the thing… but it leads to systems that require a big cognitive burden to approach from the outside-in. Composition has proven to be more useful and other-developer-friendly. Subunits are easier to mentally visualize than graphs of inherited functions. A flat library of functions is easier to use than a vertical tree of functions that have nuanced differences depending where the caller lives in the hierarchy.
@mcmillanator
@mcmillanator Рік тому
It's so easy to get this wrong and can be difficult to teach to someone else. You've done a great job at explaining it clearly and simply. Thank you.
@maybepumpkins
@maybepumpkins 4 місяці тому
The "Rule of Three" is a good counterweight to "Don't Repeat Yourself" The idea is that you need at least three examples before you can decide what a good abstraction would be. If you try to write an abstraction too soon, you might abstract around concepts which turn out to be not very useful.
@super0spore0fan
@super0spore0fan Рік тому
I think the major problem is that it seems the code wrote on the video favors inheritance over composition. Had the FileSaver class follow a bridge or strategy pattern, with the expected interface of the implementation component being something like "Save(fileName)", It would have worked better. Then, SaveToJSON would be one possible implementation, and the user would use FileSaver directly with either a default implementation or one of his choosing from the library we created. With dependency injection, he could create his own implementation to save files in any format he desires
@aoeu256
@aoeu256 10 місяців тому
Java supports higher-order functions now, maybe try using them although you will have need pass through for arguments.
@alexmercerind
@alexmercerind Рік тому
I'm so glad I discovered this channel. I think I'm early, watched the two videos. I'd definitely love to see code architecture & structuring related videos.
@RyanBrockey
@RyanBrockey Рік тому
This channel is great. I'm a hobby programmer and I find each of your videos very instructive and encouraging. Thank you. I'm looking forward to your next video!
@erlend1587
@erlend1587 Рік тому
Good video, but there are other ways of abstraction then inheritance, you could use composition, and create a component based system. You also don't need to make classes for everything, you could just make a function to handle some specific parsing. Not thinking too much ahead and being pragmatic about the code you write (keep it simple), often makes the code easier to reason about and later refactor when it changes.
@user-bk4gx9zh5v
@user-bk4gx9zh5v Рік тому
Also thought about composition. (?)Something like StateSaver(stateSerializer).save(filePath, gameState)
@muadrico
@muadrico Рік тому
Exactly. Of course, choosing the wrong abstraction will lead to code that is worse.
@crownstupid
@crownstupid Рік тому
This is 100% right. The terrible thing that inheritance does to your mind is that it makes you want to cram everything into the same hierarchy of "things". (i.e. "File Savers") In this example, all the little pieces like the "periodic" file saver and the different file formats, and even the "streams" that the bytes are sent to from the conversion should all be interfaces that are composed together.
@sir_no_name1478
@sir_no_name1478 Рік тому
Searched for this comment
@iantaakalla8180
@iantaakalla8180 Рік тому
Then what is inheritance good for? Inheritance is talked about but then every other instance of inheritance seems like it’s poorly-thought-out interfaces or something akin to that.
@codingbloke
@codingbloke Рік тому
Nice one! Completely agree with this! There is a difference between "repeating the same logic" and "by coincidence having the same logic currently". Spotting the difference can be hard but if you eliminate the apparent repetition of the latter you can find the code becoming less malleable . It can perversely be a source of bugs. Class A shares some logic with Class B. Class A doesn't behave correctly because there is a "bug" in the shared logic, however this "bug" is only truly a bug from the point of view of Class A, for class B it is perfectly correct. So you fix the bug, now you have broken Class B and its hard to know you have done that unless you check also Class B (and C, D...). Even with strong automated testing that newly introduced bug in Class B may go unnoticed. Also when shared logic is no longer compatible with all consumers there is a tendency for ugly `bool` values to appear in parameter lists and the code becomes harder to understand and even more bug prone.
@TheMyHalo
@TheMyHalo Рік тому
I just found your channel and love both videos. Really hope youre going on with this style
@yassay5854
@yassay5854 Рік тому
Good looking Channel, short format, single subject, calm ton & relaxing background music, visual/ easy to understand/synthetic examples & explanations, this is probably gonna be a killer channel, glad to be here at the begining of the story, whish you the best :)
@klikkolee
@klikkolee Рік тому
I think separating the ideas of abstraction and repetition helps a lot to choose good abstractions. Abstractions are supposed to guide your field of view to whatever is relevant to a given part of code. If one part of your code needs a means of saving a game, but doesn't need to know how it's done, then an abstraction for saving a game is beneficial. From the perspective of what code changes guarantee the need for other changes as a matter of being able to compile the code, an abstraction will always create coupling. But if the abstraction was a good choice, then from the perspective of what code changes are required for the code to continue being sensible, that coupling already existed. The abstraction just enforces it. A good choice of abstraction can also reduce coupling of both kinds from other parts of the code -- a Saver interface means that code that uses Savers can have just one variable and from its perspective one code path regardless of how many types of Saver exist. Lastly, a good choice of abstraction pushes coupling into islands of relevance where you can readily see what depends on what and why. Code that just needs a Saver and doesn't care which Saver still needs to get a Saver from somewhere, and that somewhere needs to contend with the different reasons one might be chosen over another and needs to contend with the needs of creating individual savers. That is coupling, but it's coupling that would've been diffused through the code base without the abstraction. I am struggling to make sense of your Saver example. I just cannot think of a situation where I would have multiple methods of saving something but would not have a part of the code that shouldn't care which method is employed. That is a situation that is impractical to accommodation without an abstraction. This situation also means the example of wanting to change the interface of just one does not make sense. If the code using savers does not need these additional features, then adding those features to any savers is unused code. If the code using savers does need these additional features, it probably needs them regardless of which kind of saver it is told to use, meaning that it needs to be added to all of the savers -- regardless of whether there is an actual in-language interface that enforces the change. I don't choose what I save and how I save based on the serialization format -- I choose the serialization format based on what I save and how I save. If a given serialization format or some other aspect of a saver isn't compatible with the new needs of the rest of the code, that saver is getting the boot.
@thommekm
@thommekm Рік тому
I just wanted to say that I really like your presentation style - working with examples from real use cases and showing how the code changes. That is very helpful and easy to follow, good job!
@yrds96
@yrds96 Рік тому
You know this channel is good when it's 11 days old and already have 17k subs with only 2 videos.
@lachlanstanding7386
@lachlanstanding7386 Рік тому
this video is only useful as an example of the kind of logical circles you can run around in if you don't understand SOLID principles. Please don't follow the advice in this video.
@ecm9251
@ecm9251 Рік тому
@@yrds96 That's not good, that's popular.
@jeromesimms
@jeromesimms Рік тому
This is so insightful, it really brings together what I have been learning in my Software Design and Development course. I subbed and would like to see more videos like this
@AnotherFancyUser
@AnotherFancyUser Рік тому
First and foremost, I recently saw your videos, I love how you make them, I like the aesthetics of the edits and I like how you educate about these concepts, so kudos to you, I'm subscribed. Now, to me abstraction means more than just create classes and hide implementation details. Abstraction to me also means the usage of interfaces and the elimination of 'new' which ties your classes together (Tight coupling). Your FileSaver.Create method is still coupled to concretions like AWSSAver, SaveXML, etc. You could make the FileSaver where T is an IFile or a representation of something needed to save, that type T knows how to save itself because the "can do" contract is about implementing the Save method, after that you have different approaches, you can either use a factory pattern to make the concretion or better yet use a container that contains all the types something like services.Add() etc, and you can even change the abstraction on runtime, after that FileSaver can be much more, you can have an IEnumerable of files to save them, you can create a queue that saves them following a CRON or saves them using hangfire, etc, so you can use composition and have this IEnumerable as a property to do whatever you need. To me, the idea of abstraction should be there to talk about them as it is things in the real world (concepts or physical objects), if you can say them speaking using language then you can do it properly. Now, one rule of thumb I would use is... don't start with abstractions, start with the code all over a single piece of method and from there start the refactoring process, no duplicate code, separate things into methods, group behaviors and reasons to change into classes, etc., I don't think starting abstracting is a good idea, the main reason is because an implementation can change in the future because that Jira or whatever feature you are creating can change tomorrow.
@AnyVideo999
@AnyVideo999 Рік тому
This is the situation at my work right now. Crazy balance between coupling and abstraction to deal with custom requirements growing. Every vendor has a different workflow and customers all want very unique things. It was once very coupled on the vendor side but we've broken it up a bit now.
@gr0nis
@gr0nis Рік тому
I would suggest using composition over inheritance and also use more functional style programming. It’s much easier to have abstraction that way without locking yourself too much into coupling imo.
@davidmartensson273
@davidmartensson273 11 місяців тому
All have their merits and knowing more ways can make the code better. Fully functional is only really worth if with a language/compiler that can use the fact that the code is functional to optimize the compilation. If your using a more traditional language, functional constructs can still help improve code but some of it can also be much less performant since real functional languages use many hidden optimizations that a non functional language cannot apply.
@aoeu256
@aoeu256 10 місяців тому
I was thinking doing it like this in Python/Ruby/JS (simple dependency injection?). def save(saveFunc=Save.XML, *args, **kwargs): ....# do some stuff with args and kwargs ....result = saveFunc(*args, **kwargs) # pass all other arguments straight to this func ....return somefunc(result) , the save method would do a bunch of stuff then call your saveFunc using keyword arguments (which are objects) that are automatically passed to your saveFunc. This reduces coupling, but you need intergration tests to make sure code is exercised but your program will probably have errors anyway if you don't do testing, I believe this is "message oriented" OOP programming.
@notreallyasloth
@notreallyasloth Рік тому
Your videos are so good. Can’t wait to see what you do next ❤
@tally3018
@tally3018 Рік тому
Just found ur channel. Looks like ur doing absolutely great after only 2 weeks uptime! Subscribed!
@ciberman
@ciberman Рік тому
I REALLY love this way of showing code. Explaining what are you doing while showing a speed up video of the changes.
@thelatestartosrs
@thelatestartosrs Рік тому
The base class for the filename does not create coupling to a filename, that was already there, if you didn't want the saver to save to a file its not the base class' fault. If anything, if when trying to abstract you think it creates a problem it means you already had a problem before. in case anyone didn't get it the problem is that XML has little to do with the file, in other words a saver needs a saving strategy like file or db and that strategy needs an optional format. say `new Saver(new DBSavingStrategy(db_handle))` or `new Saver(new FileSavingStrategy(file_handle, file_format))`.
@jonan.gueorguiev
@jonan.gueorguiev Рік тому
Great approach for the craft of programming! I really like the incorporation of the word "aesthetic" - I've found it myself that beautifully working code _is_ better. So, on the topic of abstraction - a broader generalization of what you've shown us, is that - if an abstraction is created to capture common ground from inside - implementation, tools, libraries, etc - it is usually unnecessary coupling. On the other hand - when abstraction tries to capture common view from outside - i.e. from those who _use_ the code, then it is usually OK, because it actually introduces a generalization, a true abstraction, and not just a code-duplication-removal.
@chrismingay6005
@chrismingay6005 Рік тому
Great video that puts into words things I've felt for a while! I'm working on a project thats heavily abstracted on multiple levels. While there is less code overall it's very difficult to pick up, you get no sense of flow and it's a pain to debug. It feels like overly abstracted code makes it more and more difficult to stray from the beaten track and eventually you will have to.
@chrishamilton1728
@chrishamilton1728 Рік тому
I think you're talking about inheritance more than abstraction. Interfaces or abstract classes are a way to hide implementation details and actually decrease coupling. Inheritance / extending classes is what increases coupling.
@mmaldonadojr
@mmaldonadojr Рік тому
As I mainly write firmware for microcontrollers in C, my main criterion for abstracting or not a piece of code is whether this will save on memory. Maintainability is then a close second (may be prioritized over memory if the amount of memory saved otherwise is small). Elegance that's not essential to maintainability comes third. Embedded programming is quite a fun field!
@meatbleed
@meatbleed Рік тому
that's awesome
@aoeu256
@aoeu256 10 місяців тому
Instead of coding in C, why not code in Rust or LISP and use Lisp macros as a super-powerful compiler generator... Also there is an option to inline functions or not, and often not inlining functions can let the code fit in cache.
@jayocaine2946
@jayocaine2946 5 місяців тому
@@aoeu256 because why would you do that? lol, C is the king
@friedrichwaterson3185
@friedrichwaterson3185 Рік тому
Such an awesome thematic ! I hope your channel grows fast.
@ktvx.94
@ktvx.94 Рік тому
There're times when coupling is good. Sometimes you _want_ to update something that changes all children classes simultaneously, instead of keeping track of which ones need the new code and manually changing it every time. If you forget, different entities that should have the same behavior start behaving differently. That said, I fully agree with everything else.
@foible2085
@foible2085 Рік тому
One consideration might be the skill level of other developers on your team. Delaying abstraction only until the benefits outweigh the coupling might mean you will encounter a huge mess the next time you need to work in this area of the code due to all the cumulative changes from the team. Setting up the abstraction early will encourage better design for future changes even if it may seem over engineered in the interim.
@Bluedragon2513
@Bluedragon2513 Рік тому
For instance, in a game, I might have to implement a global EXP multiplier for certain days of the week. Rather than having a variable be directly accessed in 60 different functions, I should just abstract the EXP variable to be handled by a class, allowing a global EXP multiplier to be more easily maintained within that single class. I think?
@matthewvandenheuvel8401
@matthewvandenheuvel8401 Рік тому
For some projects a senior dev who was very used to working with architectures used to lay the basics, he would then relay it to me for the implementation. I'd always be lost at first but I always ended up understanding the reasoning later, and the motivation too as some other projects were deeply ingrained in that whole coupling mess. So I'd totally agree with that, it's better to conceptualize and plan early so that you don't end up building on a mess
@SamuelLopez-mr5br
@SamuelLopez-mr5br Рік тому
yes abstraction can be great tool for design especially if paired with TDD.
@matias-eduardo
@matias-eduardo Рік тому
It's funny because most beginner code is decent code. It's when you start getting "mid-to-high" skilled developers that things go bad. It takes time to "unlearn" all of those "best practices". People tend to interpret complexity as sophistication.
@rangedfighter
@rangedfighter Рік тому
@@matias-eduardo Well, in a programming class or when learning most of the time you work alone. Once you have a bunch of full stack programmers, each of which with different favorite/main languages and paradigms or simply different ways of thinking, that stuff goes south more than 0% of the time. Or when you have too much "democracy" and 20 different decisions that don't all fit together get made. So you have no coherent design of the whole programm, but a mess of concepts.
@cal-overflow
@cal-overflow Рік тому
Great video. I think we as developers need to often stop and ask ourselves, "am I over-engineering this by implementing it this way?" Instead of just assuming they're doing the best work because it's a common practice. Otherwise it often causes immense headache when another developer (or even the person who designed something) need to refactor or change something. Thank you for bringing attention to this overlooked topic!
@kaiserouo
@kaiserouo Рік тому
This video decribes me toooo well. After learning OOP and design pattern stuff I am always thinking about "how" I can abstract something, not "when". And that indeed screw things up a lot later.
@sandropollastrini2707
@sandropollastrini2707 Рік тому
You just coupled in my mind all the abstractions I did in the past by this abstract framework of abstraction-coupling. I will abstract no more in the same way, being now coupled to your ideas.
@_Aarius_
@_Aarius_ Рік тому
Interefaces are also important to consider. in this videos examples, you could have as many diofferent types of savers as you want, with one bit of logic to determine which to use, that all share a common interface, and then set up a way to check if its using interval at runtime and set the hook for that, for example. But, interface design is tricky, and you can end up with extra coupling where a certain method doesn't make sense for a particular implementation...
@ucantSQ
@ucantSQ Рік тому
I just watched you videos on naming variables and nesting code. I ran over to see what other videos you had and realized how new this channel is. Keep it up! This will be super useful to anyone new to programming. You bring out subtleties and nuances in coding that I myself have struggled with, but never given voice to. It's reassuring to hear that repeating code is ok, because in some cases it feels much more natural to do so, but I tend to feel some bizzare responsiblity to generalize when possible. Even though I'm writing code solo, for myself.
@exploringgodscountry
@exploringgodscountry 6 днів тому
I need to hug you! It's INSANE how much abstraction is going on. I am trying to learn Android OS API / programming. The examples I find are abstracting interfaces already designed in the API. Obfuscating the underlying "Source of Truth" in the logic. Programmers seem to have fallen so much in love with coding their own classes that they code data types over the top of datatypes just for the sake of loving their own coding style and not much more thought. Case in point, 20 years ago graduated as a computer engineer. Code was closer to hardware level. Now that's all abstracted. It's good we don't have to code the hardware interfaces but it's to the point the code for interfacing with hardware is MUCH more complicated than the hardware itself. Have we really gained anything in that process? I used to look at a datasheet and then write the code. What I needed was right in front of me to write my program. Now you interface with code to request access to hardware from the OS. In many instances that interfaces / code is scarcely documented... even if it is well documented you run into unknown dependencies and some degree of uncertinty in how the code interacts with the hardware. Many times there's tens of pages for a software interface (sometimes 100+ pages of documentation), when I used to deal with only a few page datasheet on the hardware resource. I don't think we've really made much progress to be honest with all this abstraction. There is definitely a balancing point and I feel we've far exceeded it to the point of too much code.
@stuartferguson11
@stuartferguson11 7 місяців тому
A saver class is probably going to call a save method on the game objects, and provide methods for writing state values like numbers, strings, etc. In that case using an interface (abstract class in C++, protocol in Swift) would be my choice. Both savers can conform to the interface without sharing any code.
@VitorMach
@VitorMach 2 місяці тому
One mistake I commonly see is people try to abstract away pieces of code that only coincidentally repeat, but that isn't inherently equivalent. This is closely related to the single responsibility principle and separation of concerns. Code might be similar, but if they have different reasons to change, they do not belong under the same abstraction.
@Imevul
@Imevul Рік тому
The problem in the example is really that the different savers have too much responsibility, namely both serializing the game state to a certain format, and also writing it to some kind of storage. This would make much more sense if you had an XMLSerializer and JSONSerializer that only did just that: take some input data and convert it to the correct format, then return it either as a string or a stream. Then you would have a GameManager that uses one type of serializer (DI) to facilitate the whole logic of "saveGame", and one or more storage connection classes (also DI), for example. In the end, you would end up with two interfaces: Serializer, Storage And several single purpose classes: GameManager, XMLSerializer, JSONSerializer, FileStorage, SqliteStorage, etc.
@natenez
@natenez Рік тому
Completely agree. And maybe use the strategy pattern if the serializers need separation between. ‘Walk the data structure’ and “emit the serialized blobs” code
@animanaut
@animanaut Рік тому
good video. one question you can always ask yourself is: what is the blast radius of this change. having code duplication can be a good thing if you want to reduce the blast radius. "do i want to break y when i fix this for x". sometimes, instead of abstracting something away to a library, just leave it where it is until you really need to abstract it. "YAGNI" can be perfectly applied to pre mature abstractions ("you aint gonna need it")
@chordfunc3072
@chordfunc3072 Рік тому
Please make more videos, I love this so much!
@astronemir
@astronemir Рік тому
I usually find that good abstraction reduces coupling. I always aim to reduce coupling in my refactors and in my design. Having that as a goal works way better than anything else.
@not_vinkami
@not_vinkami Рік тому
As a math student and a programmer, I'd say doing abstractions is like doing factorization When you see a few terms, like x²+2x, you can factor it into x(x+2), which makes some further actions simpler because you have separated components to work with. However, this isn't always the case to do. For example, x²+1 isn't that good to be factored to (x+i)(x-i). This only made your original polynomial messier. This is so similar to code abstraction in the way that, you have to identify what's worth abstracting, and how it can help in further applications. Doing abstractions in already very simplified code only gives coupling, just like the x²+1 case I've mentioned. You can just call it not factorable (not abstractable) and peace out.
@mrsharpie7899
@mrsharpie7899 Рік тому
Small correction: it's (x^2)-1 that gets factored into (x+1)(x-1)
@not_vinkami
@not_vinkami Рік тому
@@mrsharpie7899 what are you even correcting?
@JakoTheWacko
@JakoTheWacko Рік тому
@@not_vinkami I believe they’re unaware that x^2 + 1 = (x-i)(x+i) and they’d assumed you’d meant x^2 -1 = (x-1)(x+1)
@iantaakalla8180
@iantaakalla8180 Рік тому
To be fair, when you really want to emphasize the imaginary answers of x^2 + 1, that factorization is useful.
@trollnat9857
@trollnat9857 Рік тому
As a physicist, sometimes (x+i)(x-i) is a useful factorization for (x^2)+1, but I agree that in most cases you're better off not factoring into imaginary components. And I think that's very apt for abstraction, even edge case abstraction can be useful, but outside of the edge case you designed it for the usefulness does not justify it.
@tobyjacobs1310
@tobyjacobs1310 Рік тому
I've definitely seen both scenarios, as well as the one where over-abstracted code losses all meaning. That said I've also had the experience where accession reduces coupling, because dependencies drop off. This is especially true when using DI.
@DynamicalisBlue
@DynamicalisBlue Рік тому
It works well when you program in a way where you only need to know about the interface. Saving by interface makes it way easier to transition to another save format later down the line. If done right, you can change one line of code and now your entire code base is using a different file format.
@TheGamezbePlayed
@TheGamezbePlayed Рік тому
The value in not repeating code is for the sake of maintainability. If you fix a bit of code that is shared across multiple functions you can be prone to miss all the spots that need updating. I typically dont let functions do more than "1 thing". I also am not doing OOP anymore. When a function does "1 thing" then its easy to generalize functions that can be generalized and functions that need to be hyper specific can be hyper specific
@ArnabAnimeshDas
@ArnabAnimeshDas Рік тому
If I have multiple functions I place them in one separate file.
@aleixlopez5600
@aleixlopez5600 Рік тому
Just found your channel, you've a new subscriber, really like the dedication to some topics related to clean code. Could you do a video about your take in OOP, second level inheritance, MVC and how what's been considered good practices has been changing through the years ?
@TheIllerX
@TheIllerX Рік тому
Thanks for the video and for bringing up this topic, which I think is massively overlooked in general. In school and the early years of programming one often get the impression that "Code duplication is bad, must do abstraction" without ever thinking about coupling issues and about creating unnessecary complexity in the system. Sure, code duplication might be bad, but that doesn't mean more abstraction is the solution, especially if the abstraction means more inheritance structures in some object oriented language. I have often been swearing at old code that cannot be upgraded or modified just because the thing I want to modify is stuck in some strange structure with a lot of dependencies/couplings. Some contained free utility functions doing one thing and doing exactly what it is said to do without any couplings to other code is often a better alternative to more abstractrion. In that way one can avoid code duplication without increasing the couplings. Coupling really is an enemy to all upgrades of the code. Everyone will become more and more hestiant to do any changes since it might break something. In that way they whole codebase has a big risk of becoming obsolute and out of date.
@IIIWhiteBoyIII
@IIIWhiteBoyIII Рік тому
Awesome video format! Keep the great content coming!
@LordErnie
@LordErnie 3 місяці тому
To be honest, good abstractions aren't made because you want to limit duplicate code. Sometimes two processes, even though they are completely unrelated, do things the same way. That doesn't mean that they should share an abstraction. Sometimes things just look alike. The point of abstraction has never been, and will never be, limiting code duplication. It is all about sharing contextual abstractions. Hey I need to read an XML file to this format. That is translated to wanting to read a file that is in a format, and translating it to specific type X. That is an abstraction. Abstracting an account and a vault because they both have passswords isn't. Sometimes two or more things just look alike, but they aren't the same, even though they do things in the same way. Never abstract to limit duplication, abstract because you want to introduce flexibility to your system.
@Yupppi
@Yupppi Рік тому
What do you think about abstraction in the terms of readability? What I mean is when the naming is on point (on top of your logic in abstracting things), you can read the "headlines" of the code and it divides into very understandable blocks and chunks and functionalities for human brain, and you quickly get a grasp of the big picture. With a lot of repetitive coding you're a bit in the jungle trying to see the forest from the undergrowth, you're whacking with a machete left and right trying to piece together the general picture of repetitive sections, you're creating the library of structure in your head.
@DuniC0
@DuniC0 Рік тому
Hi, this is a very interesting topic with a really short conclusion in my opinion. I see trading between abstraction and coupling as an oversimplification. There are multiple ways of fighting coupling and code repetition: abstraction as in inheritance, better abstraction with interfaces, composition, bridges, callables/runnables/callbacks/closures, proxies, event driven programming, etc.
@Frankenstein786
@Frankenstein786 Рік тому
I think you need a lot more videos! So much value!
@yuryzhuravlev2312
@yuryzhuravlev2312 11 місяців тому
If you start using langauges with optional classes (python, C++) or without classes (go, rust) all this becoming even more interesting! Basicaly, in most cases you shouldn't make abstractions at all, it's needed in rare cases. Procedure decomposition much better in many common cases, and OOP (especial with classes) can help in some corner cases only.
@insomnia20422
@insomnia20422 Рік тому
Could also be the other way around that due to poor abstraction you need to change code in a lot of places. I think the coupling thing is mostly an issue if you have poorly designed code that needs to be reworked. So the solution is, dont design your code poorly.
@YuriG03042
@YuriG03042 Рік тому
so what you are saying is: skill issue
@eidiazcas
@eidiazcas Рік тому
Agree
@tobiasbergkvist4520
@tobiasbergkvist4520 Рік тому
Except you typically don't know where you want your coupling to be, and where you don't want it ahead of time. So start with repetition first, and then create abstractions later once you notice you want to change things at the same time.
@rutabega306
@rutabega306 Рік тому
Yep, I think it is good to ask "Is coupling desired here?", and often the answer is "yes".
@sgerodes
@sgerodes Рік тому
Please dont stop creating content. Your videos have amazing value
@sahandjavid8755
@sahandjavid8755 Рік тому
Most of my time in companies I worked for goes into convincing engineers not always repeating is bad! If you have only 2 cases for your found pattern, it doesn’t mean you need to create shared code! If you don’t have a complete insight over your problem or future requirements do not abstract!! Thank you for the video, The idea is to grow together and then we can do great things.
@TheKimpula
@TheKimpula Рік тому
Great video! I tend to agree with you. Love the presentation. Looking forward to what you're planning on creating next.
@kunodragon4355
@kunodragon4355 Рік тому
I've never run into any system that suffers from overcoupling. Instead, I've often had to deal with systems that have copypasta code galore, dozens upon dozens of lines, and then when a feature needs changing, and it needs to happen everywhere, you gotta go and find all instances of this code and modify it X times, and test each one, because sometimes they have subtle differences and...
@RCL89
@RCL89 Рік тому
I feel you. Too much repetition hides the subtle differences and buries the underlying structure of the code - its business logic. Even if you only need to change one place, understanding the code and finding the right place to change is hard. Without a good structured/abstracted code, e.g. with everything inside one big KLOC function, you don't find what blocks are relevant for you or which ones to ignore, because it's too much to parse by your brain at once.
@perchful3872
@perchful3872 Рік тому
Dude! I love this video!! I think especially for less experienced engineers like me, this kind of thinking is ABSOLUTELY what takes the longest. Thanks for the video!
@zeckul
@zeckul Рік тому
Abstraction *through inheritance* creates coupling. Once you mostly let go of class hierarchies and choose to program using data types and functions instead, most of these issues go away by themselves.
@mexico14000
@mexico14000 Рік тому
Been debating about abstraction in my both my React and API code. On one half, I enjoy knowing how each function's flow. On the other, I like writing less. I haven't really touched OOP recently, but I'm trying to avoid it as functional programming is something I prefer working on in the future.
@DanDanDandelion
@DanDanDandelion Рік тому
Well with higher order functions you are welcome back to the world of abstraction :)
@mexico14000
@mexico14000 Рік тому
@@DanDanDandelion Yeah but it's less code regardless. I worked with functional programming on Scala and rarely passed 50+ lines of code for basic college assignments.
@jacobkirstein4798
@jacobkirstein4798 Рік тому
I think an often overlooked benefit of abstraction is that, if done properly, it makes understanding code simpler.
@JamesPhipps
@JamesPhipps Рік тому
Yup. If you’re in a large org writing shared libraries or frameworks and you don’t understand abstraction you’re not going to have a job for very long. If you’re on a small team and insist on “pre-factoring” so much I need to have six files open just to figure out how I’m going to handle the response from an API endpoint let alone update models/UI then you’re not gonna have any friends.
@ZahrDalsk
@ZahrDalsk Рік тому
However, his examples use inheritance, which makes understanding code needlessly harder. Never ever EVER use inheritance if you can avoid it, use composition instead!
@aaronclement1266
@aaronclement1266 10 місяців тому
This came at a good time for me. I'm rewriting my game engine's code and I have felt the effects of coupling without really understanding what I was doing wrong.
@Nerdsown
@Nerdsown Рік тому
Excellient video. Very succient. I have recently been attempting to reduce coupling by allowing for some repetition but I hadn't come across someone else in favour of it yet. In fact I have recently encountered the exact save and load scenario you did. I have a SaveFileReadWriter which manages 2 other ReadWriters (JSON and legacy XML). These are intentionally completely decoupled. We need to always attempt to reduce cognitive load on the next person. So we need to ask ourselves, if we change logic in one, how likely is it we will want to make the same change to the other? If its unlikely, then abstraction would mean we need to check that we didnt accidently change the other more often then not. So its increasing effort, not decreasing.
@creo_one
@creo_one Рік тому
Cant wait until he discovers Dependency Injection and Interfaces, then learn to use it properly... until then, he will rediscover whole OOP piece by piece
@TheDesttinghim
@TheDesttinghim Рік тому
Thinking about the data you have and what you need to do to it is more important than figuring out abstractions. Figure out what data you actually need to perform the work and write code to operate on that struct. This is the main idea behind data oriented design
@rutabega306
@rutabega306 Рік тому
Wait is this really your second video? It's excellent quality, subscribed!
@hvaghani
@hvaghani Рік тому
Subscribed immediately! Btw what theme are you using? it looks very clean.
@keokawasaki7833
@keokawasaki7833 Рік тому
Don't abstract away code, abstract away the idea
@redlancer7263
@redlancer7263 Рік тому
I would love a video about file system structure! I know its always going to be different between projects but I know there are common patters with /src, /docs, /bin, etc. Are there principles we should be following as to not get too nested or too shallow in our file structure?
@blueghost3649
@blueghost3649 Рік тому
Just do what makes sense for your project, any convention for this would be dumb since every project has different needs
@TruthAndLoyalty
@TruthAndLoyalty Рік тому
Ui rules" apply here. If you have navigation menus, it will take a long time to find what you're looking for if you have a lot of levels with a lot of generic split paths that end up hard to navigate. On the other hand, good luck finding a file in a completely flat directory for a sizable project. This is a version of "the hardest problem in programming is naming things". Only nest when you have a logical group with an accurate name and doing so would make it less difficult to navigate. Don't nest things just to "organize". Start with very broad understandable groups. Keep things wide unless there's a good reason not to.
@redlancer7263
@redlancer7263 Рік тому
@@TruthAndLoyalty Awesome, that makes sense. I hate digging through pages and pages of game UI or inventory dividers but I like that all my weapons and armor are grouped. Thank you!
@LonetrackTV
@LonetrackTV Рік тому
your videos are amazing, keep it up man
@Vdherrlichkeit
@Vdherrlichkeit Рік тому
Glad I found your Channel. Excellent content.
@AI-Effect
@AI-Effect Рік тому
Code is an art and a state of mind. I think that abstraction can't be learned, some feel it and some never, even with years of development. This is what differentiates an excellent programmer from others, an author of widely used libraries, frameworks, languages from others. Very good visual quality of the video, can't wait to see where this channel will take us.
@katto1937
@katto1937 Рік тому
Everything can be learned, nobody is born with knowledge or natural aptitude towards programming abstraction.
@02orochi
@02orochi Рік тому
@@katto1937 agree w first, disagree w second some take longer to learn certain concepts than others
@5cover
@5cover Рік тому
I disagree. There has to be an objective way to write better code, and avoid common pitfalls.
@katto1937
@katto1937 Рік тому
@@02orochi Maybe at first, but over an entire career this will completely even out as you will be very slow at learning other things. And the huge majority you learn faster because you've already done something similar before. Search up the violin study on natural proficiency vs hard work.
@lachlanstanding7386
@lachlanstanding7386 Рік тому
no, it's very much a science, with rules, that you can learn. This is just what people say when they haven't learned them yet.
@ZachHixsonTutorials
@ZachHixsonTutorials Рік тому
What you're referring to here as abstraction seems to mostly just be inheritance. Abstraction deals more with making sense of raw data. EX: instead of remembering 3 numbers and an image, we group those together and call them a "GameObject," since it's easier to think about that way. Instead of calling 5 seemingly unrelated network functions, we wrap those up in an "UpdateServerState()," function because it makes more sense to read.
@Outfrost
@Outfrost Рік тому
In oop terms, abstraction _is_ inheritance (and traits/interfaces, if they're separate in your language). Sure, we can call any struct or collection an "abstraction layer", but it doesn't help us reason about code architecture
@ZachHixsonTutorials
@ZachHixsonTutorials Рік тому
@@Outfrost Reasoning about code architecture is literally what abstraction is. Abstraction is in every language. It's the act of naming and structuring things to give context to the code architecture in a way that "abstracts," the mental model away from the implementation, thus implementing a layer of reason into the system. In the context of OOP abstraction is sometimes defined as the act of exposing/hiding properties and methods within a class, which still has nothing to do with inheritance.
@Outfrost
@Outfrost Рік тому
@@ZachHixsonTutorials ok purist
@natenez
@natenez Рік тому
While inheritance is one form of abstraction, others forms exist. A DateTime class is an abstraction, regardless if it doesn’t inherit from anything. Private methods, with good names of course, can (but not always) be abstraction. Really the title of the video should be something like Bad Class Hierarchy Design Makes Your Code Worse. Which of course is true. And given there are lots more ways to design a bad hierarchy than good one, most of the ones developers deal with are closer to the bad end than good one.
@cassandrasinclair8722
@cassandrasinclair8722 8 місяців тому
Counter argument for the "save" interface. Instead of choosing or constructing; pass the object as a Save Object, i.e. do dependency injection.
@slephy
@slephy Рік тому
Thanks for sharing this! Perhaps slightly off topic, but one thing I'm (quickly) starting to discover is that even though I may have cleaner, compact and more readable code, it may not necessarily run faster. Being specific and taking the time to type out exactly what I want to happen when I can be specific may take me more time to do, but it performs faster than, for instance, looping for a solution. (This is Mike Action's thesis in a nutshell really.)
@JordanDavidson3102
@JordanDavidson3102 Рік тому
For me it's all about defining abstractions that couple the code in a useful way. In other words if there's code that when it changes, by definition (not by convenience) must change in all places then it should be coupled and therefore abstracted.
@matias-eduardo
@matias-eduardo Рік тому
I agree. One way to think about it is that you're moving the coupling/complexity (or, more concretely, the things that need to happen and the order in which they need to happen to transform the data) to an isolated place (for example, a single enum) so that the rest of your code doesn't need to "think" about those things. It just needs to "do the thing". This is also why programming languages with proper reflection are so powerful, they can enforce things to happen in your code at compile-time so that the implementation itself does not need to "think" about it. To me this is what good de-coupling means. You move complexity to few places where you actually need to "think" about it, and the rest is just writing implementation code.
@riahmatic
@riahmatic Рік тому
"identifying repetition and extracting it out" is honestly a junior/mid level understanding of abstraction. What you've described are the dangers of inheritance. The real power of abstraction is realized when you starting thinking about interfaces, layers, and domains. E.g. separation of concerns is achieved through abstraction ,and that decreases coupling.
@yutubl
@yutubl 8 місяців тому
I made best expierience implementing data specific serialization (also save + load) methods in each class which data/attributes have to be serialized/saved/loaded early in the software project. 0. when your software architecture class design is stable enough (no daily complete redesigns keeping you away from implementing these classes) 1. serialization methods for saving and loading keeps you back from re-implementing new file format methods per each class which has to be serialized it data attributes (DRY). I think a good serilization method interface might support parameter for: 1.1 storage/file/stream method/functor parameter implementing file format; 1.2 content filter method/functor parameter selecting which object internal data attributes; 1.3 if you always serialize per each class / object a specific version in the saved file format, building and maintening downward compatibility to your 1st (experimental) early file formats versions are possible, so you don't need to throw away saved file contents, giving you options of converting into latest file format version. Here a defined default class constructor and default class loader with exact default values per attribute helps. 2. your project development process benefits early from saveable (and re-loadable) classes, 3. all testing become much easier: manual tests get faster and you can begin automated test code.
@zyansheep
@zyansheep Рік тому
If it was me and I wasn't limited by OOP abstractions, I would create an interface (trait) "Saver" that contains an associated type "Resource", a "constructor(Resource)" and a "save(GameState)" method. And then just pass a specific implementation of "Saver" to the Game object.
@jonohiggs
@jonohiggs Рік тому
I think the missing piece is that inheritance is the only method of abstraction presented, and no mention of composition. GameObject is not great because it is typically implemented with inheritance but a better solution is ECS which is a compositional / data-oriented pattern, the same concepts are abstracted but in different ways
@zyansheep
@zyansheep Рік тому
@@jonohiggs absolutely, OOP-style inheritance is an outdated form of abstraction...
@benbertheau
@benbertheau Рік тому
i just love your animation style very simple and stylish
@adolfolecumberri3643
@adolfolecumberri3643 Рік тому
Man, it's wonderful to watch your videos
@techkev140
@techkev140 Рік тому
Seriously good points about abstracting away common functionality. However i had to watch through a second time as the highlighted code did not always standout. Trying to take in everything on screen when the surrounding code was blurred out, i found the highlighted code you were talking about didn't standout and i only focused on it as you moved on to your next point. The second viewing of the video was better as i knew what i was looking for in your examples. Good video, thoughtful.
@Whelknarge
@Whelknarge Рік тому
I learned to code on the job over the years, I don't have an academic CS background, and I've often noticed benefits of the academic training some of my colleagues received that make me kind of wish I had done a CS degree. That said, I have also notice a tendency in them to follow certain rules and conventions blindly, having been taught that that is the "right" way to do it. Everything you've said in this video just seems like common sense to me, it wouldn't occur to me that I "must" always avoid every scrap of repetition as a rule - repeting code is bad not just because it's "wrong", it's bad because I have to maintain more code, so the more I'm repeating the worse it is. But obviously, having the code defined separately in each class means I can change one without affecting the others. So I do whatever I feel is the best cost-benefit solution for my case. If you understand why these things are good or bad, you don't need formalised rules for when you should or shouldn't do something because it's common sense.
@RainbowVision
@RainbowVision Рік тому
I disagree with the save example, because you want to provide a unified way of saving and loading your game to an arbitrary file format. The other components are not responsible for knowing how the game is saved, just that it's 'savable' (so interface)
@eidiazcas
@eidiazcas Рік тому
Agree, the ugly abstraction was the problem, not abstractik itself, thats why we need composition ans dependency injection
@jebwatson
@jebwatson Рік тому
I really appreciate the thought that abstraction and coupling are opposing forces. I've never considered it from that perspective and I think this will help me when designing future systems.
@Nicholas-qy5bu
@Nicholas-qy5bu Рік тому
Abstraction can also be used to reduce coupling with dependencies, but i totally agree with you when you are designing your "business/game" logic it can increasing coupling which can be dangerous without any actual benefits. One other point you didnt mention is with generic purpose classes, if not designed/used correctly it can make the code harder to understand for what use cases it is used for. A simple exemple i can think of is using the same generic entity with a 'type' property to handle differents use cases, instead of having one entity for each, i see this a lot, and it create its own lots of problems ( storage and data manipulation ), while forcing you to use switch statement in your code base which is not a good idea for maintainable code.
@aidenkim6629
@aidenkim6629 Рік тому
The 3b1b of code :)
@encapsulatio
@encapsulatio Рік тому
Not really. There are others I can think of that have even higher production animations.
@aidenkim6629
@aidenkim6629 Рік тому
@@encapsulatio Even if the production isn’t the same quality as a channel like Reducible. I found his explanations to be straight forward and logical.
@mody1710
@mody1710 Рік тому
Cool stuff. I think one important thing to consider here is that abstraction doesn’t increase overall coupling per say. In your example, with no abstraction the coupling will now happen with the rest of your code interacting with your saver, and I don’t know if that’s a better scenario. Architecture flows so the whole breadth of how the system works matters. The goal is to lock your features for modification, so removing the XML saver for example won’t break logic in multiple other classes needlessly that were already tested. This is why the dependency rule is probably one of the most important rules to stick with. Your application should be split into layers, where there’s a saving top layer, for example. That layer should manage the bottom layers where you might have any variety of savers. That way, the rest of your code doesn’t care what happens when you save. It only knows to call a standard method on the top layer. That way, it truly doesn’t matter if you abstract your savers or not, because their lifecycle will be managed in a single place and any number of changes to the savers won’t result in changing code in unrelated features, which is often the way developers introduce bugs to existing functional features.
@gustavoberwanger1412
@gustavoberwanger1412 Рік тому
I clicked the thumbnail thinking "what bs is this?" and finished the video and now I know where all my frustration comes from. Thanks for showing us something so easy to miss
@JosepPi
@JosepPi 3 місяці тому
The way I usually go about this is, by default, having different scripts with duplicate code. The moment I try to do something with those scripts in which an abstraction could help me do it faster, I stop whatever I am doing, and create that abstraction. There is a little downside to this which is that you have to create all the systems from the beginning and not really overdevelop one side of the app without making sure the rest is in a basic state and interconnected. This way, you can catch these potential abstraction classes early and you don't have to change a lot of things. I don't see this working for bigger applications, thought. Actually, today, I had to do this in my tower defence game. I was creating one script for all the turrets, another script for all the barracks and another script for all the farms. Then I had to create a very basic UI and realized if I had a building parent class that contains the name, description and cost of every building, I could save me some time developing it their UI. We will see if in a year, I regret this decision, but for now it does feel great to find these little shortcuts.
@Zoomakroom
@Zoomakroom 4 місяці тому
Abstraction doesn't increase coupling when used properly. Abstraction hides complex ideas behind simpler ones. There is nothing simpler about inheriting from a FileSaver class if the only thing you share is the filename. This poorly chosen example feels like too much of a straw-man and I think you're doing people a disservice by confusing an example of bad object-oriented design with the idea of abstraction, which has no inherent relation to OOP.
The Flaws of Inheritance
10:01
CodeAesthetic
Переглядів 869 тис.
The Ultimate Tier Programming Tier List | Prime Reacts
26:57
ThePrimeTime
Переглядів 275 тис.
Teenagers Show Kindness by Repairing Grandmother's Old Fence #shorts
00:37
Fabiosa Best Lifehacks
Переглядів 23 млн
didn't want to let me in #tiktok
00:20
Анастасия Тарасова
Переглядів 1,8 млн
0% Respect Moments 😥
00:27
LE FOOT EN VIDÉO
Переглядів 38 млн
SOLID Design Principles Made Easy
4:36
Carrio Code
Переглядів 3,2 тис.
Dear Functional Bros
16:50
CodeAesthetic
Переглядів 427 тис.
Abstraction Bad? | Clean Code : Horrible Performance : (Clip) Interview
7:39
how NASA writes space-proof code
6:03
Low Level Learning
Переглядів 2 млн
Every CSS Animation property
9:26
chunkydotdev
Переглядів 41 тис.
Never install locally
5:45
Coderized
Переглядів 1,6 млн
Don't Write Comments | Prime Reacts
14:31
ThePrimeTime
Переглядів 196 тис.
Premature Optimization
12:39
CodeAesthetic
Переглядів 743 тис.
How principled coders outperform the competition
11:11
Coderized
Переглядів 1,5 млн
Naming Things in Code
7:25
CodeAesthetic
Переглядів 1,9 млн