“The Clean Code Talks  — Inheritance, Polymorphism, & Testing”
Articles Blog

“The Clean Code Talks — Inheritance, Polymorphism, & Testing”

>>HEVERY: Thank you guys for coming. By the
way, these are the new and improved code quality talks. We have Dave Astle who’s done a great
job revamping them and so these are the new and improved ones. So if you’ve seen him before,
come again and we’ll do it again. Is it not–oh, I have to talk over here, huh. So haha. I’m
so used to the clip-on microphone that–thanks for reminding me. Okay. So, today we’re going
to talk about basically conditionals and polymorphism and how that affects testability. So here’s
the premise and this is a bit of a crazy premise. And that is, back in a day when we went from
the basic world, it’s not even procedural languages, what are they called? Well, the
basics of the world into procedure world were able to get rid of go to’s. And I don’t think
anybody has really missed them. So here’s a crazy thought and that is if you go from
procedural languages to object-oriented languages, you can get rid of quite a few if statement.
I’m not going to go as far as say all of them but for the most part you can get rid of most
of them. It’s actually kind of fun to see if you can try writing code without an if.
It’s a very unique way of writing code. As a matter of fact, there’s even certain languages
out there like Smalltalk were the concept of if doesn’t even exist. It’s not–it’s not
part of the syntax of the language. So, why would you want to get rid of an if statement?
Here–well, the thing is that code without ifs are easier to read. And I don’t think
anybody can really argue with that, right? If you can just read code straight, you know,
do A, do B, do C, do D, that’s pretty clear what’s happening. Whereas if somebody says,
well, I’ll do A but then sometimes the B, and some other times the C, and then maybe
you do D, well, it’s kind of confusing as to–under what condition, what’s happening
and what’s the output? And so, because it’s easy to read, it also turns out that functions
without if statements are easier to test. As a matter of fact, you only will need the–probably
one test, maybe a couple of tests for exceptions but for the most part, one test will do because
there really is only one execution through your code for this particular function. And
as a result of all this, polymorphic systems or systems that do not use if statements tend
to be easier to maintain, easier to understand, easier to extend, and therefore our–those
are all properties of things that we really like and we look for. So, once you–how do
you get rid of if? I guess is a better question. As you get rid of if by using a polymorphism
in its place, where as you dispatch into a method whose binding is not known at compile
time, right? This is good old polymorphism were you have a class and a subclass, and
you have two different instances and when you say print, it’s not clear whether you
are printing to the printer or printing to the screen because it’s a PDF. So, you want
to use a polymorphism if the objects should behave differently based on its state. And
we’re going to talk about an example of what that means. And you should also use polymorphism
if you have to check the same condition in multiple places. This usually happens with
flags were you want to enable debugging or disable them and your code is sprinkled with
all bunch of if statements saying, if this flag is enabled then do this extra stuff over
here. So let’s have a look. But before we go there, I want to point out that there are
certain places were you cannot get rid of an if. If you’re comparing, if three is greater
than seven, there’s no other way of doing it other than an if statement. So for comparison
of primitive types with a lower case int as supposed to the uppercase integer, you really
have no choice but to use an if statement. But, we know we’re not going to focus on that.
We’re going to focus on where the business logic should behave differently, that’s the
interesting part. Also I want to point out that if you are–if you really want to be
if free in your application, the thing you have to do is you got to make sure you don’t
return the Nulls. And you kind of talked about it earlier in earlier talks how Nulls are
your friends inside of your test but really your enemy inside of production code. You
really don’t get in a situation when you return Null because when you return a Null from a
method, you can’t dispatch off on a Null. You’ll get a NullPointerException. And so,
what you need is–you need to put an if statement over there to make sure you don’t dispatch
a Null. And that clutters your code. And so, we want to get away from that. So you simply
want to always be in the situation were if you have a method, the method needs to return
some kind of an object that probably doesn’t do anything. Typical example of this would
be like the Null Logger. If I need to log, I’m always logging except sometimes I get
a re-logger that logs the file system and sometimes I get a logger to just eats all
my messages and doesn’t do anything. But, not always good and great, you got to be careful
not to go on crazy with subclassing. When you have deep inheritance hierarchies, that
creates problems from not just testability, also from understandability and a couple of
other abilities probably as well. So, it’s a very fine line between, you know, getting
rid of your ifs and at the same time not turning your application to one ridiculous comp–inheritance
hierarchy. So, let’s look at the first case where you can get rid of an if. And that is,
getting rid of–in case of we have state based behavior. This is quite common. If you for
example have a conditional that chooses different behavior based on its type. Typically the
way this thing happens is you have some kind of field inside of your object and then based
on whether this field is said or a flag, you’d be headed differently. And really what we
want to do is we want to say, okay, when this flag is on, all of the stuff that happens
differently should really go into a subclass and when the flag is off, all the stuff that
happens in the flag is off should go into this other subclass and then the common logic
stays in the super class and that way we can separate the ifs from the non-ifs, or from
the flag turned on from the non-turned on, simple stuff. You know, this is described
in the Refactoring book, so by all means, if you have one of those, we do suggest you
read it and you’ll use it as a reference. But let’s go and look at an example of what
this thing would look like. So suppose we have a method such as, you know, get speed
and it does a switch operation and on a switch operation, we return different things. This
is typical things that people do inside of their code. Any suggestions on how to improve
>>HEVERY: Subclasses, exactly. And, you know, don’t we already have a type system? Like,
if you’re switching in a type or the type of bird you are or anything like that. And
based on that, you’re doing different operations. We already have a subclass system, and so
we should take advantage of this thing. And so, you know, solution for this is quite obvious,
right? You have your base class, bird. And you have your European, Norwegian, and African
swallow and then you can subclass it out and have different behaviors and different locations.
So, this is–my favorite questions I love to give on interviews. I don’t know if any
of–I don’t think I’ve interviewed any of you guys in the audience, but the premise
is very simple. You have a mathematical operation such 1+2*3. And you want to represent this
as a tree. So, as a tree, it will look like this. And I’m sure you guys are all familiar
with this. And so I would like to have a way to have storing this in memory. So I need
to have some kind of a class, let’s call it a node which stores this tree and then I want
to perform operations on this. And to–for the purpose of the example, let’s say we want
to perform evaluate method on it which computes the result. In this case, two times three
is six, plus one is seven, right? But, while I’m going through the examples, I want you
to also think about the typical class such as node would do other things such as toString
operation, let’s say. And a toString operation should print us the tree, placing the parenthesis
only when necessary. But, you know, a real class could have lots and lots of other methods
that can do lots of other things. So, once you get into a real, real class situation,
the issues you’re going to see in the next couple of slides are going to be even so much
more important. So just keep an eye on them and just keep thinking as, how this would
effect your toString method as I go through the evaluate method? So when I have an evaluate
method that computes the result of an expression, you know, pretty straightforward stuff. And
what we want to do–when you give this problem to most people, this is what the solution
they come up with is. They say, I have a class node and I’m going to have an operator on
it which basically says, whether I’m a plus, multiplication, division and so on. And then
I’m going to have a value which is the number that I represent. I’m going to have the left
child and the right child, and my evaluate method would then have a switch statement
that switches on the operation I am and then perform the operation you want. Now, keep
in mind how the toString method would mimic this, right? You have toString method in order
to get the infix notation printed, would essentially mimic your switch statements here. But there’s
actually a bigger problem with this. Before we go there let’s kind of do graphical representation
of this, right? So you have your node as we point out, we have your four fields and one
evaluate method. And this would represent into a structure such as this. Notice a couple
of weird things in there. Our leaf nodes still have the left and right child and they’re
pulling thing to nodes, and we already said that nodes are not a good idea in production
code, right? And so we’re going to trip up over our Null values by having the possibility
of having an NPE. So you want to kind of get rid of that. Also noticing something else
which is the plus and the multiplication node has to keep around zero even though it’s a
completely meaningless concept for a plus or multiplication to have zero associate.
We have some number; we have to give it something over there, right? And not because we chose
zero. So, it has information that it doesn’t need, right? So there’s two different behaviors
that are kind of fighting in here. And so the different behaviors are basically, if
you’re an operation node, then you need your left and right child whereas if you’re a value
node, you just need the value. And you can see that in the presentation how you don’t
need the value or I need the left and right but I never need both. And that usually is
a perfect example that you have a class that has multiple responsibilities all entangled
inside of it and then there’s some kind of a polymorphic behavior going on but the polymorphic
behavior is going on through fields and if statements not through polymorphism. So, let’s
break this up. Let’s take our node and we say we’re going to have a value node and operation
node. And by breaking this up into value and operation node, what we can do is we can take
the value and shove it into the value node which is the leaf node. And we can also get
rid of the left and right child for the leaf node because it has no meaning over there.
And so this is a good way of separating it out and then simplifying this thing. So, we
would have our, you know, standard issue node with the evaluate operation and then we would
have the value node which extends the node and defines the evaluate method to simply
return your value. Notice how simple the value node is, right? There’s no if statements in
there, there’s no possibility for a Null or an NPE or anything like that. But we’re still
left with this app node which has this nasty switch statement inside of it. Now, I want
to point out at this point that think about how you would extend this. Not only do you
have to worry about having your toString method and your evaluate method mimic each other,
but every time somebody wants to add a new operation, they have to recompile the code.
Not only do they have to compile the code, they have to get a hold of their source code
first. So if this is meant to be as a library that a third party is using, they might not
have the access to the source code or maybe they don’t want to recompile the library,
right? And so, let’s see if we can do something better. So, with this change, this is how
the tree looks like, right. We get rid of our Nulls for our leaves, so we’re making
good progress and now when you have operation node it no longer has the zero that’s–that
was stuck over there before. And so this is definitely a progress in the right direction.
But, we still have the same problem as we had with the swallows in the previous example.
And that is, that the behavior of the node changes based on a type. On this case, it’s
the operator field, right? So depending on what the operator field is our class behaves
differently. And that’s something we want to avoid, rather we want to take advantage
of the construct of a language which is the polymorphism to take advantage of this thing
rather than encoding it using if statements. So, again let’s focus on the addition and
multiplication, and let’s further subdivide this into an operation node where we keep
our left and the right because all operation nodes have left and right children. And we
now just have evaluate which is continues being abstract and it’s becomes concrete in
the addition node and multiplication node. That’s where we have the actual implementation.
So from a coding point of view, right, we still have our value node, now we have our
abstract app node. We keep our left and right int at this level. And now we have the addition
node and multiplication node which does the actual operation. Notice what happens in here.
First of all, the possibility of an NPE has disappeared because, you know, operation nodes
needs a left and a right child, and therefore it will not, it will never throw an NPE. Whereas
the leaf node doesn’t have a left and right child and, again, it will never throw in NPE.
So we can really clean up the code simply by breaking it away into smaller subclasses
that do individual pieces of work. Again, keep in mind that in addition node, you would
also have to implement a toString method that it would know how to print the plus operator.
And in mean multiplication node, you would have to write a toString method that knows
how to print the multiplication operator and so on and so forth, right? So, it no longer
is a bunch of switch statement in different methods that have to all mimic each other.
They’re now separate subclasses. And if you wanted to add a new operation, it’s very clear
as to which methods you have override and which you have to implement over there. Right?
I know I have to implement the evaluate method because it’s abstract. And I know I have to
implement the toString methods. And therefore I can easily–any new person who comes to
the project doesn’t have to be explained or doesn’t have to go through the code in great
depth. It’s very obvious as to what needs to be done because simply the code doesn’t
compile any other way. So, after all this, we basically end up with addition node and
multiplication node. And again notice how the addition node and multiplication node
now don’t have the operator field. Not only do they have no operator field, they also
have no value field which we originally had at the beginning. So they went kind of on
a diets, they’d became just the meat of what needs to be done. So we kind of talked about
the toString method all throughout the presentation. But, it is a good point to kind of reflect
on how, you know, in a real world projects were you have multiple name and have evaluate
method you want to have–you might want to have a print method and a couple of other
things how it really helps the situation because you have one structure that you deal with
and you don’t have to go through multiple places and remember where everything has to
change. So, I’m going to argue that a polymorphic solution is oftentimes better. Specifically
because the new behavior has to–goes into a separate subclass, right? All of the behavior
specific to addition goes into one subclass. All the behavior specific to printing leaf
nodes goes into another subclass and so and so forth. And that actually makes it easier
to test, that makes it easier to understand, that makes it easier for people to extend
and maintain. You know, all of those are good qualities that we are looking for. So that’s
one way you can get rid of an if statement. Right, before we go there. So, switch statement,
whenever you see a switch statement in your code base, that’s usually a clear sign that
polymorphism is begging to be there. It’s almost the rule. I would go as far as saying.
If statements are more subtle and most of the times we want to get rid of ifs and at
polymorphism, but there are certain cases were, you know, you don’t want to be pragmatic
about it. But let’s talk about the other situation of where you want to get rid of if statements
and that is, when you have the same condition all over the code base. Let me give you an
example. Supposedly I’m a method classical update and there’s a method called execute
and based on some flag, you have to do either a, A portion or the B portion. You might think,
yeah, it’s not so bad, you know, I’m just–I just have a flag and I do different behavior
depending where their flag is set or not. Well, I would already argue, you probably
want to have a polymorphism at this point but, you know, it’s still just a single if
statement. But, at some point, you have a rendering method. And now, the same if statement
appears again. And when you start repeating the if statements over and over and over again,
that’s a clear sign that what you want there is polymorphism. The reason for this is because,
if you look at the do A part and the render A part, they both go in this–they both get
executed together. Similarly, with do B part and render B part, right? They–those pieces
get executed together and they’re rendering pieces go exit–I’m sorry, the A parts get
executed together and the B parts get executed together. And it’s not like you can execute
A and B, actually that will be a bug, right, if you could execute A and B. And so you’d
really want to make sure that the conditions are the same. Preferably, you want to get
rid of the conditions. Now, from a testing point of view, this becomes a problem because,
you know, not only do we have a global variable which is the flag, which is usually how a
command line flags get dealt with. But it’s always, you’re not really sure, like, did
I really cover all the ifs statements because are these if statements really combinatorial,
like, is it possible to execute A, do A and render B, or is it not? You know, it might
be easy to see in a simple class like this, but if you have a very complicated class with
lots of code base, it’s not clear which conditions go together with what. And so you might end
up trying to test things that can’t actually happen in production. And so, what we want
to do is we want to really separate it out. Same story as before, and that is we want
to use polymorphism to our advantage. We want to take the A parts and put them in one class,
and take the B parts and put them to the other class, right? And the work over here is pretty
straightforward. You create an abstract super class which is the update and now you take
the A–do the A parts, whether it is a do A or render A and pull it out in a separate
method called render and execute. And you do the same exact thing for the non-international
class, right? So now you have two subclasses representing what you wanted to do. Now, from
a testing point of view, this is great, because when I instantiate an internationalized subclass,
I know exactly what I’m talking about. It’s not some flag that got set somewhere else;
it’s a concrete class that I can associate with. It significantly lowers my cognitive
load when I think about the test. I don’t have to think as hard when I deal with this
thing. And I have a separate test for the other subclass, right? And again, I don’t
have to think about all the nuances. Not only are the tests separate, chances are that being
international and being non-international requires you probably to have a different
setup method, will probably require different fixtures and different ways of testing it.
So that further helps by separating the different kinds of tests out. But, the if statement
really have–didn’t disappear. The if statement is still there. Rather there’s two different
kinds of if statements. There is if statements that is in the location were the if–the original
if statement use to be, which is the polymorphic behavior of your code base but there’s also
the original if statement just got moved somewhere else. And that is if you are a consumer of
the update and you say, I need to get a hold of the update. What you’re really saying as
I need either the international or non-international one. But you don’t know which one it is and
it’s really not your business to care about which one you get. So somebody else is responsible
for instantiating the correct subclass of what you want, which gets us back to the good
old dependency injection, which is that you have two piles of objects. You have the piles
of objects which does the business logic. This is where the stuff actually gets done.
And then you have the piles of objects that are responsible for the object graph construction.
Again, for those of you guys who have been here before on these talks, you know, we’ve
covered this many times over because it’s really, really important. By separating the
objects out into the objects that the business logic and the objects that do construction,
you can basically move your if statement from being inline inside of your code which was
inside of the update that used to be just if international do something or something
else, you move that if statement into the factory. So now the factory says, ah, maybe
I have to instantiate an international version of the update because the consumer is asking
for it. As supposed to making the decision inline a new code. And that actually can have
great benefits in terms of performance because you don’t have to make the decision over and
over and over again as the code runs in some kind of a type loop. You make the decision
once, you instantiate the correct subclass and he gets inline. It turns out many modern
JVMs can actually inline that for you. So, a modern JVM, for example notice that nobody
has ever instantiated the non-international version which is probably true if you–because
you only run the application in either one mode or the other mode. And when the JVM notices
there’s no other subclasses of this thing, he will go and inline these operations, which
is great speed performance improvement. Now, if you’re using something like Guice, you
know, you can take advantage of providers.>>Can you [INDISTINCT], the fun stuff?
>>HEVERY: The fun stuff is your business logic.
>>Oh.>>HEVERY: This is what–why we are the software
developers, right? I live and breathe to make code and my code is mostly the fun stuff.
You know, the logic, the stuff that makes the cool applications, right? The factories
are the boring stuff. Well, like, I got to wire it together so that it runs. Right? It’s
no good to have a cool algorithm that can sort your data. You need to have some kind
of wiring that says, okay, instantiate disorder, instantiate the reader, instantiate the file
system and then hook it all together, and then kind of orchestrate the whole thing.
That’s–those are the differences between the business logic and your new operators.
Were your factories are your new operators. And we kind of mention that how important
it is to separate your new operators from your business logic because you want to be
able to–inside of the test you want to be able to instantiate the small sub portion
of your application. And by mixing the new operator together with your application logic,
you don’t have the control in your test of instantiating things in isolation. And that
kind of prevents you from being able to test things. So, you know, we kind of cover this
right, but the business logic is responsible for doing work, right? And the constructors
or the factories are responsible for wiring the objects together. Building you the object
raft, right? The reader talks to the filter, talks to the writer which talks to database,
right? The wiring magic happens inside of factories, that’s where your new operators
end up. It is also where your–some of the if statements end up because you want to get
in the situation were your application behaves differently, not because you have if statements
and flags sprinkled all over your code, but it behaves differently because you’re wired
it to get it differently. And that’s a big aha moment, right? Because when you can change
the behavior of application simply by the way your wire it together differently, you
have a lot of possibilities if you–what you can do at one time and in terms of compile
time in understanding, in maintaining it, and in extending it. So if you’re using Guice
for example, the constructors could be your dependency injection, right? This is what
creates the providers which hooks at things to get better. Where the actual original check
into the flag is made to see if we are international or we’re not international, and then we can
subclass the correct. We can instantiate the correct version of it. Now, going back to
the international example, it turns out that when you subclass things into international
and non-international, chances are that the two subclasses will actually have different
set of arguments in their constructors. And that’s actually important because if you’re
international, chances are you’re going to need certain classes that you don’t need when
you are non-international. And if you have a single class, where everything is done then
you’re forced to create all the objects and pass them into the constructor even if they’re
not needed. So, let’s have to look at this. So you have a consumer and he wants the update.
So what you need to do is to create some kind of a factory, right? This is where the new
operator is for the update. And this is where the if statement happens. We are either instantiating
the international version or the non-international version. So the if statement has moved from
being inline in your application to being inside of your factory. And that’s great advantage,
that’s what we’re looking for. If you’re using Guice, this gets even better because then
you can simply create a provider and you can create provider of international which is
automatically done for you. You can ask for the provider of international version, you
can also ask for the provider of non-international version, and then you can simply ask for the
flag so you can go a step further and you can get rid of the dependency on the global
variable. And now you can simply test–you can simply say, okay, get me the correct provider
allocation. So now, you actually make the provider testable because all the pieces are
fully injectible. So the benefits of this is the conditionals as we pointed out of the
decision of are we international or not has gone into a single location. So we took a
whole bunch of independent ifs and we collapsed them into one if and we move that if from
being inline in your application to being inside of your factories. We got rid of a
lot of duplication in the process and duplication can cause errors, right? If you discover that
your if statement has an error, now you have to go change all the if statements that are
spread all over the code. Now, we have only a single if statement, so if there’s an error
in the if statement, we can easily fix that. And it also allows you to separate yourself
from the global state. Like, originally, we were doing an if statement on a global variable
inline. Now, that nasty global variable ended up in some factory. So from a testing point
of view, yes, I might still have a hard time testing the factory but I have easy time testing
my logic. So we have taken something that we consider bad and we have moved it to some
other place where it’s still bad but because of where it is, it doesn’t cause as much problems
for us. So, the benefit of using polymorphism instead of if statements is that you simply
have a single locations were all of your related items are together. The multiplication example,
you know, we had the multiplication logic, we had the toString logic, it’s one location.
In the rendering example, we had the single location where we could put the rendering
and the operations for the update in a single place. And it greatly aids in the cognitive
load when I think about this thing. Not only does it help with cognitive load, it also
helps with testability, understanding, and makes it easier when you look at the subclasses
to figure out what the differences are. Right. If I look at international, non-international
version, I can easily see what the difference between the two of them are because the common
stuff is in the super class. I don’t have to worry about that. I simply have to worry
about what is different between international and non-international version. Or what is
different between multiplication and addition. I don’t have to worry about the common stuff
because that’s somewhere else. Anyways, behavior–so, you want to use polymorphism, you know, we
cover two different things and that is you want to use polymorphism when the behavior
changes based on state, right? Which is the example of the multiplication were we had
a flag and based on that flag which was–already was addition or subtraction, we did different
stuff. Or you want to use polymorphism when you have the same if statement over and over
and over again. This is typically done with flags. But, I know at the end of the day,
right, you got to be pragmatic. So don’t go crazy. I recommend that you try writing a
small project without any sort of ifs, just say I’m going to try it without ifs, and you’re
going to learn a tremendous amount about how you can take advantage of polymorphism in
a lot of different ways. It’s worth the experience. But at the end of the day, you know, you’d
be pragmatic if there’s a simple if statement that I can throw somewhere, that’s fine. But
when it becomes too many if statements, polymorphism really is the way to go. The thing is if statements
creep up on us. You know, when you throw in one and you’re saying, I’m being pragmatic.
Come along–comes along somebody else and he’s extending the code and now he says, well,
I’m just doing what the other person is doing. And now you’re no longer being pragmatic,
you are now duplicating code but you’re not realizing it because you didn’t write the
original if statement. And so Bart says, that you promised not to use, abuse conditionals
in polymorphic languages, and instead use polymorphism for it. Anyways, I’m going to
open up for questions. By the way, I want to point out that this might sound like an
obvious stuff especially with the example of multiplication. But my empirical evidence
of looking at other people’s code tells me otherwise. It’s one of those things that when
you see it, people say, yeah, clearly it’s obvious, yes. That’s how it should be done.
But then when you go inside a code base, all you see is if statements everywhere and very
a rare use of proper polymorphism. Do we have a microphone? I guess we don’t. Yes, I’ll
repeat your question.>>Okay. [INDISTINCT]. So, I was just going
to say that the first example that the [INDISTINCT] specialty?
>>HEVERY: Uh-hmm.>>There’s a lot more concise [INDISTINCT].
So, I wonder if these [INDISTINCT], you know, get something that’s really concise but at
the same [INDISTINCT].>>HEVERY: So you’re saying that the–I’ll
just repeat the question. You’re saying that the example of addition, the math example
was too concise and has…>>No, it wasn’t. It was nicely concise.
>>HEVERY: It was nicely concise, okay. And so you’re wondering if a different example
would be uglier, is it what I’m hearing?>>You think, I think that just depending
kind of injection its [INDISTINCT]. It’s not if [INDISTINCT] but the original, the [INDISTINCT]
which is at 1,500 it’s pretty short.>>HEVERY: Yes.
>>And whatever–and literally one file to [INDISTINCT].
>>HEVERY: Right. So, your objection is or the question you have is that many people
could argue that a single file with the node where you had a switch statement is clearly
easier to understand than the whole bunch of small files. I have an issue with the word
clearly over there. To me, it’s not that obvious and again it goes back to, you know, you write
as a simple node class that today is just doing node operations and additions, and subtractions
and tomorrow somebody adds something to it and they have to duplicate the switch and
so on and so forth. To me, this is not in my question of pragmatic. There is a concept
of an addition and the concept of an addition has behavior adding to numbers. And then in
the oh-oh world, behavior deserves to have its own, either a method or a class where
it lives, right? Now, in order to dispatch the behavior, you would have to go through
an if statement, which is what we kind of don’t want to go because, you know, it’s a
slippery slope where we say, yeah, one if statement is okay, you’re being pragmatic.
But soon enough, you know we have a file that’s 5,000 lines long and there is if statements
everywhere and nobody can quite figure out what’s going on. Especially with today’s day
with modern IDEs, the cost of writing, creating a new class is essentially a zero. So–or
traversing it or finding who to call was that–et cetera. So there’s no really problem there.
Where people actually do get into problems, which I see often, is they don’t separate
responsibilities of objects. So a single object has too many responsibilities. Now, keep in
mind that your object can only have one inheritance hierarchy, which suggests that you really
should only have one responsibility because that’s the only–you can only take advantage
of single polymorphic behavior through a single inheritance. And the way around that is, or
rather another way around that, it’s not a work around, it’s a good idea is you should
break it up into lots of small objects that collaborate with each other.
>>[INDISTINCT]. You can actually call the [INDISTINCT]. So, many interfaces [INDISTINCT].
>>HEVERY: Yes, but you only–the–remember what we did–sorry. You’re–to repeat the
question for the audience. You were saying that you can be polymorphic as–on multiple
methods. That is true. But, the polymorphism is decided on at the point where the new operator
is instantiated, right? And at that point, you cannot say that these two methods will
be polymorphic on to this behavior but these two other methods will be on this other behavior,
right? It’s all or nothing proposition. So, all methods have to end up in the same subclass.
And for that reason, you have to clearly separate responsibilities of objects, otherwise, you
have two responsibilities and those two responsibilities will want to have two different kinds of inheritance
and they will be fighting. Or put it differently, when I’m on a team and I see a nasty use of
a switch and I say, you should do polymorphism, the most common suggestion is, but I can’t,
I already have a specific kind of inheritance, right? And the answer to that is, well, that
means you’re mixing responsibilities aside of that object. Really, there is a whole bunch
of related objects living inside of this one object and their behavior is controlled by
a whole bunch of flags as supposed to collaboration. All right, guys. Thanks for coming. We have
these talks every week. We always have a different topic. These are new and improved talks. So
we appreciate feedback. Also, as I always point out, I do have a whole bunch of the
Java Reviewer’s Guide. So if some of you guys want one of those, I’d be happy to give them
out. Thanks for coming and we’ll see you guys next week.

