Tuesday, October 11, 2016

Aloha Ruby Conf 2012 Refactoring from Good to Great by Ben Orenstein

how's it going guess everybody doing well
good lunch raise your hand if you're in hawaii right now
not bad right been the worst conference locations we've got to tell you
so it's interesting i realized earlier this is the first time I've given a talk
twice in a week
so on thursday i gave this actually the exact same well very similar versions
talk at Magic Ruby which is in Disney World
so I flew directly from orlando to hear so my life is rough
you can send sympathy cards to my address so just a little bit of
administration before we get started
my name is Ben orenstein i work at top pot in boston and this talk is
refactoring from good to great and this is basically about things I've learned
in the last layer year or so that I think improve the quality of my code
so I'm just going to share that with you guys now I don't want you to think of
this as a lecture
this isn't me standing here and telling you all these things that are absolute
truth
think of this is pairing an au pair programming with all of you
so as a result of that if you have questions
say something if you disagree you say something to suggestions say something
I love that back and forth during the talks don't be shy about interrupting
I love diving into stuff so so go for that
now let's dive right into this i want to show you my first example take a second
and read this code
now this is based on some code I wrote recently
it's a simplified version this is basically a very simple report that
takes a collection of orders a start date and end date and returns the total
sales of those orders order has an attribute called placed at that we used
to check the date range now about a year ago I would have committed this push it
up and been done with it
now when I look at this I look at it I think it's it's about being SH about
abbey d -
it's decent if I if I was pretty confident that I would never come back
to this code and change it or extend it
I'd probably just say it whatever good enough push it up and let's move on to
the next thing but these days I actually some stuff i would do to improve it
so the first thing I like to do notice we've got this temp variable right here
we're figuring out the orders within range or second attempt and they were
doing something with it and actually to distract this into its own method
I'm gonna pull this into a private method now record a macro that does this
for me
don't freak out so here's the before
temp is in that method here's the after made a private method with the same name
and just referencing it from up here
so this is something i actually do a lot these days
pull out these texts this is our factoring neighbors called extract temp
to query and this is something i do a lot
now why do i do this why is this worth it well the first thing to notice is
we've gone from one method with two lines to two methods with one line each
I'm not going to tell you that that's always an improvement but it usually is
I'm starting to think these days that methods longer than a line or a code
smell and I should define what code smells just in case a coat smells
something that indicates there may be a problem that there is a problem that
there may be a problem these days I tried really hard to get down the
methods that are one line and it usually results in really good code because my
methods are focused
that's one win the next is that we can reuse this so i think it's reasonably
likely given that we have total sales of the date range
the next thing that the stakeholder ask for something like average sales within
date range now one of the code looks like this you have the logic for
selecting those orders within range locked up in one method
it's more likely to duplicate that later whereas if I have like this
I think it's more likely to me to reuse it so I think that's another win
finally the nice thing about this is when the code looks like this for
whatever reason because we're programmers because we read code when we
see code like this
we read it so the first thing your eye doesn't ucok order to arrange equals
ok let me figure out what this is a figure out what this is doing what it
looks like this when its own method
my life is more likely to see orders of the range ok this is private method
I'm just gonna assume that selects all the orders that are within the date
range what to do next
I'm more likely to ignore those details and in fact by extracting this method of
moving it into a private method
I've given you a hint and the hint is this code is not important
this is an implementation detail that you don't really need to care about if
you care about exactly what's going on in that method you can dive into it but
it's not super important to what this report is about so i think the winds are
sort of small but in the aggregate there
there's they're worth doing let's keep moving out
I think we can make this better let's look at this method we've created now or
is within range and now within this method
we're asking order about things about itself
we're saying hey you placed after the start date before the end date and then
we're using that information to make a decision
has anybody heard of a concept called tell don't ask
ok cool so this is that this is an idea
it's not a law but it's something that can sometimes lead to better code and
what L don't ask is is it says it's generally better to send a message to
send an object a message and have it perform work rather than ask that object
about his internal state and decide what to do on its behalf
not a law but it's a maximum it tends to lead to better code this code actually
violates tell them ask you can see I'm trying to select some orders and to do
that I asked order about things a sort of things about itself
and then make a decision on his behalf so I'd rather actually change this code
to look a little bit differently
so what if instead it is something like this
so now this sort of looks like an ask but the logic has moved i'm actually
telling order something I'm saying
tell me if your place between these two dates as opposed to a order
what's your internal status one of what kind of attributes do have and then i'll
make a decision based on that so this is actually closer to following tell don't
ask so i have specs for this
what I'm gonna run right now that blows up because i use local variables when I
meant instance variables
let's do that again okay
there's your there we want undefined method place that we're calling a method
on order
I'm effectively doing TDD by writing the code i wished what which were there so
it's actually add that method to order now and we actually want not place that
we want place between that's a better name
alright so to find that place between takes a start date and an end date and
then we're gonna say is my start is start date after is it before placed at
and his end date
look backward so I students / placed at this will be easier to read his place
that after start date and is it before end date
right there are placed between method
let's run the test again back to green
the question was what about a range include and that's a great idea when we
get there
yeah we're doing a little steps but this guy's totally right
we will end up there eventually but not quite what you said something a little
bit slightly better look a question
so okay so is this an improvement yes i think it is we've moved this logic over
to order
we stopped pulling out interior pieces of order and fiddling with them
understand just sending messages
this is a good old principle to follow don't let the internal details of
something like order leak out into code surrounding it
that's that's the core idea behind tell don't ask so i think we we we have a
nice win here again
I'm happy with where this logic is living but now we've sort of i see now a
new problem a problem is made evident now that we have a couple places where
I'm passing start date and end date
so notice i pass started and ate into the initialize this report and then I'm
doing it again down here and I've start date end date here
this is another smell when you have a pair of arguments at least two that
you're passing together all the time
there's a name for that and it's called a data clump and now today the clump is
a great hint that you should've strapped an object instead to hold those values a
good way to test if you have a data plan by the way say this two piece of data
have started an end date if I took one away with the remaining one makes sense
not really right what would it mean to pass it to create an oral report with
just an end date doesn't make sense
so if these things are always going to live together there's an implicit
reliance on each other right
it is implicit that I needed started an end date whereas if I made this thing
into one object like a date range it becomes explicit that I need both of
those
that's another great Maxum to think about when you're writing your code
imagine you have to show explain your code to somebody else and a lively have
to go
okay well we're always have started an end date anything that's implicit in the
code
you can take out and somehow make explicit and more obvious
that's generally going to be a really big win so let's do this and we'll start
in the spec
here's my spec it's really simple
I have an order within range and then out of range and then just then the
state range and then I make sure that the total sales number is correct
so let's put a date range right now and again i'm going to write the code i wish
i had come on baby
oh my - I'm gonna be too hard
there we go and then here will pass in the range
cool so far we're gonna run this blows up
uninitialized constant date range as expected because I just reference a
constant that's not real
let's go make that error go away
ok now we're going to be a handful of errors as i run this right because
suddenly wrong number of arguments
this actually I'm calling a range not new and passing arguments but it doesn't
expect them such as make a quick struct to hold a start date in the end date and
now i have roughly the air i want which is wrong number of arguments into orders
report
i'm passing two arguments right here it used to expecting three up here
so now i need to thread this new date range through I'm gonna do this in sort
of a compressed series of steps
so again don't freak out let's pass in the date range now there's no such thing
as start and end date it's just date range and same deal here in that method
we wrote in order
it's just a date range and now we need to ask the date range about it started
an end date
see for green again well okay
so is this a win
yes it's a win i think it is I think this is worth doing now Bob Martin has
said he thinks that most intermediate object-oriented programming errors are
too reluctant to extract classes you should be fairly aggressive about
willing being willing to extract small classes like this look at date range
it's super simple right it's very basic but again it's made something that used
to be implicit in our code
better better or worse
all right it's made something that used to be implicit and explicit now now date
range you know is a pair of values that this class doesn't have any behavior on
it but i think this is still worth doing
I've created a name for something I've pulled out an explicit name that's
almost always an improvement but there's another one here which is we reduce
coupling
now what's coupling company is the degree to which two components in his
system rely on each other
so if a component a and component B have zero coupling
you can change a as much as you want and in any way you want and you'll never
break be vice versa right so that's with no coupling
let's say that a and B are extremely coupled that means it's really hard to
make changes to either one without breaking the other
now as you might imagine the low coupling is good
hi coupling is bad because couple low coupling makes change easier and that's
what's hard about software is responding to change
I saw keynote by Dave Thomas and he said the only thing worrying about worth
worrying about when you look at code is is it easy to change
solo couple makes things easier to change and let's look at a quick example
of some coupling
so there's different kinds of coupling
this is called parameter coupling
so notice that notify user of failure passes in an object called failure into
another method within that method within print to console we call to sentence on
that parameter
now if I past mill into print a console is a blow-up right
no method air to Center does not defined if I passed us
if i pass something else let's say an integer into print a console this will
blow up right because two sentences not to find integers
because I hope not so there's actually coupling between these two methods
notify user of failure has to know what print a console is going to call on his
parameter if i change print a console
I could make notify user of failure blow up because they're coupled through the
parameter that parameter coupling isn't bad but less coupling is almost always
good
so something to notice is methods that take no arguments are superior to
methods that take one because they do not have parameter coupling first time i
heard that blew my mind
also if we keep using induction methods that take one argument are better than
ones that take - and methods to take two arguments are better than the ones that
take three
because in each example we're lowering parameter coupling
so notice what happened here we just slim down our argument list from three
to two
and that's a win so probably was reduced
that's one win we made something explicit used to be implicit that's
another win but also we now have a great place to hang behavior in
object-oriented programming it's a really good idea to group behavior with
the data operates on
and now that i look at this figuring out if a date is between to end to bounds is
not actually really good responsibility for order but it's a great
responsibility for date range
I can imagine wanted to know if other objects have a date place between two
two end points and we can reuse date range
so what I'd like to do now is move this logic into date range
so why don't we say what we want us to look like
so why don't I ask date range
hey does this include my place that looks good to me
that blows up as expected because this method doesn't exist
date and then we'll say is a date after the start date
and
before the end date let's see if that works for us and it does so now order
just knows how to ask something else if its place that is included and I like
this because order should know about place that I'm okay referencing this bit
of data which is on order with in order and I'm okay with date range knowing how
to find if a date is between two dates
perfect exactly where I want this logic to live
now let's this guy asked about a little refactoring so let's do that right now
there's actually a hand your way of writing this so i can ask if start date
end date the range if it includes date right back to green good but a little
whole thing that i gave this talk somewhere maybe Scott should be calm and
was able and told me this cover cover covers
that's it no cover
yeah so when you ask a range if it includes something
ruby is going to instantiate every object within that range and then check
if the object to pass it to include exist in there if you ask cover
it's just going to figure out its gonna stand at the two endpoints and then use
some logic to figure out if the thing you passed in between this
so if we had a date range that was 300 years long this actually could be a lot
faster before what was your question
yeah
that's a great point his point was that my tests aren't really thorough enough
I'm not testing the edge conditions in there and that's actually really good .
actually go back and improve those tests
I think you can try trust me that it works enough for now but yeah that's it
that's a good thing I should
I'll beef up the coverage on that guy that's a very good point other questions
yeah
mention that
yes
yeah featuring a good point yeah so the the code smell that motivates this kind
of refactoring is called feature envy and feature envy is when one class seems
very concerned with the internals of another class was asking a lot of
questions about its internal data and working with it
that's usually a good hint that you want to move that logic on to the class
itself that the code the client code has envy of what that other class knows
and so it's asking a lot of questions and fiddling around with the data thank
you that's good
so a couple quick things i would do now true fact to finish this up going to
move on to a new example
so this is kind of ugly right
this is pretty janky when I read this yes I mapping the amount of them doing
this and something in this way but if you read this you're just really
calculate the total sales right
so whenever I have a bunch of kind of ugly code that I wouldn't describe how
you wouldn't use the words
oh I'm going to map the amount and then inject with zero as the default and
added some what i really say if I would describe this to us
then I'll add up the total sales so when you look at your code and it doesn't
read like you would say it make it read like you would say it
so what I really would say is something like that
oh where are my type of sorters within range are back to green
so now take a look at this top-level method the total sales is a name total
sales within a range are the total sales of yours within range that is how I want
my code to look
that's like brain dead simple right and this is my only prob I'm only public
method
I'm extra aggressive about making my public methods read like this because
it's really likely that someone that comes into this code
mostly cares about this method these are slightly less aggressive about that but
people want to know about your public API your public API should be super
super clear the private api should be as well but it's a little bit less
important it's less likely that people care about those details but even so i'm
going to change this guy right here just to be a slightly quick little hack with
Ruby 19
I don't need to understand simple plus my goodness
so it calls to proc on that for me
that's wonderful that's cool okay so apparently we don't need you don't need
to call to property just passed a similar argument which is wonderful i
think i also heard some murmuring so glorious and I know 20 but he is only
partially right if I don't have any orders
this will blow up and funny enough I didn't have the zero originally and then
in the middle of a talk
Jim why rick is like what happens if you don't have any orders within range
it was like a map will bring up an empty array and then checked over it and when
i get if i dont have it in
I just let return an empty array as opposed to 0 right if I inject + 10
yeah right if I just have this is going to blow up Brittany let's suppose to 0
so my Rick beat you on that one cory sorry if it
you should see my commitment is the gym why I found a bug in my talk was really
excited
ok so we've been working hard so i want to show you as a quick need of a break
my most important in plugin
mmm
this is the only then plug and i use obviously not really but hey all right
let's move on let's do something different
there's another bit of code like you to look over now this code represents a job
site as in a place where doing some construction work or cut off the top of
the screen a little bit
let's go here are you now all job sites have a location because you're always
doing work somewhere but not every job site is going to have a contact contact
could be no that's optional
we might not know who the contact is that a particular job site
so notice i just described something that implicit about this code right it's
not obvious from looking at this the contact is optional but you can start to
see it at these ugly conditionals
look what happens if i want to pull up the contact name I've got a check for
the presence of contact
otherwise i provide a default like with contact phone and I want to email the
contact i have to make sure it exists first before I try to call a method on
it
so how is this code well as codes ok
it's not great what's what's the problem well it turns out in a slightly more
hidden way we're still violating tell damask provided until then ask again
so we're actually every time we ask contact something we say hey do you
evaluate to a truth value and if you do I know what to do and if not I'll do
something else
so what we'd rather do is just send contact contact name
tell me your name and if you do exist return what your name is and if you
don't exist
tell me no name so what's actually happened here is we have co-opted mill
because when content doesn't exist at contact will be new and so I'm actually
passing around the nil object the mill singleton as my contact
that's not a very good idea and at least this family conditionals like the 112
so how do we prove this well
oh and one of one of the bad thing
this obscure is the point of the code right contact name really just cares
about the contacts name but I have this annoying handling in here
it's making it harder to actually see what this code really does so the way
around this is with a pattern
recently , one called null object pattern so rather than have nil stand-in
to mean when there is no contact
I'm going to actually create an explicit object to stand in for that case
and since this uses the null object pattern and i believe it's a good idea
to actually use pattern names in class names which will some people want to
fight to the death about Alan and I call it not contact
so if we don't actually have a contract passed in a sign and all contact that
new let's run our tests looks better on tests going boom and things blow up the
first error was that there's no no contact
let's make that happen
now we have more errors and now it's happening here is I have tests that
don't pass in a contact that just passed and has nothing
and so it's a signing a new no contact here but then no client doesn't respond
to things like contact name just a brand new class got nothin on it
let's add these things were going to add name or to have phone and were to add
deliver personalized email on two are not contact class
so here's name just one has no contact
I think I want to return is no name or no email deliver personalized email
takes a female body but i'm just gonna leave a blank
I'm not going to do anything so there's not a contact just do nothing
so if i run this hope my method phone up the phone right
phone yep
ok back to green and now we're green but what can i do now i can do whatever fate
programmers favorite thing is
which is what delete code
no one ever fails to know what that is that is so universally the programmers
favorite thing
everyone gets that so let's make some code
oh yeah oh yeah oh my god
haha and what's the green
how great is that right
thank you guys yes i got like to contact a lot to do
ok so for the cost of this stupidly simple no contact class
I've blown away three conditionals yanked at about twelve lines of code
made these methods more obvious and more direct all for the cost of one little
class also notice we're no longer valid until don't ask
we always tell some sort of contact
yo dude I need your name we never care about whether it's an actual contact or
null contact the client code doesn't know and it doesn't care
so that's awesome this is actually a great win this pattern it's simple once
you understand it
you see opportunities to to work with it all the time and it's great
now there's a downside now right what's the downside
that's right yeah
now I basically have to keep to api's and sink right if i add new methods to
contact
I'm going to need to add the milk contact as well that's a bit of a pain
in the ass but it turns out it's generally worth it
a lot of code ends up with these big hairy nasty conditionals and no contact
just like destroys them like that
by the way this for factoring is called replace conditional polymorphism which
means rather than doing ifs just send that same message to multiple different
classes
that's polymorphism right you just always send a message two very different
as objects and objects know how to respond to it in different ways
there's a bit of a cost of this
so you have to wait that to see if it's worth it
nothing i'm teaching you today always works
there's no real factoring that is always a great idea
you always have to say is this worth it given the components of my system as
they are so that's the downside to talk about the good signs
there's a lot going on how many people by the way have code in a rails app that
looks like if current user yada yada yada is your hand
yeah you see how this would apply to that
so rather than have current user return a user object or nil and then constantly
need to check if current user is nil have current user return user or a no
loser
yeah yes
yeah
yes
yeah
yeah
it's a great question the question was Melanie content is defined in this class
do I leave it in the class or do I pull it out and make it sort of a first class
citizen in my business logic and the answer is it varies usually with
something like an old contact
I will pull this out i'll put it in at models i'll call it and we'll contact
our be it will live as a top-level important class in my app
occasionally I will define classes that only live inside the context of like a
one other class right
so like if you are being aggressive about extracting small classes like Bob
Martin says you should be there are times where you'll find that you've
written a small class is really just a little data container or something very
basic
that's only used in one class and in those cases
I'll just leave that class inside the original parent class all you make it
private so i know nothing will ever talk to it
it's just for that that top level class it by the way in that case I wouldn't
read explicit tests for that class if its private to another class
I'm not going to test it I'm not gonna test private methods ever actually
nothing is private but if i do promote it in to be a top level class that i am
going to write separate unit tests for this to make sure it works
it's a great question other questions about this or anything else
all right
we got one more example and then a quick wrap-up and I got some recommendations
and things like that so onward and upward
let's go to this guy
the second and read this code
ok
so let's talk about an idea called depend upon abstractions that most
programmers are aware that's a good idea to depend upon abstractions
so most people will use for example active record to have it generates equal
for them rather than rights equal by hand
unless you're in a horribly ugly situation where sometimes that's the
only way out
hopefully you'll get there also most people won't just shove bites into a
socket will use a library like net HTTP so most programs are aware of this idea
in general like you want to you rather keep pulling up a level of abstraction
and you rather depend upon those abstractions that particular
implementation details for instance that's why you pull a lot of stuff to be
private inside an object
you don't want other things outside that code to depend on your internals you
want to depend on an abstraction that you're providing the thing that a lot of
people don't realize is that abstractions are fractal you can keep
going higher and higher and you should be relatively aggressive about creating
abstractions within your application
one great rule of thumb is that you want the whole to be simpler than the sum of
its parts
that's a great look from a book called growing object-oriented software guided
by tests which has the longest book title I've ever recommended gonna show
you a link to that later because it's an awesome book
that's a great rule of thumb the sum should be simpler to work with than its
parts
so if you've got a few models or a few classes in your app wrap a class around
that bad boy make a simple API that's easier to use created abstraction that
your other things can depend upon rather than the low details within your app one
place i see this violate a lot is ideas like this
so I have all this code here and this code is concerned with charging people
think for things braintree by the way as a payment processor so I pulled down the
braintree gem which is good it's better than writing direct calls two branches
API shoving bites down the socket
I've extracted a bit it's using HTTP API but my co doesn't know about that it
doesn't know that this is an HTTP API which is good
we've gone pretty far this is nice it's not great
notice that user is concerned with things like how do i find my own
braintree ID and then once i do how do i charge for it
scription and how much should i charge or how do i create myself as a customer
with inside braintree and then refund is concerned with other problems and i find
the transaction ID of the thing I build for and then how do i refund that
so we have depending upon the braintree jam as an abstraction but we can go more
abstract than that
this has some that this has some weaknesses right now if I wanted to
change which gym we use to build braintree I simply need to open up user
it seems like the wrong thing right we need to change payment process and
gently using therefore let me open up the user class right
that's a great smell this idea called shotgun surgery where if you need to
make an appt a change in your app and you can open up 30 files
you're doing surgery with a shotgun regular below and stuff cold everywhere
you're affecting everything you're breaking stuff
it's so much more likely that you're gonna break things you're going to do it
wrong
wouldn't you love to just open up one file and change your payment processing
them there
yes you would is it likely that you might change payment processors
yes it absolutely is I've done it before here we have to open up all these
classes
so how do we improve upon this well do something like I would do something like
this
I make a new class as you might have guessed i love classes called payment
gateway
I've moved that constant inside payment gateway it's a nice place to hang it and
i set up my gateway which by default is braintree gem and I move that logic in
there and then my client code this stuff only knows about payment gateway and the
method names and it passes itself in now all that logic lives inside payment
gateway
it hasn't leaked into my application I want to change payment processors
there's only one file that needs to change that's the power of depending
upon abstraction one file needs to change what I'm going to change not
shotgun surgery
that's actually a really big win it makes it easier to change stuff which is
the thing that really matters
finally notice now if I want to test this guy thoroughly
I have to stub methods on braintree gym which is a great way to make yourself
one to have a bad day you're gonna have a bad time
if you stop other people's methods you're going to have that time
braintree gym is if API is reasonably likely to change you updated versions
your tests are stubbed out
you don't realize those methods have been changed until you run this thing in
production
it blows up but you can't build people for stuff and people are really upset
in this version you can stuff your own methods if you study your own methods
you're gonna have a good time I'm totally fine stepping out charge for
subscription or create customer because I control them
so this thing just got easier to test with the introduction of a new
abstraction
that's a great sign that's a positive code smell when you're writing your
tests
pay attention they're telling you things if it's hard to test something
if you have to do something that makes you feel dirty don't do it
listen to those tests and instead figure out how you can test it and figure out a
change you can make to it to test it in an easy and straightforward way I don't
always do things like this but when i noticed that I've got the concerns of
billing spread out through the app
I'm more i'm pretty likely to do it I don't like to see things like gem names
popping up for gym class names popping out through all my business logic
I'm just concerned this is a payment gateway I'm not concerned that i'm using
braintree to do it depend upon distractions
ok so we've talked a bit about some different ways of refactoring
so when do you refactor the best Henry factors when you want to make changes to
the code
it's actually rare for me to just be like wake up on Monday morning like you
know what
in fact some stuff I there's that user class that sucks on refactor it now part
of that is because i'm a consultant right and consulting code is a little
different than product code your product company guy versus a consulting guy like
at the end of every week
I need to . the stuff that I've done
and that justifies the value that i just charged for so there's there's a bit of
a bit of a paradigm situation there which may be doesn't match yours but I
don't just wake up and say I'm refactor stuff but when i go need money to change
something
I am very likely to go to factor it so Kent Beck had this great tweet which is
if you need to make a change
refactor the code so that the change is easy
note this part might be hard then make the easy change
it's a great way of thinking about it when you get to some code and you think
oh man i'm going to change this widget to take a few which instead think about
how you can make the change that you're about to make a really simple and
straightforward refactor it that way and then make your change
so just a factor willy-nilly special your consultant okay so that's a great
time to refactor what are some good things to refactor what are good
candidates for factoring the first my favorite things are a factor God objects
that was a God object the object is something class in your system that
everything seems to rely on or everything seems to interact with and a
great rule of thumb is that rails apps almost always have to God objects
the first one is user and the second one is whatever that app is about
so if it's a to-do list application the other got object is what to do if it's
an e-commerce application the other guy . it is what order
exactly two objects at least some apps have more
the bigger they are the more level you've got a handful of God objects so
how do you find these got to be aware of them well
a great way is to walk into your app models directory
I've anonymized this one to protect the guilty let's get a word kind of lines of
every object every every model of ours and then let's sort of and you'll see
that i'm not totally crazy
this is an e-commerce app how can you tell well user is a God object order is
right behind it and this one actually kinda has three merchant is arguably a
God object
do you think a 600 line
class has only one responsibility
probably not you've heard a single responsibility principle right
every class should only have one responsibility a single responsibility
the first rule of classes is that they should be very small
the second rule of classes is that they should be even smaller than that
this app is violating that user is huge and because of that it is a pain to work
with user
so when i'm working with user I refactor it if you want me to change something
about user I'm gonna make damn sure when I push up those changes user is smaller
than when I started
I'm extremely aggressive about refactoring responsibilities out of God
objects
I don't want you to get any bigger I want to get smaller same thing with
order same thing with merchant
it's a great way of thinking of these things be aware of your God objects and
be completely reluctant to add additional lines of code to them
it's going to make your life a lot better wear that one else is a great
Henry factor
I turn files
what's churning when you're changing a file a lot
I keep having to come back to user and change it and change it and change it
and change it
pay attention to that how do you have you noticed that well maybe you just
notice it but maybe use a gem like this gem called turn this will look through
your get history or svn if you're crazy and it will tell you the files that
changed the most
if a file is changing all the time it's because you don't really understand it
it's a great candidate for refactoring if change you want to make it easy to
change that file in the future
so give it a good a good healthy dose of refactoring another great place to do
look for refactorings our files in which you find bugs and you know why because
bugs love company
if there's a lot a bug on line 10 chances are there's a bug on line 11 and
the reason is the code was too complicated for you to understand it
that's why the bug is there it was too hard for you to see the bug
so if you've got a file or bugs are showing up all the time for factory make
it easier to understand
give the bugs fewer places to hide
so that's what I like a factor so a couple of recommendations before I go
first is if you ever read this book read this book
this is about the best like intermediate to advanced to sort of advanced beginner
ish book for general programming knowledge like it
it's just great read this book after you've read that book read this book
there's basically nothing i just talked about today
that isn't in this book this is the Bible you've got to know this book you
should know the names in it you should know the techniques in it
it is wonderful also these two guys
Bob Martin over here and martin fowler over here are just the best damn
software authors there are no one writes about software and programming better
than these guys
in my opinion finally this is a great book
this one is like the least known of those three books
the other two a lot of people have read or at least have heard of this book is
sort of an unknown
it's awesome if the beginner book it's an advanced book it talks about the
ideas in
oo programming and TD that I sort of roughly new implicitly but very cogently
very explicitly it made these ideas make a lot more sense and presented them in
ways that never thought of and give you a lot of really good rule of thumb so
check out those books refactor when you got to do it right some good code
thank you