Every time I see these videos, it's always arguments about the verbose nature of OO code, code that's only used in one place being inefficient, etc. And every time, these projects are dissected as if they were in a complete vacuum. He appears to be going for larger projects now due to previous criticisms that he's tackling over-simplified examples. Despite his obvious coding talents, his analyses show someone who doesn't work on large numbers of similar and/or recurring projects, and someone who doesn't work well on a team.
Procedural code for large projects can be a nightmare to maintain with a team, it takes longer to onboard new team members, and it is more difficult to document in a comprehensible fashion. There's a reason that enterprise code is more generally OO. In the long run, in large teams, and on large projects, OO code saves time and money.
Yes, until now he mostly took toy examples and considered them as if they were in a vacuum - completely missing the point of the example.
But he has raised a few very good points that I - as someone who HAS worked on a large number of big, complex projects with similar / recurring elements - have encountered and agree with:
In OO, who should be responsible for the interaction between two objects? "Functions" sound like a better option than "randomly choose one of them" or "create a new interaction object". Example: readline between an std::istream and an std::string in c++.
Sometimes - more often than I would have liked - I suddenly need access to the functionality of an inner object of an inner object of an inner object of the object I can see. The solution is annoying: create a set of "proxy functionality" for all the objects in the hierarchy. That is bad because: (a) I now need to create a ton of new tests for basically nothing, (b) I now need to "change the story" of each of these objects to explain why having that functionality makes sense with their "design" and (c) it's just a ton of extra code for something very small.
"Design", or "what does this thing I need really mean" is an interesting and fun exercise, but when you just want something that "works", it's an annoying distraction that costs you money. How many times did you have code that actually did what you wanted perfectly, but you had to rewrite it from scratch because you found a better "design"? It happened to me very often. Is it worth it? In OO it's essential. But if it was programmatic? I'm not sure you need it then.
Small things make sense as objects - like strings and such. But even with strings - strings! - the rigidity of objects is creating problems. Want to add a "write on change" functionality where sub-strings are very cheap? Oh, sorry, your original design called for iterators to be persistent when changing a character. So you now can't do that very important thing that would have helped a lot and make some code substantially faster. Even when some people don't use iterators. Because OO. Too bad.
In your first bullet point, I think object interaction is solved nicely with a registry system. In cases where the objects are logically interweaved but also distinct I'd go for a manager system. As for the second bullet point, since the functionality in question is clearly at least semi-general usage why not remove it from the lower class and place it your general utils library for the project?
For the string problem, I'm probably missing something but if you want a string type specialization why not simply inherit/extend the class? Alternative in C# there are expansion methods where you can actually extend the functionality of a class without actually creating a new class. It's a neat and clean solution as well. It would require a new interface, but I think when the behavior may be different than what people expect that's actually a good thing.
You do bring up some valid arguments. I'm definitely not saying that you should always follow OO practices all the time for all purposes. Blindly following ANY ideology all the time is generally a bad idea.
In your first bullet point, I'd recommend strongly against picking one of the two original objects to handle interactions in most cases. While adding a bridge object can be a little verbose at times, it preserves reusability. You could also extend one of the original objects and add the code for interaction there if it makes sense, which would ensure that you're following SOLID.
I'm not sure I see the issue with your second bullet point. Object1.object2.object3.method() should work if the method is publicly available. If it's protected, then it adding getters for the functionality you need shouldn't be a huge task and would only need minimal testing, assuming you had already written tests for the internal objects. Am I missing some other use case here?
If I have code that works, I don't rewrite it just because there's a 'better' design. The only time I'll rewrite working, bug-free code is if I'm creating new functionality that may use old functionality that's not general enough, or if I have to copy and paste it too much, creating a maintainability issue. If there is a need to generalize, abstract, or refactor code, I'll do it. Otherwise, rewriting for the sake of purity and perfection is an exercise in futility.
Your final point just seems like a development problem--not because of bad programming, but just because the original developer didn't see future use cases and performance issues that may pop up later. This isn't limited to OO. @rwbj makes a good point as well in that you can extend the object and override things that don't make sense for your case.
Will hasn't demonstrated noteworthy coding talents that I can recall. He strikes me as someone who has studied and practiced long hours to gain the knowledge he has.
If anything, his talent may be in making programming appealing to newbies. That's obviously not what he's doing here.
You just have to translate opcodes into whatever library you are using for video / sound / device support. The mods that you are executing already have the hard stuff built in, they handle their own data structures, manage memory, all designed around clock speeds that are magnitudes slower than what is possible with a modern CPU.
The comment about "navigating a file that is thousands of lines of code is a nicer problem than navigating lots of small files" seems insane. Given a modern IDE it's akin to arguing a book without a table of contents is better. Finding references, going to method definition, etc are all literally a matter of one key press and you get the benefit of a file hierarchy that can be made more granular and clear. It reminds me of people that argue against incrediblyLongVariableNamesAreBad because it's more typing, yet with a modern IDE it's comparable (and often less) typing than ilvnab with millions of times more clarity. He's also not really considering maintainability/extension and code reuse.
Or, even simpler, it'd be like comparing a series of books that approach a topic various ways, but are individually light reading and easy to cross-reference - to a book that's 3 times the width of a phonebook & its glossary is spread through the entirety of the book.
The comment about "navigating a file that is thousands of lines of code is a nicer problem than navigating lots of small files" seems insane.
It sounds like the opinion of one who uses a text editor instead of an IDE. Having written OO in text editors, I'm convinced that slow and heavy IDEs won't be displaced any time soon.
I watch these videos with an open mind because I'm always interested in learning something new. However, I think I'll stop because his arguments always seem to be "I don't like this style of programming". Which is rather ideological as opposed to actually USEFUL.
What specifically are the performance gains? THAT'S the 300 pound gorilla in the room. Writing smart OOP VS smart procedural, you will be hard pressed to get much of anything.
The whole sub-function to minimise the footprint of the library is a superficial point which can be solved using private functions. Public functions are the only thing someone needs to be aware of. Making a private function into a sub-function doesn't solve anything. It just moves code around. On a related note, D language has the sub-function use case he is looking for in a language.
I'm not on Team OOP, or Team procedural. But, I don't think I'll be wasting my time on Brian Will any more. Not that he's WRONG by any measure. It's just that he doesn't have much of substance to say.
The whole sub-function to minimise the footprint of the library is a superficial point which can be solved using private functions. Public functions are the only thing someone needs to be aware of. Making a private function into a sub-function doesn't solve anything. It just moves code around. On a related note, D language has the sub-function use case he is looking for in a language.
If anything, I feel like his choice to use "subfunctions" just validates the OO model. "Here's a function that isn't generally useful to the program as a whole, but is required to perform these operations on this data." Sounds like a private method to me.
FWIW I don't think Will is altogether wrong in his conclusions. It seems to me that the way we do OO right now is not as useful as it could be. Every OO program I've ever written has been at least 5 times larger than its procedural equivalent, and the source code bloat didn't buy me much in the way of maintainability. But that's just me.
I'm not a real programmer, but nice clickbait title? I still see advantages to both. His complaints don't sound significant enough to just drop OO for C. If OO gets more people coding right away, then it's worth it just for that. We can move on to C from there.
I can see how one might think that, but Will has been building his case against OO for years. The title might be sensational, but it very much reflects his views.
23 comments
7 u/nice_tie 22 Mar 2016 06:43
Every time I see these videos, it's always arguments about the verbose nature of OO code, code that's only used in one place being inefficient, etc. And every time, these projects are dissected as if they were in a complete vacuum. He appears to be going for larger projects now due to previous criticisms that he's tackling over-simplified examples. Despite his obvious coding talents, his analyses show someone who doesn't work on large numbers of similar and/or recurring projects, and someone who doesn't work well on a team.
Procedural code for large projects can be a nightmare to maintain with a team, it takes longer to onboard new team members, and it is more difficult to document in a comprehensible fashion. There's a reason that enterprise code is more generally OO. In the long run, in large teams, and on large projects, OO code saves time and money.
3 u/Men13 22 Mar 2016 10:12
Yes, until now he mostly took toy examples and considered them as if they were in a vacuum - completely missing the point of the example.
But he has raised a few very good points that I - as someone who HAS worked on a large number of big, complex projects with similar / recurring elements - have encountered and agree with:
In OO, who should be responsible for the interaction between two objects? "Functions" sound like a better option than "randomly choose one of them" or "create a new interaction object". Example: readline between an std::istream and an std::string in c++.
Sometimes - more often than I would have liked - I suddenly need access to the functionality of an inner object of an inner object of an inner object of the object I can see. The solution is annoying: create a set of "proxy functionality" for all the objects in the hierarchy. That is bad because: (a) I now need to create a ton of new tests for basically nothing, (b) I now need to "change the story" of each of these objects to explain why having that functionality makes sense with their "design" and (c) it's just a ton of extra code for something very small.
"Design", or "what does this thing I need really mean" is an interesting and fun exercise, but when you just want something that "works", it's an annoying distraction that costs you money. How many times did you have code that actually did what you wanted perfectly, but you had to rewrite it from scratch because you found a better "design"? It happened to me very often. Is it worth it? In OO it's essential. But if it was programmatic? I'm not sure you need it then.
Small things make sense as objects - like strings and such. But even with strings - strings! - the rigidity of objects is creating problems. Want to add a "write on change" functionality where sub-strings are very cheap? Oh, sorry, your original design called for iterators to be persistent when changing a character. So you now can't do that very important thing that would have helped a lot and make some code substantially faster. Even when some people don't use iterators. Because OO. Too bad.
1 u/rwbj 22 Mar 2016 11:06
In your first bullet point, I think object interaction is solved nicely with a registry system. In cases where the objects are logically interweaved but also distinct I'd go for a manager system. As for the second bullet point, since the functionality in question is clearly at least semi-general usage why not remove it from the lower class and place it your general utils library for the project?
For the string problem, I'm probably missing something but if you want a string type specialization why not simply inherit/extend the class? Alternative in C# there are expansion methods where you can actually extend the functionality of a class without actually creating a new class. It's a neat and clean solution as well. It would require a new interface, but I think when the behavior may be different than what people expect that's actually a good thing.
0 u/nice_tie 22 Mar 2016 17:42
You do bring up some valid arguments. I'm definitely not saying that you should always follow OO practices all the time for all purposes. Blindly following ANY ideology all the time is generally a bad idea.
In your first bullet point, I'd recommend strongly against picking one of the two original objects to handle interactions in most cases. While adding a bridge object can be a little verbose at times, it preserves reusability. You could also extend one of the original objects and add the code for interaction there if it makes sense, which would ensure that you're following SOLID.
I'm not sure I see the issue with your second bullet point. Object1.object2.object3.method() should work if the method is publicly available. If it's protected, then it adding getters for the functionality you need shouldn't be a huge task and would only need minimal testing, assuming you had already written tests for the internal objects. Am I missing some other use case here?
If I have code that works, I don't rewrite it just because there's a 'better' design. The only time I'll rewrite working, bug-free code is if I'm creating new functionality that may use old functionality that's not general enough, or if I have to copy and paste it too much, creating a maintainability issue. If there is a need to generalize, abstract, or refactor code, I'll do it. Otherwise, rewriting for the sake of purity and perfection is an exercise in futility.
Your final point just seems like a development problem--not because of bad programming, but just because the original developer didn't see future use cases and performance issues that may pop up later. This isn't limited to OO. @rwbj makes a good point as well in that you can extend the object and override things that don't make sense for your case.
0 u/effusive_ermine [OP] 24 Mar 2016 02:42
Will hasn't demonstrated noteworthy coding talents that I can recall. He strikes me as someone who has studied and practiced long hours to gain the knowledge he has.
If anything, his talent may be in making programming appealing to newbies. That's obviously not what he's doing here.
5 u/effusive_ermine [OP] 22 Mar 2016 05:03
Personally I'm surprised to learn that a working NES emulator can fit in under 10k lines of OO code.
0 u/Tecktonik 22 Mar 2016 21:51
You just have to translate opcodes into whatever library you are using for video / sound / device support. The mods that you are executing already have the hard stuff built in, they handle their own data structures, manage memory, all designed around clock speeds that are magnitudes slower than what is possible with a modern CPU.
5 u/rwbj 22 Mar 2016 09:08
The comment about "navigating a file that is thousands of lines of code is a nicer problem than navigating lots of small files" seems insane. Given a modern IDE it's akin to arguing a book without a table of contents is better. Finding references, going to method definition, etc are all literally a matter of one key press and you get the benefit of a file hierarchy that can be made more granular and clear. It reminds me of people that argue against incrediblyLongVariableNamesAreBad because it's more typing, yet with a modern IDE it's comparable (and often less) typing than ilvnab with millions of times more clarity. He's also not really considering maintainability/extension and code reuse.
2 u/Majatek 22 Mar 2016 10:08
Or, even simpler, it'd be like comparing a series of books that approach a topic various ways, but are individually light reading and easy to cross-reference - to a book that's 3 times the width of a phonebook & its glossary is spread through the entirety of the book.
I'm calling elitist on this one.
0 u/CirdanValen 22 Mar 2016 18:13
Found it! Man that was hard, I need a drink.
0 u/effusive_ermine [OP] 24 Mar 2016 02:37
It sounds like the opinion of one who uses a text editor instead of an IDE. Having written OO in text editors, I'm convinced that slow and heavy IDEs won't be displaced any time soon.
1 u/Master_Foo 23 Mar 2016 00:32
I watch these videos with an open mind because I'm always interested in learning something new. However, I think I'll stop because his arguments always seem to be "I don't like this style of programming". Which is rather ideological as opposed to actually USEFUL.
What specifically are the performance gains? THAT'S the 300 pound gorilla in the room. Writing smart OOP VS smart procedural, you will be hard pressed to get much of anything.
The whole sub-function to minimise the footprint of the library is a superficial point which can be solved using private functions. Public functions are the only thing someone needs to be aware of. Making a private function into a sub-function doesn't solve anything. It just moves code around. On a related note, D language has the sub-function use case he is looking for in a language.
I'm not on Team OOP, or Team procedural. But, I don't think I'll be wasting my time on Brian Will any more. Not that he's WRONG by any measure. It's just that he doesn't have much of substance to say.
0 u/effusive_ermine [OP] 24 Mar 2016 02:26
If anything, I feel like his choice to use "subfunctions" just validates the OO model. "Here's a function that isn't generally useful to the program as a whole, but is required to perform these operations on this data." Sounds like a private method to me.
FWIW I don't think Will is altogether wrong in his conclusions. It seems to me that the way we do OO right now is not as useful as it could be. Every OO program I've ever written has been at least 5 times larger than its procedural equivalent, and the source code bloat didn't buy me much in the way of maintainability. But that's just me.
0 u/8bCvYq2vpg 22 Mar 2016 18:24
I'm not a real programmer, but nice clickbait title? I still see advantages to both. His complaints don't sound significant enough to just drop OO for C. If OO gets more people coding right away, then it's worth it just for that. We can move on to C from there.
In short, I don't see why OO is complete garbage.
0 u/effusive_ermine [OP] 24 Mar 2016 02:30
I can see how one might think that, but Will has been building his case against OO for years. The title might be sensational, but it very much reflects his views.
-2 u/SlappyHo 22 Mar 2016 16:02
Sorry, I didn't have 52 minutes to watch some guy bitch about how he doesn't want to learn modern programming techniques.