Code Stinkers
Anonymous
Mark Cornick • Viget Labs
RubyNation • June 12, 2009
Friday, June 12, 2009
Hello
Friday, June 12, 2009
My name is Mark,
and I am a code stinker.
Friday, June 12, 2009
How I got here
Friday, June 12, 2009
10 years in sysadmin
before becoming a developer
Friday, June 12, 2009
Mostly self-taught;
almost never used my CS degree
Friday, June 12, 2009
A very Brief Introduction To
Edsger W. Dijkstra
who wi\" be quoted a few times
in the next few slides
Friday, June 12, 2009
Edsger W.
Dijkstra
(1930-2002)
Notable for:
• Shortest path algorithm
• Reverse Polish notation
• Being a curmudgeon
Friday, June 12, 2009
How Do We Tell Truths
That Might Hurt?
Friday, June 12, 2009
My Back Pages
Or, “I was so much lamer then;
I’m less lame than that now”
Friday, June 12, 2009
BASIC
Friday, June 12, 2009
10 TEXT:HOME
20 GOSUB 100
30 END
100 ?“YES I JUST GOSUBBED FOR
NO REASON WHATSOEVER”
110 RETURN
Friday, June 12, 2009
“It is practica\"y impossible to teach
good programming style to students
that have had prior exposure to
BASIC: as potential programmers
they are menta\"y mutilated beyond
hope of regeneration.”
– Edsger W. Dijkstra
Friday, June 12, 2009
COBOL
Friday, June 12, 2009
IDENTIFICATION DIVISION.
PROGRAM-ID. COBOL-EXAMPLE.
PROCEDURE DIVISION.
MAIN.
IF YEAR <= 1991
DISPLAY 'COBOL! Argh!'.
STOP RUN.
Friday, June 12, 2009
“The use of COBOL cripples the
mind; its teaching should, therefore,
be regarded as a criminal offense.”
– Edsger W. Dijkstra
Friday, June 12, 2009
FORTRAN
Friday, June 12, 2009
C HAD ENOUGH YET?
PROGRAM UGLY
WRITE(UNIT=*, FMT=*) 'FORTRAN!'
END
Friday, June 12, 2009
“[T]he infantile disorder”, by now
nearly 20 years old, is hopelessly
inadequate for whatever computer
application you have in mind
today: it is now too clumsy, too
risky, and too expensive to use.”
– Edsger W. Dijkstra
Friday, June 12, 2009
Perl
Friday, June 12, 2009
#/usr/bin/env perl
#
# (Insert some convoluted JAPH
# code/line noise here.)
Friday, June 12, 2009
Dijkstra doesn’t mention Perl,
but I don’t think he would have
liked it.
Friday, June 12, 2009
There’s More Than
One Way To Do It,
but many of them
are Wrong
Friday, June 12, 2009
What Sysadmins
Do All Day
and how it explains
the code they write
Friday, June 12, 2009
Friday, June 12, 2009
Get it done. Put the fire out.
Then forget about it.
Friday, June 12, 2009
Short, quick scripts
#!/bin/sh
for year in 1996 1997 1998 1999 2000; do
rm -rf backups/${year}
done
echo \"Sorry, all backups from the pretend Internet money
era have been purged.\" | /usr/ucb/Mail -s \"Your restore
request\" boss@example.com
Friday, June 12, 2009
Sysadmins aren’t agile
Friday, June 12, 2009
Sysadmins don’t do OO
Friday, June 12, 2009
Some Object-Oriented
Languages I Have Not Known
Friday, June 12, 2009
C++
Friday, June 12, 2009
Friday, June 12, 2009
Python
Friday, June 12, 2009
Python seemed cool to me,
but I didn’t get it.
Friday, June 12, 2009
Java
Friday, June 12, 2009
I never learned Java.
Really.
Friday, June 12, 2009
The Predicament
Friday, June 12, 2009
Bad practice
as a non-developer
carries over
Friday, June 12, 2009
Dijkstra was right:
I never learned good style
Friday, June 12, 2009
Code
Smells
Friday, June 12, 2009
The Result
Friday, June 12, 2009
My code needs a lot of
refactoring
Friday, June 12, 2009
Maintenance is
difficult
Friday, June 12, 2009
Fellow developers laugh and
kick sand in my face
Friday, June 12, 2009
The Goal
Friday, June 12, 2009
Write quality code
the first time
Friday, June 12, 2009
Minimize the need for
refactoring
Friday, June 12, 2009
No more sand
kicked in my face!
Friday, June 12, 2009
On Refactoring
(a brief philosophical interlude)
Friday, June 12, 2009
Refactoring:
improving the non-functional
characteristics of the code
without screwing up the
functional parts.
Friday, June 12, 2009
Refactoring
An essential part
of a developer’s
healthy diet.
Friday, June 12, 2009
BUT
Friday, June 12, 2009
Refactoring is like sugar.
It’s sweet,
but too much is bad for you.
Friday, June 12, 2009
WHY?
Friday, June 12, 2009
Time spent refactoring could
be spent actua\"y coding.
Friday, June 12, 2009
Time spent refactoring could
be spent factoring.
Friday, June 12, 2009
I do love refactoring, but
I make avoiding it a goal
Friday, June 12, 2009
Writing Better Code
Or, “It hurts when you do that? Don’t do that.”
Friday, June 12, 2009
Number one:
Friday, June 12, 2009
TEST
Friday, June 12, 2009
No, really.
Friday, June 12, 2009
TEST!
Friday, June 12, 2009
99 out of 100
developers agree:
writing tests
leads to
writing better code
Friday, June 12, 2009
Test First
Friday, June 12, 2009
Testing Philosophies
And Frameworks
Friday, June 12, 2009
TDD, BDD, DDD,
TATFT, LMNOP.
Friday, June 12, 2009
Test::Unit, RSpec, minitest,
micronaut, bacon.
Friday, June 12, 2009
Fettucine, linguine,
martini, bikini.
Friday, June 12, 2009
I’m not going to tell you
which test framework to use*
* but I like Test::Unit with Shoulda and Factory Girl
Friday, June 12, 2009
Pick one
and stay with it.
Friday, June 12, 2009
Still don’t know
which one to use?
Find out what
your peers use, and
use that one.
Friday, June 12, 2009
At first, writing tests
was completely foreign to me.
Friday, June 12, 2009
Until I decided to
appeal to my own ego.
Friday, June 12, 2009
I like being right.
(Don’t you?)
Friday, June 12, 2009
Testing is an
automated way of
proving I’m right.
(Or, at least, that my code is.)
Friday, June 12, 2009
Proving my code correct
motivates me
to keep writing
good code.
Friday, June 12, 2009
Be a good primate.
Use your tools.
Friday, June 12, 2009
Tools can help you
improve your code.
Friday, June 12, 2009
BUT
Friday, June 12, 2009
Tools cannot write good code
for you.
Friday, June 12, 2009
A Few Tools I Like
Or, “I got your take-home message right here”
Friday, June 12, 2009
RCov
gem install relevance-rcov
http://github.com/relevance/rcov
Friday, June 12, 2009
Checks code coverage
in your tests.
Friday, June 12, 2009
Checks code coverage
in your tests.
Friday, June 12, 2009
Why RCov Helps
• To reach full coverage,
you write more tests.
• As you write more tests,
you fix more problems.
• As you fix more problems,
you write better code!
Friday, June 12, 2009
Things To Look Out For
• RCov isn’t perfect.
• It will sometimes miss code that is
covered.
• It is easy to cheat.
• Just because it’s covered doesn’t mean the
code is awesome.
Friday, June 12, 2009
Reek
gem install reek
http://github.com/kevinrutherford/reek
Friday, June 12, 2009
Finds common smells
in your code.
\"app/controllers/application_controller.rb\" -- 3 warnings:
ApplicationController#username_for calls user.username multiple times (Duplication)
ApplicationController#username_for doesn't depend on instance state (Utility Function)
ApplicationController#username_for refers to user more than self (Feature Envy)
\"app/controllers/groups_controller.rb\" -- 5 warnings:
GroupsController#show calls params multiple times (Duplication)
GroupsController#show calls params[:page] multiple times (Duplication)
GroupsController#show calls params[:page].to_i multiple times (Duplication)
GroupsController#show has approx 6 statements (Long Method)
GroupsController#show/block/block is nested (Nested Iterators)
\"app/controllers/sessions_controller.rb\" -- 2 warnings:
SessionsController#create calls flash multiple times (Duplication)
SessionsController#create has approx 8 statements (Long Method)
\"app/controllers/user_feeds_controller.rb\" -- 3 warnings:
UserFeedsController#create calls logger multiple times (Duplication)
UserFeedsController#create has approx 6 statements (Long Method)
UserFeedsController#create has the variable name 'e' (Uncommunicative Name)
\"app/helpers/application_helper.rb\" -- 14 warnings:
ApplicationHelper::feed_date_for doesn't depend on instance state (Utility Function)
ApplicationHelper::feed_date_for refers to date more than self (Feature Envy)
ApplicationHelper::feedstitch_group_for doesn't depend on instance state (Utility Function)
ApplicationHelper::feedstitch_group_for refers to user more than self (Feature Envy)
ApplicationHelper::link_to_group_feed has 4 parameters (Long Parameter List)
Friday, June 12, 2009 ApplicationHelper::name_for doesn't depend on instance state (Utility Function)
Why Reek Helps
• Reek finds common
anti-patterns.
• Anti-patterns are bad habits
that are worth breaking.
• Fewer bad habits ==
better code!
Friday, June 12, 2009
Things To Look Out For
• Reek also isn’t perfect.
• It false-positives often.
• It can only make suggestions.
• It doesn’t catch all possible code smells.
Friday, June 12, 2009
Let’s Talk About
How My Code Smells
Or, The Part Of The Presentation That Is Potentia\"y
Very Embarrassing To The Presenter
Friday, June 12, 2009
MVC
Learn it. Know it. Live it.
Friday, June 12, 2009
Obese Controllers
Friday, June 12, 2009
Do As I Say,
Not As I Did
Actual client project, 2007 (I am not making this up):
• One controller
• One method
• ~130 LOC
• Actual comment:
# OPTIMIZE: this is ugly
Friday, June 12, 2009
Why???
• Didn’t understand the domain.
• Not thinking in object-oriented
paradigm.
• Not thinking in MVC.
• Not pairing.
• Lousy tests.
Friday, June 12, 2009
What Really Goes
In A Controller?
• Code you need to respond to a
web request and render the result
• Not business logic
• Not complex operations on
objects
Friday, June 12, 2009
Controller Liposuction
• Everything in its right place.
• When you see yourself doing
business logic, move it to the model!
• When you see yourself defining
view logic, move it to the view/
helper!
Friday, June 12, 2009
BIG
METH-
ODS
Friday, June 12, 2009
Finding Big Methods
• Too much stuff happening; too
many concerns
• Too many LOC to comprehend
in a glance
• Logic inside logic
Friday, June 12, 2009
def response
if @response.nil?
@final_response = false
current = source
path = source.query.nil? ? source.path : \"#{source.path}?#{source.query}\"
until @final_response
Net::HTTP.start(current.host, current.port) do |http|
@response = http.get(path, 'User-Agent' => user_agent)
if @response.header['location']
current = URI.parse(@response.header['location'])
path = current.query.nil? ? current.path : \"#{current.path}?#{current.query}\"
else
@final_response = true
end
end
end
end
@response
end
Friday, June 12, 2009
Small Pieces,
Loosely Joined
Friday, June 12, 2009
Remember
UNIX?
Small tools doing one
job well ⇒ small
methods doing one
job well
Friday, June 12, 2009
Name Methods To
Communicate Intent
thing.expires_at <
Time.now thing.expired?
user.has_accepted_terms &&
!user.suspended
user.can_sign_in?
Friday, June 12, 2009
Don’t Do Too Much
In A Method
• When you see a method getting too
long, break it into sma\"er methods.
• Hint: look for excessive indentation
and nested ifs.
• Hint: a method shouldn’t come close
to filling your editor window.
Friday, June 12, 2009
def self.user_agent
\"Awesome App Ruby/#{RUBY_VERSION}\"
end
def self.maximum_redirects
4
end
def initialize(url)
@url = url
end
def endpoint_for(uri)
endpoint = uri.path.sub(/^\\/?$/, '/')
endpoint += \"?#{uri.query}\" unless uri.query.blank?
endpoint
end
def fetch(url, redirects_remaining)
return if redirects_remaining == 0
begin
uri = URI.parse(url)
response = Net::HTTP.start(uri.host, uri.port) do |http|
http.get(endpoint_for(uri), {'User-Agent' => self.class.user_agent})
end
if response.is_a?(Net::HTTPRedirection)
response = fetch(response['location'], redirects_remaining - 1)
end
rescue URI::InvalidURIError
RAILS_DEFAULT_LOGGER.warn \"Error parsing URL: '#{url}'\"
end
response
end
def response
@response ||= fetch(@url, self.class.maximum_redirects)
end
Friday, June 12, 2009
Self-Review
• Don’t check it in if the tests fail.
• Use continuous integration to keep
yourself honest. (more on this later)
• Look over all your changes before you
commit.
• If you miss something and you’re using
Git, fix it and git commit --amend
Friday, June 12, 2009
Peer Review
• Pair-program whenever you can. Pair
programming comes with built-in peer
review.
• Do regular code reviews with your peers.
During active development, weekly is
good.
• Listen to criticism. Don’t take it persona\"y.
No one’s perfect.
Friday, June 12, 2009
Quality Takes
Time
By law, straight bourbon
must be aged in new, charred
oak barrels for at least two
years. Anything less yields
just whiskey, not bourbon.
Friday, June 12, 2009
Sysadmins are used
to fighting fires
Friday, June 12, 2009
Firefighting is
not
the way to lasting code
quality.
Friday, June 12, 2009
Firefighting results
in code that is
“just whiskey”
(and maybe not even that)
Friday, June 12, 2009
You may not have
two to four years,
but you sti\"
shouldn’t rush
Friday, June 12, 2009
Working In A
Vacuum
Most of us don’t.
No one should.
Friday, June 12, 2009
Ethic of
Reciprocity
Friday, June 12, 2009
The
Golden
Rule
Friday, June 12, 2009
Code unto others
as you would have them
code unto you.
Friday, June 12, 2009
You hate fixing
other people’s
bad code.
Friday, June 12, 2009
Don’t make other
people fix yours!
Friday, June 12, 2009
One more tool:
Continuous Integration
Friday, June 12, 2009
Every time the code changes,
run the tests.
Friday, June 12, 2009
Know where a build broke
and who was responsible.
Friday, June 12, 2009
CI is a good idea
even if you work alone.
Friday, June 12, 2009
Some CI Options
• CruiseControl.rb,
cruisecontrolrb.thoughtworks.com
• Integrity, integrityapp.com
• RunCodeRun (hosted!),
runcoderun.com
• runcoderun.com/mcornick
Friday, June 12, 2009
Let’s Wrap This Up
Or, “I Hope You Know This Wi\" Go Down On Your
Permanent Record”
Friday, June 12, 2009
Where we come from
influences where we go.
Friday, June 12, 2009
There’s still time to change
the road you’re on.
Friday, June 12, 2009
Test.
No matter how, just do it.
Friday, June 12, 2009
Use tools to help you,
not to do work for you.
Friday, June 12, 2009
Recognize anti-patterns.
Avoid them.
Friday, June 12, 2009
Play well with others.
Friday, June 12, 2009
Take pride in your work.
Appeal to your own ego.
Friday, June 12, 2009
Learn from mistakes.
Learn from refactoring.
Friday, June 12, 2009
Put it all together and
you will write better code.
Friday, June 12, 2009
The End.
This has been “Code Stinkers Anonymous”
by Mark Cornick. Thank you!
http://objectsinmirrors.com/
http://twitter.com/mcornick
Please rate this talk on SpeakerRate!
http://speakerrate.com/talks/1170
Friday, June 12, 2009
As a professional developer, especially one who wor more
As a professional developer, especially one who works in Ruby, you hear about code quality all the time. You learn that testing your code and making it easy to maintain are the path to success. You know about TDD, BDD, TATFT and LMNOP. You learn to cycle from red to green to refactoring. We all do our best to write quality, maintainable, reusable code. We're all human, though; some of us slip, and some of us have had to work hard at preventing code smells. In this talk, I'll talk about how I learned to program, how going pro exposed flaws in my coding style, and how I'm working to improve my code quality, sharing some of my old stinky code, the better, refactored versions, and the lessons I've learned in honing my craft. less
0 comments
Post a comment