100 thoughts on ““The Clean Code Talks — Inheritance, Polymorphism, & Testing”

  1. The word the guy is looking for in the beginning is "structured". At the age of thirty, I feel like a graybeard for knowing that. 🙂

  2. "Maintain an if switch"

    Programmers don't maintain if switches. Programmers maintain software projects. What that entails is being able to look at the code at any point and know what the hell is going on. That means refactoring your code all the time, whether it's while loops or type hierarchies or if's or goto's.

    You wanna have a rule like "if's are bad"? Have fun. You still have to do all that shit, and people have to read it, who might not necessarily be inducted into your cult.

  3. you still need to check the operator and new up the appropriate subclass so, how are getting rid of if statements? am i missing something?

  4. i'm a complete noob… so i'm trying to learn how to organize my programs/applications into a collection of classes… and wrap my head around object oriented programming… i think this was helpful for understanding polymorphism (even to a beginner)… And it really makes me think about different ways to go about coding… The only thing i didn't understand was Guice… i'll have to look it up and learn more about it.

  5. I can see how using subclassing with well chosen names would make your code much cleaner. With the flags example I suppose the flags must not change during the lifespan of the object ( with the example they probably won't) , I assume you don't want to cast the object when the flag changes.

  6. 14:30 He wrote "abstract class Node" then he reversed it down a few lines of code as "class abstract OpNode extends Node". Was this intentional ?

  7. Check out this file system that can compute! It is based on declarative formulas but way more powerful than a spreadsheet! Really amazing. It even invented a new king of inheritance called deep inheritance. Check it out @ solebase.com

  8. Some of the best advice given to me back a few years ago but you actually can remove _if_ statements entirely. He mentions SmallTalk… how did you think the language did without? It borrowed the conceptual idea of predicates from the functional programming world… predicates can be provided in Java _with_ a hidden _if_ clause for the three functional map features. More specifically, a reusable function and it's part-with typing can be created to allow Java programmers to use predicates.

  9. You can find my proof of this concept within my Java library called Mint.

    Here's its GitHub wiki page all about using Mint's predicates:

  10. wouldn't it be asinine to replace a structure that is less complicated in syntax, as well as more efficient in compiled operations with one that is more complicated in syntax and requires more operations in compiled code? Seems like turning a trade-off into a no-win situation. Not to mention that a decent compiler would likely reduce your loop to the same output as the if condition because they are logically equivalent.

  11. That is a great way. You could also define a macro to rename if to i_am_the_best. BAM! no more if's. Verify with find. To hell with logic, we care about what we can see!

  12. why some speakers always sounds a wierd voice just before the sentence beginning.. I think it is a lip movement and kind of a tic. I cannot listen to that invaluable conference because of that fucking tiny annoying voices of speaker.. holly fuck…

  13. Learn Selenium , QTP , manual Testing , Software Testing from Industry experts at very affordable price @ Madrid Software Trainings – 9560785589

  14. This post is an eye opener on how to smooth things as I am also a victim of having complicated IFs but now I'm improved.

    I've also used it one my presentation to share it with my colleagues that we have a problem in doing our stuff. You may view my presentation here: docs.google.com/presentation/d/1PMi3PemqUp3qIiX9sZRW058JWeNLsmfJ7jT9zRTk01Y/pub?start=true&loop=false&delayms=30000

    I'm happy if someone can help me improve my topic by giving feedback and recommendations. Thanks!

  15. So, nested conditionals could be realized using polymorphism but how would multiple conditionals be expressed?

    Like if([conditional 1] && [conditional 2]), how would you create a class encapsulating two different states?

  16. The idea of polymorphism > conditionals seems a fallacy to me. It's still doing a memory inspection and a branching of execution based on this. All it's doing is moving the 'if' to another part of the code, and then executing later on. Conditionals can be runtime state dependent too, just set the variables being tested.
    Arguably it's less readable because of this. The idea of less branching is good, but polymorphism branches depending on data/state, it's still branching just the same.

  17. You can actually get rid of "if" statements in any language supporting lists, arrays and switch statements. the "if"s are shame-on-you greatest mistakes …

  18. Sorry, I do not agree. Polymorphism is not just better that switch statements, just think about the SDL_Events. How would you do that polymorphic? And having a virtual render has also two problems. How do you implement a second renderer like DirectX/Opengl? Also query on visibility is not best done like that. There is even a very popular concept for that, it is called "model view controller".

  19. Never return null but Null Objects:
    * null is your friend in test but not production code
    * If you want to get rid of "ifs"

    Replace switch and if with polymorphism

  20. The 1 + 2 * 3 model is fantastic. The first node sketch is the ideal model. We then see that the simple approach (no polymorphism) results in a model that is far from ideal. It's full of waste and an engineers job isn't done until there is nothing left to take away. He should have driven home the point by showing how close the final code (using polymorphism) is so close to the ideal model by having them side by side.

  21. Watched the video. Just wondering does it mean rather than going through a if statement helll, we are having alot of sub class objects for us to execute our stuffs and testing? Will it be for each if statement, we create a subclass for it?

  22. * Switch Statement is always begging for polymorphism(almost a Rule)
    * IFs are not always…

    i like the way the "IFs are hidden" using the Factory pattern.

    Also agree with the fact that, wiring the factory, order of invocation are boring and writing business logic is fun stuff

  23. What would the final Node code look like ? I can see how all this is cool, but the switch statement comes because we need a condition, how do we manage that with those new classes ? Does Node even exist anymore ?

  24. Polymorphism is always slower then a builtin if and it is often much worse to read and result into terrible Spaghetti Code with Classes. Especially with verbose languages like C++.

  25. He makes a claim saying polymorphic system is easier to maintain but gives 0 argument and just anecdotal evidences. Yeah you say a method without if is easier to understand but a system with 100 classes with if is easier the a system with 1000 classes but no Ifs. Like Betrand Meyer used to say this is more like OO Hysteria.

  26. If this was presented as something to consider rather than an ideal to strive for I'd agree. However it seems that the matra is that ending up with thousands of small classes is a good thing. In my book that usually equates little real world functionality, patternitis and lots of code.

    If you can use this approach to reduce the size of your code base it's a good idea, if it increases the size it is bad. If it gives you an order of magnitude more modules and classes it is also bad.

  27. I guess with today's hardware performance raw code speed isn't such a major issue anymore. You aren't writing for 8Mhz CPUs. Polymorphism compiles to many more steps than an if statement. Would it work for a tight loop? The dependency injection business in Java relies on reflection, which is slow. But easy to maintain code is important too, life is a tradeoff

  28. I think there's really no reason to use a subclass for every op-type (depending on your language). I'd prefer to make the OpNode constructor take a function pointer/delegate to a function of type int -> int -> int (or more preferably, make the tree classes generic over types T and have the operations be arbitrary binary operations over T (T -> T -> T).

  29. Google or not, this propagates horrible over-engineering and some of it is against best practice in C. Also, exceptions? Really? The Video is from 2008, I think they changed their opinion on most of this since then.

  30. And polymorphism?! We try to avoid vtables wherever we can! Sublassing, yes, but you shouldn't use polymorphism if concepts achieve the same. And in most cases, they do.

  31. Notice he states right away this is done more to increase testability and reduce errors. If you are repeatedly using the same if statements for the same reason then use this. But, If you just need ifs a few times, then it's not necessary or particularly desirable. By making everything smaller pieces it reduces the chance of errors from incorrectly branching, reduces the time it takes to figure out what is going on, and makes test paths and procedures clearer as well.

  32. incredibly bad advice in general. polymorphism makes the code MUCH harder to understand and follow in many cases because the logic is split up into many files.
    of course there are instances where polymorphism is a good idea, but the first example he gives makes for horribly unreadable code. now, when there is a small change in the superclass, there are many files that require changes, and someone new to the project has to first grasp some complex design idea before understanding what this pile of classes does.
    Also, there still is a switch in his version of the code, namely in the factory or builder class, so he just moved the original 30 lines of business logic into 20 different files with 10 times the number of lines in total.

  33. In defense of this talk I would say that you should use this approach in business logic. This logic is usually never needs any performance since DB is the bottleneck in this whole system. If you write your code for real time high-loaded systems then polymorphism is not a good idea, true.

  34. Yeah, programmers should do their best to have clean, readable, and testable code. However, a lot of these people who preach religious code rules are like professors at university. Yeah, you are knowledgeable on the subject and your theories are intuitively correct. The problem is when you take these theories in the real world, they fall apart or become impractical. The only thing you need to ask yourself as a programmer is "Can all this be understood and maintained by a reasonable person?" and NOT "Does this follow the rules the elites have placed before me?". At a certain point, all this programming concepts turn into fucking beauty pageants rather than reasonable expectations and guidelines.

  35. Seems like a good opportunity to use Strategies. IStrategy: AdditionStrategy, MultiplicationStrategy, etc. Instead of doing everything.

  36. The jump was from non-structured to structured which enforces constraints that are supposed to eliminate spaghetti code.

  37. I wonder what the speaker would say about Default Methods in Java 8 interfaces – in regards to single-inheritance principle?

  38. I honestly don't see the problem with if statements. I don't find them unreable at all. In fact, with all the collapsing and regioning you can do, I hardly find any code hard to read at all. I do see the benefit of polymorphism though, sometimes.

  39. I find it disturbing that people like this carry out interviews and judge good coders for not having ridiculously over-engineered the code.

  40. For those arguing that the computation graph was over engineered: suppose ValueNode represents a complex type, such as a matrix. Misko's approach separates the responsibility of each operator out of the main class. For me the main take away was just that: separate responsibility.

  41. Bullshit. The PREMISE: Most if can. It is not true. There is a point when you need to use that.

    This is same as not use setters. Use the $Obj->moveUp, $Obj->moveDown, etc, instead of $Obj->setDirection('up'), and use a switch. But this is not how you should walk around this problem. Premise are not good. This is one of a perspective what you should understand if you are using clean code, but you should not to say, avoid if-s.

    Conditions are cool, this was one of the worst explanation of google talk.

  42. In your first example with the birds, could Bird be an interface with the method getSpeed rather than an abstract class? What if Norwegian etc implement the Bird interface rather than inherit from it? This would allow us to give other kinds of objects (trucks, planes) a getSpeed() operation without forcing them to inherit from an abstract Bird class.

    As a rule, I prefer composition over inheritance. Do you think this is a good place for composition? If not, why not?

  43. this is the exact meaning of over-engineering. i've one principle, "do it when you REALLY need it, and probably you don't"

  44. Yes, and we don't need pork and beef and chicken, we can just eat worms and bugs. Let's see if we can survive only with eating worms and bugs for one year.

    Easier to read, to test? Because the branch is outside of the code, where decision was made, wether to use a GreaterThanFooBar extending RelatedToFooBar or an EqualFooBar (extending the same) or an LesserThanFoo extending RelatedToFooBar? So we now have three times as much to test. That's easier to test and surely easier to maintain!

    At least we got rid of these annoying middle statements in for loops! Just using IfFreeIterators now without conditions. The same for the newly if-free-condition-checked-while-Statement:

    while (ifFreeCondition<ItsMagical<Object>>) { … };

  45. i love how hilariously dumb most of the contrarian remarks are. goodness… this video is simple, straightforward and discusses obviously reasonable things to anyone with experience or a brain.

  46. Is this talk the inspiration for FizzBuzz Enterprise?

  47. Uncle Bob's Clean Code got published right before this talk, you can see "Don't return null" part is showing in this video as "to be if free", amazing! But that's outdated since we already have Optional in Java, oh BTW this series of talk is heavily focused on JAVA instead of other languages

  48. if we think about replacing polymorphism with if-else, then the "if-else type of polymorphism" depends on the source code instead of the language itself, this talk seems under the influence of trying to make OO pure instead of finding a perfect combination of procedure and OO

  49. So, he doesn't answer the question: How to implement ToString() method without if statements. Does anyone know how we can solve this problem? The only solution that I know is to put a precedence operator field inside operation node, and then ask if precedence of node is greater than precedence of the child node put parenthesis around child.ToString.

  50. I agree with the "copious amounts of state inspection using conditionals is bad" part, but it becomes really obvious how an algebraic datatype would be so much simpler and more efficient and clean to use, rather than a complicated class hierarchy.

    full implementation of the problem statement in haskell:

    data Expr a where
    Lit :: a -> Expr a
    (:+:) :: Expr a -> Expr a -> Expr a
    (:*:) :: Expr a -> Expr a -> Expr a
    deriving (Show, Eq)

    evaluate :: (Num a) => Expr a -> a
    evaluate (Lit n) = n
    evaluate (l :+: r) = evaluate l + evaluate r
    evaluate (l :*: r) = evaluate l + evaluate r

    example output:
    evaluate (Lit 2 :+: (Lit 3 :*: Lit 2))

    no inheritance, no ifs, when adding new ops you get full compiler support with warnings and errors in incomplete pattern matches, everything in one single file, and everything in 9 lines of code.

  51. Here is a quick summary:

    – methods with less if statements have less possible paths of execution going through them
    – thus they are easier to think about and easier to test
    – they are easier to test because if there is only 1 path of execution going through a method, you only need to test that one path of execution (i.e. one test case). If there are 4 paths of execution going through the method (due to different conditions for the if statements) you need to test all 4 of these paths, thus you need about 4 test cases

    – normally, an if statement inside a method does a different thing based on some condition somewhere (can be state of a member variable or a global state)
    – what if instead, we create a class hierarchy such that we put the different behaviors in different classes?
    – for example, if we have a class called Car and a method called drive(), and the drive() method will either drive the car really fast or really slow based on the value of a member variable which tells us whether the car is a sports car, or a big truck, etc. Also, consider if there is another variable called broken, and if this variable is true, the drive() method does nothing.
    – instead of putting a bunch of if statements in the drive() method, we can simply create a bunch of different classes with a drive() method. For example a SportsCar's drive() method will make it drive super fast where as a BrokenCar's drive() method does nothing. Of course these classes would need to inherit from a base Car class with a perhaps abstract drive() method.

    – ok, so we know how to take if statements out of our methods, but when should we do it? What are the guidelines?
    – switch statements in your methods are a HUGE hint that you should strongly consider polymorphism
    – if you have the same switch statement, or the same if structure, in several of your methods, this is a strong hint that you should consider polymophism instead
    – if an object behaves different based on its state, consider using polymorphism (this is called the state pattern btw)
    – if you have if statements (or switch statements) that do different things based on a variable called "type" or something similar, this screams polymorphism! Why are you keeping track of the type of this object via a member variable? Why not just make sub classes?

    cool/helpful hints:
    – you can use the Null object pattern to really reduce the number of null checks your client has to do. Normally your client calls your function, then checks to make sure he did not get null back, and if not, he calls methods on that object. Basically what he is thinking is "if the object returned by this function is not null, i want to do some work, otherwise no work". If instead of returning null we return an object whose methods do nothing when called, we achieve the same thing! The client calls your function, then starts calling methods on the object you returned. If the object you returned is a Null object, nothing happens anyways!
    – you want the behavior of your system to be determined by the objects and how you link them together. If you wanna change the behavior of your system, you want to link different objects together, or remove one object and insert another one in its spot. This is the type of design that you tend to get if you favor polymorphism over if/switches.

    main overarching message:

    As with most things in software engineering (and life in general), it is all about balance. You cannot completely remove if/switch statements, and that is not what you should aim to do. Just know that in certain cases (especially when your class consistently changes its behavior based on the value of its member variables) you should consider polymorphism. Just know that there is a relatively easy way to take a class whose methods are riddled with similarly structured if/switch statements and instead create a class hierarchy whose methods are nice and simple (but of course you end up with more classes).

    Hope that was helpful!

    Thanks so much for the talk, really enjoyed it!

  52. Is there another way of dealing with the OpNode? Instead of creating subclasses of OpNode, I was thinking of creating a NumericOperator interface.

    This interface would have one method: calculate(double operand1, double operand2).

    I was then thinking that OpNode would have a NumericInterface field which would be assigned one concrete implementation of the interface. It would then be able to use calculate() with whatever value is in its child nodes.

    Anyone have any thoughts on this or tips for improvement?

  53. Is this link what he refers to when said "Java Reviewer Guide" ? https://google.github.io/styleguide/javaguide.html

  54. This subject (and much more…) is essentially a "design pattern" issue in all OOP world.
    A good book : "Design Patterns – Elements of Reusable Object-Oriented Software", Erich Gamma/Richard Helm/Ralph Johnson/John Vlissides (1995), you'll find all answers you need about all these basic design patterns (creational, structural and behavioural patterns). A must for any serious OOP programmer.

  55. This entire idea is the largest pile of theoretical horseshit I've ever seen. Polymorphism is just hiding the branching behind 30 more source files. This does not make the code in any way easier to read or maintain. It just obfuscates basic truths that would have otherwise been quite obvious. I've spent years working in codebases that tried to following this approach, and every single day I longed to go back to simpler concepts where you can just read the damn code from top to bottom and understand what it does, without mentally "branching" out into a hundred other source files to wade through all of the endless layers of polymorphic abstractions which add absolutely no value to the code.

  56. All this disdain for "if"s and still you couldn't describe polymorphism without jumping right away into a list of "if"s 3:35 😉

Leave a Reply

Your email address will not be published. Required fields are marked *

Back To Top