SlideShare ist ein Scribd-Unternehmen logo
1 von 135
Downloaden Sie, um offline zu lesen
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 wiquot; 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 practicaquot;y impossible to teach
                        good programming style to students
                        that have had prior exposure to
                        BASIC: as potential programmers
                        they are mentaquot;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 quot;Sorry, all backups from the pretend Internet money
                        era have been purged.quot; | /usr/ucb/Mail -s quot;Your restore
                        requestquot; 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 actuaquot;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.
                        quot;app/controllers/application_controller.rbquot; -- 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)

                        quot;app/controllers/groups_controller.rbquot; -- 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)

                        quot;app/controllers/sessions_controller.rbquot; -- 2 warnings:
                        SessionsController#create calls flash multiple times (Duplication)
                        SessionsController#create has approx 8 statements (Long Method)

                        quot;app/controllers/user_feeds_controller.rbquot; -- 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)

                        quot;app/helpers/application_helper.rbquot; -- 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 Potentiaquot;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
xxxxx XxxxxxXxxxxxxxxx < XxxxxxxxxxxXxxxxxxxxx # redacted for public publication
                          xxxxxx_xxxxxx :xxxxx_xxx_xxxx
                          xxxxxx_xxxxxx :xxxxxxx_xxx_xx_xxxxxxx, :xxxx => [:xxxx]‚Ä®
                          xxx xxxx
                            xxxxxx.xxxxxx(:xx_xxx_xxxxxxx)
                            xxxxxx[:xxxxxx] ||= Xxxxxxx::XXXXXX_XXXXXX
                            @xxxxxxx_xxxxxxx = xxxxxx.xxxxxx(:xxxxxxx_xxxxxxx)
                            xx xxxxxx[:xxxxxxxx_xxxx_xxxxxxx].xxx?
                              @xxxx_xxxxxxxxxx_xxx_xxxxxxx = xxxx
                            xxxx
                              @xxxx_xxxxxxxxxx_xxx_xxxxxxx = xxxxxx[:xxxxxxxx_xxxx_xxxxxxx].xxxxxxx?(quot;xxxx_xxxxxxxxxxquot;)
                              xx @xxxx_xxxxxxxxxx_xxx_xxxxxxx
                                 xxxxxx[:xxxxxxxx_xxxx_xxxxxxx].xxxxxx(quot;xxxx_xxxxxxxxxxquot;)
                                 xxxxxxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxxxxx_xxxx_xxxxx']]
                                 xx xxxxxxxx_xxxxxx.xxxxxx > 9
                                   xxxxxxxx_xxxxxx.xxxx{|x,x| x[1] <=> x[1]}[9..-1].xxxx xx |x|
                                     xxxxxx[:xxxxxxxx_xxxx_xxxxxxx] << x[0]
                                   xxx
                                 xxx
                              xxx
                            xxx‚Ä®
                            xx xxxxxx[:xxxx_xxxxxxx].xxx?
                              @xxxx_xxxxxx_xxx_xxxxxxx = xxxx
                            xxxx
                              @xxxx_xxxxxx_xxx_xxxxxxx = xxxxxx[:xxxx_xxxxxxx].xxxxxxx?(quot;xxxx_xxxxxxquot;)
                              xx @xxxx_xxxxxx_xxx_xxxxxxx
                                 xxxxxx[:xxxx_xxxxxxx].xxxxxx(quot;xxxx_xxxxxxquot;)
                                 xxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxx_xxxxx']]
                                 xx xxxx_xxxxxx.xxxxxx > 19
                                   xxxx_xxxxxx.xxxx{|x,x| x[1] <=> x[1]}[19..-1].xxxx xx |x|
                                     xxxxxx[:xxxx_xxxxxxx] << x[0]
                                   xxx
                                 xxx
                              xxx
                            xxx‚Ä®
                            @xxxxxx = xxxxxxx_xxxxxx(xxxxxx[:xxxxxxxx])
                            xxxxxx @xxxxxx.xxx?
                              xxxxxx[:xxxxxxxx] = xxxxxxxxxx_xxxxxxx(@xxxxxx)
                              xxxxxxx_xxxxxx(:xxxxxx => xxxxxx[:xxxxxx], :xxxxxx_xxx => xxxxxx[:xxxxxx_xxx],
                              :xx_xxxxxxxx => xxxxxx[:xx_xxxxxxxx], :xxxxx => xxxx, :xxxxxx => xxxxxx[:xxxxxx].xx_x)
                            xxxx
                              xxxxx[:xxxxxx] = quot;Xxxxxxx xxxxxxxx, xxxxxx xxx xxxx xxxxxx xxxxx.quot;
                              @xxxxxxxx = [].xxxxxxxx(:xxxx => 1)
                            xxx
                            @xxxx_xxxxxxx = @xxxxxxxx[0,3]
                            @xxxxxxxxxx_xxxxxxx = (@xxxxxxxx[3,(Xxxxxxx.xxx_xxxx - 3)] || [])
                            @xxxxxxxx = @xxxxxxxx.xxxxxx
                            xx @xxxxxxxx.xxxxxxx_xx?(:xxxxxx) && !@xxxxxxxx.xxxxxx.xxx? && !@xxxxxxxx.xxxxxx.xxxxx?
                              @xxxxx_xxxxxx = Xxxx[*@xxxxxxxx.xxxxxx['xxxxx_xxxxx']]
                              @xxxx_xxxxxx = Xxxx[*@xxxxxxxx.xxxxxx['xxxx_xxxxx']]
                              @xxxxxxxx_xxxx_xxxxxx = Xxxx[*@xxxxxxxx.xxxxxx['xxxxxxxx_xxxx_xxxxx']]

                             xxxxxx_xxxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxx_xxxxx']]
                             xxxxxx_xxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxx_xxxxx']]
                             xxxxxx_xxxxxxxx_xxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxxxxx_xxxx_xxxxx']]‚Ä®
                             xxxxxx_xxxxx_xxxxxx.xxxx xx |x,x|
                               @xxxxx_xxxxxx[x] = 0 xxxxxx @xxxxx_xxxxxx.xxx_xxx?(x)
                             xxx
                             xxxxxx_xxxx_xxxxxx.xxxx xx |x,x|
                               @xxxx_xxxxxx[x] = 0 xxxxxx @xxxx_xxxxxx.xxx_xxx?(x)
                             xxx
                             xxxxxx_xxxxxxxx_xxxx_xxxxxx.xxxx xx |x,x|
                               @xxxxxxxx_xxxx_xxxxxx[x] = 0 xxxxxx @xxxxxxxx_xxxx_xxxxxx.xxx_xxx?(x)
                             xxx‚Ä®
                             @xxxxx_xxxxxx = @xxxxx_xxxxxx.xxxx
                             # OPTIMIZE: this is ugly
                             @xxxx_xxxxxx = @xxxx_xxxxxx.xxxx{|x,x| quot;#{xxxxxxx('%09x',xxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}quot; <=> quot;#{xxxxxxx('%09x',xxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}quot;}
                             @xxxxxxxx_xxxx_xxxxxx = @xxxxxxxx_xxxx_xxxxxx.xxxx{|x,x| quot;#{xxxxxxx('%09x',xxxxxx_xxxxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}quot; <=> quot;#{xxxxxxx('%09x',xxxxxx_xxxxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}quot;}‚Ä®
                             @xxxxxxxx_xxxxxx = @xxxxxxxx.xxxxxx

                              xxxxxxxx_xxx = []
                              xxxxxxxx_xxx = []
                              xxxxxx xxxxxxx[:xxxxxx]['xxxxxxxx_xxxxx_xxxxx'].xxx?
                                 xxxxxxxx_xxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxxxxx_xxxxx_xxxxx']].xxxxxx_xx{|x,x| x.xxxxx?}.xxxxxxx{|x,x| x.xx_x}
                              xxx
                              xxxxxx xxxxxxx[:xxxxxx]['xxxxxxxx_xxxxx_xxxxx'].xxx?
                                 xxxxxxxx_xxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxxxxx_xxxxx_xxxxx']].xxxxxx_xx{|x,x| x.xxxxx?}.xxxxxxx{|x,x| x.xx_x}
                              xxx
                              xxxxxxx_xxxxxxx = []
                              (xxxxxxxx_xxx+xxxxxxxx_xxx).xxxx xx |xxx|
                                 xxxxx
                                   xxxxxxx_xxxxxxx << Xxxxxx.xxxx(xxx)
                                 xxxxxx XxxxxxXxxxxx::XxxxxxXxxXxxxx
                                   @xxxxxxxx.xxxx{|x| x.xxxxx_xxx_xxxxx}
                                 xxx
                              xxx
                              @xxxxxxx = @xxxxxxx_xxxx.xxxxxxx_xxxxxxx.xxxxxx{|xx| xxxxxxx_xxxxxxx.xxxxxxx?(xx.xxxxxx) && xx.xxxxxx.xxxxxxxxxx_xxxx=='Xxxx' && @xxxxxxx_xxxx.xxxxxxxx_xxx_xxxxxxx_xxxx.xxxxxxx?
                        (xx.xxxxxx.xxxxxxxxxx.xxxxxxxx_xxx)}
                              @xxx_xxxxxxx = @xxxxxxx_xxxx.xxxxxxx_xxxxxxx.xxxxxx{|xx| xxxxxxx_xxxxxxx.xxxxxxx?(xx.xxxxxx) && (xx.xxxxxx.xxxxxxxxxx_xxxx!='Xxxx' || !@xxxxxxx_xxxx.xxxxxxxx_xxx_xxxxxxx_xxxx.xxxxxxx?
                        (xx.xxxxxx.xxxxxxxxxx.xxxxxxxx_xxx))}
                              xxxx_xxxxxxx_xxx = @xxxxxxx.xxxxxxx{|xx| xx.xxxxxx.xx} & (xxxxxx[:xxxxxx_xxx] || []).xxxxxxx{|xx| xx.xx_x}
                              xxxx_xxx_xxxxxxx_xxx = @xxx_xxxxxxx.xxxxxxx{|xx| xx.xxxxxx.xx} & (xxxxxx[:xxxxxx_xxx] || []).xxxxxxx{|xx| xx.xx_x}
                              @xxxx_xxxxxxx_xxxxx = xxxx_xxxxxxx_xxx.xxxxxx
                              @xxxx_xxx_xxxxxxx_xxxxx = xxxx_xxx_xxxxxxx_xxx.xxxxxx
                              @xxxx_xxxxxx_xxx = xxxx_xxxxxxx_xxx + xxxx_xxx_xxxxxxx_xxx
                              @xxxxxxx.xxxx!{|x,x| (@xxxx_xxxxxx_xxx.xxxxxxx?(x.xxxxxx_xx) ? 1 : 0) <=> (@xxxx_xxxxxx_xxx.xxxxxxx?(x.xxxxxx_xx) ? 1 : 0)}
                              @xxx_xxxxxxx.xxxx!{|x,x| (@xxxx_xxxxxx_xxx.xxxxxxx?(x.xxxxxx_xx) ? 1 : 0) <=> (@xxxx_xxxxxx_xxx.xxxxxxx?(x.xxxxxx_xx) ? 1 : 0)}
                              @xxx_xxxxxxx = xxxxxxx_xxxxxxx - ([@xxxxxxx_xxxx.xxxxxx] + @xxxxxxx.xxxxxxx{|x| x.xxxxxx} + @xxx_xxxxxxx.xxxxxxx{|xx| xx.xxxxxx})
                              @xxx_xxxxxxx = @xxx_xxxxxxx.xxxxxx{|x| x.xxxxxxxxxx_xxxx == 'Xxxxxxx'}
                              @xxx_xxxxxxx.xxxx!{|x,x| (x.xxxxxxxxxx_xxxx=='Xxxxx' ? 1 : 0) <=> (x.xxxxxxxxxx_xxxx=='Xxxxx' ? 1 : 0)}
                              @xxx_xxxxxxx = @xxx_xxxxxxx[0,3]
                            xxxx
                              @xxxxx_xxxxxx = []
                              @xxxx_xxxxxx = []
                              @xxxxxxxx_xxxx_xxxxxx = []
                              @xxxxxxxx_xxxxxx = []
                              @xxxxxxx = []
                              @xxx_xxxxxxx = []
                              @xxxx_xxxxxx_xxx = []
                              @xxx_xxxxxxx = []
                              @xxxx_xxxxxxx_xxxxx = 0
                              @xxxx_xxx_xxxxxxx_xxxxx = 0
                            xxx
                            @xxxxxxx_xxxxxxxx_xxxxxxx = []
                            @xxxxxxx_xxxx_xxxxxxx = []
                            @xxxxxxx_xxxxx_xxxxxxx = []
                            xx xxxxxx[:xxxxxxxx_xxxx_xxxxxxx] && xxxxxx[:xxxxxxxx_xxxx_xxxxxxx].xxxx.xxxxxx != @xxxxxxxx_xxxx_xxxxxx.xxxxxx
                              @xxxxxxx_xxxxxxxx_xxxxxxx = xxxxxx[:xxxxxxxx_xxxx_xxxxxxx]
                            xxx
                            xx xxxxxx[:xxxx_xxxxxxx] && xxxxxx[:xxxx_xxxxxxx].xxxx.xxxxxx != @xxxx_xxxxxx.xxxxxx
                              @xxxxxxx_xxxx_xxxxxxx = xxxxxx[:xxxx_xxxxxxx]
                            xxx
                            xx xxxxxx[:xxxxx_xxxxxxx] && xxxxxx[:xxxxx_xxxxxxx].xxxx.xxxxxx != @xxxxx_xxxxxx.xxxxxx
                              @xxxxxxx_xxxxx_xxxxxxx = xxxxxx[:xxxxx_xxxxxxx]
                            xxx
                            xx @xxxxxxx_xxxxxxxx_xxxxxxx.xxxxx? && @xxxxxxx_xxxx_xxxxxxx.xxxxx? && @xxxxxxx_xxxxx_xxxxxxx.xxxxx?
                              xxxxxx [xxxxxx[:xxxxxxxx_xxxx_xxxxxxx],xxxxxx[:xxxx_xxxxxxx],xxxxxx[:xxxxx_xxxxxxx]] == [xxx,xxx,xxx]
                                 @xxxxxxx_xxxxxxx = xxxx
                              xxx
                            xxx
                          xxx
                        xxx‚Ä®




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 : quot;#{source.path}?#{source.query}quot;
             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 : quot;#{current.path}?#{current.query}quot;
                 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 smaquot;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
             quot;Awesome App Ruby/#{RUBY_VERSION}quot;
           end

           def self.maximum_redirects
             4
           end

           def initialize(url)
             @url = url
           end

           def endpoint_for(uri)
             endpoint = uri.path.sub(/^/?$/, '/')
             endpoint += quot;?#{uri.query}quot; 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 quot;Error parsing URL: '#{url}'quot;
             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 personaquot;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 stiquot;
                 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 Wiquot; 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

Weitere ähnliche Inhalte

Andere mochten auch

Andere mochten auch (6)

Cobol
CobolCobol
Cobol
 
Presentación COBOL
Presentación COBOLPresentación COBOL
Presentación COBOL
 
CURSO COBOL MAINFRAME
CURSO COBOL MAINFRAMECURSO COBOL MAINFRAME
CURSO COBOL MAINFRAME
 
Cobol power
Cobol powerCobol power
Cobol power
 
Manula de cobol
Manula de cobolManula de cobol
Manula de cobol
 
5 características del lenguaje cobol
5 características del lenguaje cobol5 características del lenguaje cobol
5 características del lenguaje cobol
 

Ähnlich wie Code Stinkers Anonymous

DelveUI Slides
DelveUI SlidesDelveUI Slides
DelveUI Slidesjkosoy
 
Presentation by Dennis Wingo on the Lunar Orbiter Image Recovery Project at t...
Presentation by Dennis Wingo on the Lunar Orbiter Image Recovery Project at t...Presentation by Dennis Wingo on the Lunar Orbiter Image Recovery Project at t...
Presentation by Dennis Wingo on the Lunar Orbiter Image Recovery Project at t...Keith Cowing
 
Of Rats And Dragons
Of Rats And DragonsOf Rats And Dragons
Of Rats And DragonsSean Cribbs
 
Developer Tools State of the Union
Developer Tools State of the UnionDeveloper Tools State of the Union
Developer Tools State of the UnionAtlassian
 
Atlassian - A Different Kind Of Software Company
Atlassian - A Different Kind Of Software CompanyAtlassian - A Different Kind Of Software Company
Atlassian - A Different Kind Of Software CompanyMike Cannon-Brookes
 
From concept to development
From concept to developmentFrom concept to development
From concept to developmentThomas Joos
 
iFixit @ Monterey Bay Aquarium
iFixit @ Monterey Bay AquariumiFixit @ Monterey Bay Aquarium
iFixit @ Monterey Bay AquariumKyle Wiens
 
Teaching Creative Problem Solving Skills.
Teaching Creative Problem Solving Skills.Teaching Creative Problem Solving Skills.
Teaching Creative Problem Solving Skills.Bernie Dodge
 
Building A Framework On Rack
Building A Framework On RackBuilding A Framework On Rack
Building A Framework On RackMatt Todd
 
Flip (Video) For West Chester University
Flip (Video) For West Chester UniversityFlip (Video) For West Chester University
Flip (Video) For West Chester UniversityChris Penny
 
BDW: How To Pitch Your Ideas
BDW: How To Pitch Your IdeasBDW: How To Pitch Your Ideas
BDW: How To Pitch Your IdeasDavid Cohen
 
Get Up And Move Quantified Self 12.7 Pdf
Get Up And Move Quantified Self 12.7 PdfGet Up And Move Quantified Self 12.7 Pdf
Get Up And Move Quantified Self 12.7 PdfJen McCabe
 
Mobile Development with Icenium
Mobile Development with IceniumMobile Development with Icenium
Mobile Development with IceniumBill Condo
 
The Beauty of Bootstrapping - Doing it Anyway
The Beauty of Bootstrapping - Doing it AnywayThe Beauty of Bootstrapping - Doing it Anyway
The Beauty of Bootstrapping - Doing it AnywayChris Schultz
 
Well-designed Good(s)
Well-designed Good(s)Well-designed Good(s)
Well-designed Good(s)Tim Salazar
 
Is Agile The New Waterfall
Is Agile The New WaterfallIs Agile The New Waterfall
Is Agile The New Waterfallfrankmt
 
component: ruby gems for the browser
component: ruby gems for the browsercomponent: ruby gems for the browser
component: ruby gems for the browserTimothy Oxley
 
Spring in-the-cloud
Spring in-the-cloudSpring in-the-cloud
Spring in-the-cloudJoshua Long
 

Ähnlich wie Code Stinkers Anonymous (20)

DelveUI Slides
DelveUI SlidesDelveUI Slides
DelveUI Slides
 
Making a living with WordPress in 2009
Making a living with WordPress in 2009Making a living with WordPress in 2009
Making a living with WordPress in 2009
 
Presentation by Dennis Wingo on the Lunar Orbiter Image Recovery Project at t...
Presentation by Dennis Wingo on the Lunar Orbiter Image Recovery Project at t...Presentation by Dennis Wingo on the Lunar Orbiter Image Recovery Project at t...
Presentation by Dennis Wingo on the Lunar Orbiter Image Recovery Project at t...
 
Of Rats And Dragons
Of Rats And DragonsOf Rats And Dragons
Of Rats And Dragons
 
Developer Tools State of the Union
Developer Tools State of the UnionDeveloper Tools State of the Union
Developer Tools State of the Union
 
Atlassian - A Different Kind Of Software Company
Atlassian - A Different Kind Of Software CompanyAtlassian - A Different Kind Of Software Company
Atlassian - A Different Kind Of Software Company
 
From concept to development
From concept to developmentFrom concept to development
From concept to development
 
iFixit @ Monterey Bay Aquarium
iFixit @ Monterey Bay AquariumiFixit @ Monterey Bay Aquarium
iFixit @ Monterey Bay Aquarium
 
Teaching Creative Problem Solving Skills.
Teaching Creative Problem Solving Skills.Teaching Creative Problem Solving Skills.
Teaching Creative Problem Solving Skills.
 
Building A Framework On Rack
Building A Framework On RackBuilding A Framework On Rack
Building A Framework On Rack
 
All The Little Pieces
All The Little PiecesAll The Little Pieces
All The Little Pieces
 
Flip (Video) For West Chester University
Flip (Video) For West Chester UniversityFlip (Video) For West Chester University
Flip (Video) For West Chester University
 
BDW: How To Pitch Your Ideas
BDW: How To Pitch Your IdeasBDW: How To Pitch Your Ideas
BDW: How To Pitch Your Ideas
 
Get Up And Move Quantified Self 12.7 Pdf
Get Up And Move Quantified Self 12.7 PdfGet Up And Move Quantified Self 12.7 Pdf
Get Up And Move Quantified Self 12.7 Pdf
 
Mobile Development with Icenium
Mobile Development with IceniumMobile Development with Icenium
Mobile Development with Icenium
 
The Beauty of Bootstrapping - Doing it Anyway
The Beauty of Bootstrapping - Doing it AnywayThe Beauty of Bootstrapping - Doing it Anyway
The Beauty of Bootstrapping - Doing it Anyway
 
Well-designed Good(s)
Well-designed Good(s)Well-designed Good(s)
Well-designed Good(s)
 
Is Agile The New Waterfall
Is Agile The New WaterfallIs Agile The New Waterfall
Is Agile The New Waterfall
 
component: ruby gems for the browser
component: ruby gems for the browsercomponent: ruby gems for the browser
component: ruby gems for the browser
 
Spring in-the-cloud
Spring in-the-cloudSpring in-the-cloud
Spring in-the-cloud
 

Kürzlich hochgeladen

What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 

Kürzlich hochgeladen (20)

What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 

Code Stinkers Anonymous

  • 1. Code Stinkers Anonymous Mark Cornick • Viget Labs RubyNation • June 12, 2009 Friday, June 12, 2009
  • 3. My name is Mark, and I am a code stinker. Friday, June 12, 2009
  • 4. How I got here Friday, June 12, 2009
  • 5. 10 years in sysadmin before becoming a developer Friday, June 12, 2009
  • 6. Mostly self-taught; almost never used my CS degree Friday, June 12, 2009
  • 7. A very Brief Introduction To Edsger W. Dijkstra who wiquot; be quoted a few times in the next few slides Friday, June 12, 2009
  • 8. Edsger W. Dijkstra (1930-2002) Notable for: • Shortest path algorithm • Reverse Polish notation • Being a curmudgeon Friday, June 12, 2009
  • 9. How Do We Tell Truths That Might Hurt? Friday, June 12, 2009
  • 10. My Back Pages Or, “I was so much lamer then; I’m less lame than that now” Friday, June 12, 2009
  • 12. 10 TEXT:HOME 20 GOSUB 100 30 END 100 ?“YES I JUST GOSUBBED FOR NO REASON WHATSOEVER” 110 RETURN Friday, June 12, 2009
  • 13. “It is practicaquot;y impossible to teach good programming style to students that have had prior exposure to BASIC: as potential programmers they are mentaquot;y mutilated beyond hope of regeneration.” – Edsger W. Dijkstra Friday, June 12, 2009
  • 15. IDENTIFICATION DIVISION. PROGRAM-ID. COBOL-EXAMPLE. PROCEDURE DIVISION. MAIN. IF YEAR <= 1991 DISPLAY 'COBOL! Argh!'. STOP RUN. Friday, June 12, 2009
  • 16. “The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offense.” – Edsger W. Dijkstra Friday, June 12, 2009
  • 18. C HAD ENOUGH YET? PROGRAM UGLY WRITE(UNIT=*, FMT=*) 'FORTRAN!' END Friday, June 12, 2009
  • 19. “[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
  • 21. #/usr/bin/env perl # # (Insert some convoluted JAPH # code/line noise here.) Friday, June 12, 2009
  • 22. Dijkstra doesn’t mention Perl, but I don’t think he would have liked it. Friday, June 12, 2009
  • 23. There’s More Than One Way To Do It, but many of them are Wrong Friday, June 12, 2009
  • 24. What Sysadmins Do All Day and how it explains the code they write Friday, June 12, 2009
  • 26. Get it done. Put the fire out. Then forget about it. Friday, June 12, 2009
  • 27. Short, quick scripts #!/bin/sh for year in 1996 1997 1998 1999 2000; do rm -rf backups/${year} done echo quot;Sorry, all backups from the pretend Internet money era have been purged.quot; | /usr/ucb/Mail -s quot;Your restore requestquot; boss@example.com Friday, June 12, 2009
  • 29. Sysadmins don’t do OO Friday, June 12, 2009
  • 30. Some Object-Oriented Languages I Have Not Known Friday, June 12, 2009
  • 34. Python seemed cool to me, but I didn’t get it. Friday, June 12, 2009
  • 36. I never learned Java. Really. Friday, June 12, 2009
  • 38. Bad practice as a non-developer carries over Friday, June 12, 2009
  • 39. Dijkstra was right: I never learned good style Friday, June 12, 2009
  • 40. Code Smells Friday, June 12, 2009
  • 42. My code needs a lot of refactoring Friday, June 12, 2009
  • 43. Maintenance is difficult Friday, June 12, 2009
  • 44. Fellow developers laugh and kick sand in my face Friday, June 12, 2009
  • 46. Write quality code the first time Friday, June 12, 2009
  • 47. Minimize the need for refactoring Friday, June 12, 2009
  • 48. No more sand kicked in my face! Friday, June 12, 2009
  • 49. On Refactoring (a brief philosophical interlude) Friday, June 12, 2009
  • 50. Refactoring: improving the non-functional characteristics of the code without screwing up the functional parts. Friday, June 12, 2009
  • 51. Refactoring An essential part of a developer’s healthy diet. Friday, June 12, 2009
  • 53. Refactoring is like sugar. It’s sweet, but too much is bad for you. Friday, June 12, 2009
  • 55. Time spent refactoring could be spent actuaquot;y coding. Friday, June 12, 2009
  • 56. Time spent refactoring could be spent factoring. Friday, June 12, 2009
  • 57. I do love refactoring, but I make avoiding it a goal Friday, June 12, 2009
  • 58. Writing Better Code Or, “It hurts when you do that? Don’t do that.” Friday, June 12, 2009
  • 63. 99 out of 100 developers agree: writing tests leads to writing better code Friday, June 12, 2009
  • 65. Testing Philosophies And Frameworks Friday, June 12, 2009
  • 66. TDD, BDD, DDD, TATFT, LMNOP. Friday, June 12, 2009
  • 67. Test::Unit, RSpec, minitest, micronaut, bacon. Friday, June 12, 2009
  • 68. Fettucine, linguine, martini, bikini. Friday, June 12, 2009
  • 69. 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
  • 70. Pick one and stay with it. Friday, June 12, 2009
  • 71. Still don’t know which one to use? Find out what your peers use, and use that one. Friday, June 12, 2009
  • 72. At first, writing tests was completely foreign to me. Friday, June 12, 2009
  • 73. Until I decided to appeal to my own ego. Friday, June 12, 2009
  • 74. I like being right. (Don’t you?) Friday, June 12, 2009
  • 75. Testing is an automated way of proving I’m right. (Or, at least, that my code is.) Friday, June 12, 2009
  • 76. Proving my code correct motivates me to keep writing good code. Friday, June 12, 2009
  • 77. Be a good primate. Use your tools. Friday, June 12, 2009
  • 78. Tools can help you improve your code. Friday, June 12, 2009
  • 80. Tools cannot write good code for you. Friday, June 12, 2009
  • 81. A Few Tools I Like Or, “I got your take-home message right here” Friday, June 12, 2009
  • 82. RCov gem install relevance-rcov http://github.com/relevance/rcov Friday, June 12, 2009
  • 83. Checks code coverage in your tests. Friday, June 12, 2009
  • 84. Checks code coverage in your tests. Friday, June 12, 2009
  • 85. 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
  • 86. 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
  • 87. Reek gem install reek http://github.com/kevinrutherford/reek Friday, June 12, 2009
  • 88. Finds common smells in your code. quot;app/controllers/application_controller.rbquot; -- 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) quot;app/controllers/groups_controller.rbquot; -- 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) quot;app/controllers/sessions_controller.rbquot; -- 2 warnings: SessionsController#create calls flash multiple times (Duplication) SessionsController#create has approx 8 statements (Long Method) quot;app/controllers/user_feeds_controller.rbquot; -- 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) quot;app/helpers/application_helper.rbquot; -- 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)
  • 89. 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
  • 90. 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
  • 91. Let’s Talk About How My Code Smells Or, The Part Of The Presentation That Is Potentiaquot;y Very Embarrassing To The Presenter Friday, June 12, 2009
  • 92. MVC Learn it. Know it. Live it. Friday, June 12, 2009
  • 94. 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
  • 95. xxxxx XxxxxxXxxxxxxxxx < XxxxxxxxxxxXxxxxxxxxx # redacted for public publication xxxxxx_xxxxxx :xxxxx_xxx_xxxx xxxxxx_xxxxxx :xxxxxxx_xxx_xx_xxxxxxx, :xxxx => [:xxxx]‚Ä® xxx xxxx xxxxxx.xxxxxx(:xx_xxx_xxxxxxx) xxxxxx[:xxxxxx] ||= Xxxxxxx::XXXXXX_XXXXXX @xxxxxxx_xxxxxxx = xxxxxx.xxxxxx(:xxxxxxx_xxxxxxx) xx xxxxxx[:xxxxxxxx_xxxx_xxxxxxx].xxx? @xxxx_xxxxxxxxxx_xxx_xxxxxxx = xxxx xxxx @xxxx_xxxxxxxxxx_xxx_xxxxxxx = xxxxxx[:xxxxxxxx_xxxx_xxxxxxx].xxxxxxx?(quot;xxxx_xxxxxxxxxxquot;) xx @xxxx_xxxxxxxxxx_xxx_xxxxxxx xxxxxx[:xxxxxxxx_xxxx_xxxxxxx].xxxxxx(quot;xxxx_xxxxxxxxxxquot;) xxxxxxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxxxxx_xxxx_xxxxx']] xx xxxxxxxx_xxxxxx.xxxxxx > 9 xxxxxxxx_xxxxxx.xxxx{|x,x| x[1] <=> x[1]}[9..-1].xxxx xx |x| xxxxxx[:xxxxxxxx_xxxx_xxxxxxx] << x[0] xxx xxx xxx xxx‚Ä® xx xxxxxx[:xxxx_xxxxxxx].xxx? @xxxx_xxxxxx_xxx_xxxxxxx = xxxx xxxx @xxxx_xxxxxx_xxx_xxxxxxx = xxxxxx[:xxxx_xxxxxxx].xxxxxxx?(quot;xxxx_xxxxxxquot;) xx @xxxx_xxxxxx_xxx_xxxxxxx xxxxxx[:xxxx_xxxxxxx].xxxxxx(quot;xxxx_xxxxxxquot;) xxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxx_xxxxx']] xx xxxx_xxxxxx.xxxxxx > 19 xxxx_xxxxxx.xxxx{|x,x| x[1] <=> x[1]}[19..-1].xxxx xx |x| xxxxxx[:xxxx_xxxxxxx] << x[0] xxx xxx xxx xxx‚Ä® @xxxxxx = xxxxxxx_xxxxxx(xxxxxx[:xxxxxxxx]) xxxxxx @xxxxxx.xxx? xxxxxx[:xxxxxxxx] = xxxxxxxxxx_xxxxxxx(@xxxxxx) xxxxxxx_xxxxxx(:xxxxxx => xxxxxx[:xxxxxx], :xxxxxx_xxx => xxxxxx[:xxxxxx_xxx], :xx_xxxxxxxx => xxxxxx[:xx_xxxxxxxx], :xxxxx => xxxx, :xxxxxx => xxxxxx[:xxxxxx].xx_x) xxxx xxxxx[:xxxxxx] = quot;Xxxxxxx xxxxxxxx, xxxxxx xxx xxxx xxxxxx xxxxx.quot; @xxxxxxxx = [].xxxxxxxx(:xxxx => 1) xxx @xxxx_xxxxxxx = @xxxxxxxx[0,3] @xxxxxxxxxx_xxxxxxx = (@xxxxxxxx[3,(Xxxxxxx.xxx_xxxx - 3)] || []) @xxxxxxxx = @xxxxxxxx.xxxxxx xx @xxxxxxxx.xxxxxxx_xx?(:xxxxxx) && !@xxxxxxxx.xxxxxx.xxx? && !@xxxxxxxx.xxxxxx.xxxxx? @xxxxx_xxxxxx = Xxxx[*@xxxxxxxx.xxxxxx['xxxxx_xxxxx']] @xxxx_xxxxxx = Xxxx[*@xxxxxxxx.xxxxxx['xxxx_xxxxx']] @xxxxxxxx_xxxx_xxxxxx = Xxxx[*@xxxxxxxx.xxxxxx['xxxxxxxx_xxxx_xxxxx']] xxxxxx_xxxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxx_xxxxx']] xxxxxx_xxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxx_xxxxx']] xxxxxx_xxxxxxxx_xxxx_xxxxxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxxxxx_xxxx_xxxxx']]‚Ä® xxxxxx_xxxxx_xxxxxx.xxxx xx |x,x| @xxxxx_xxxxxx[x] = 0 xxxxxx @xxxxx_xxxxxx.xxx_xxx?(x) xxx xxxxxx_xxxx_xxxxxx.xxxx xx |x,x| @xxxx_xxxxxx[x] = 0 xxxxxx @xxxx_xxxxxx.xxx_xxx?(x) xxx xxxxxx_xxxxxxxx_xxxx_xxxxxx.xxxx xx |x,x| @xxxxxxxx_xxxx_xxxxxx[x] = 0 xxxxxx @xxxxxxxx_xxxx_xxxxxx.xxx_xxx?(x) xxx‚Ä® @xxxxx_xxxxxx = @xxxxx_xxxxxx.xxxx # OPTIMIZE: this is ugly @xxxx_xxxxxx = @xxxx_xxxxxx.xxxx{|x,x| quot;#{xxxxxxx('%09x',xxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}quot; <=> quot;#{xxxxxxx('%09x',xxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}quot;} @xxxxxxxx_xxxx_xxxxxx = @xxxxxxxx_xxxx_xxxxxx.xxxx{|x,x| quot;#{xxxxxxx('%09x',xxxxxx_xxxxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}quot; <=> quot;#{xxxxxxx('%09x',xxxxxx_xxxxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}quot;}‚Ä® @xxxxxxxx_xxxxxx = @xxxxxxxx.xxxxxx xxxxxxxx_xxx = [] xxxxxxxx_xxx = [] xxxxxx xxxxxxx[:xxxxxx]['xxxxxxxx_xxxxx_xxxxx'].xxx? xxxxxxxx_xxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxxxxx_xxxxx_xxxxx']].xxxxxx_xx{|x,x| x.xxxxx?}.xxxxxxx{|x,x| x.xx_x} xxx xxxxxx xxxxxxx[:xxxxxx]['xxxxxxxx_xxxxx_xxxxx'].xxx? xxxxxxxx_xxx = Xxxx[*xxxxxxx[:xxxxxx]['xxxxxxxx_xxxxx_xxxxx']].xxxxxx_xx{|x,x| x.xxxxx?}.xxxxxxx{|x,x| x.xx_x} xxx xxxxxxx_xxxxxxx = [] (xxxxxxxx_xxx+xxxxxxxx_xxx).xxxx xx |xxx| xxxxx xxxxxxx_xxxxxxx << Xxxxxx.xxxx(xxx) xxxxxx XxxxxxXxxxxx::XxxxxxXxxXxxxx @xxxxxxxx.xxxx{|x| x.xxxxx_xxx_xxxxx} xxx xxx @xxxxxxx = @xxxxxxx_xxxx.xxxxxxx_xxxxxxx.xxxxxx{|xx| xxxxxxx_xxxxxxx.xxxxxxx?(xx.xxxxxx) && xx.xxxxxx.xxxxxxxxxx_xxxx=='Xxxx' && @xxxxxxx_xxxx.xxxxxxxx_xxx_xxxxxxx_xxxx.xxxxxxx? (xx.xxxxxx.xxxxxxxxxx.xxxxxxxx_xxx)} @xxx_xxxxxxx = @xxxxxxx_xxxx.xxxxxxx_xxxxxxx.xxxxxx{|xx| xxxxxxx_xxxxxxx.xxxxxxx?(xx.xxxxxx) && (xx.xxxxxx.xxxxxxxxxx_xxxx!='Xxxx' || !@xxxxxxx_xxxx.xxxxxxxx_xxx_xxxxxxx_xxxx.xxxxxxx? (xx.xxxxxx.xxxxxxxxxx.xxxxxxxx_xxx))} xxxx_xxxxxxx_xxx = @xxxxxxx.xxxxxxx{|xx| xx.xxxxxx.xx} & (xxxxxx[:xxxxxx_xxx] || []).xxxxxxx{|xx| xx.xx_x} xxxx_xxx_xxxxxxx_xxx = @xxx_xxxxxxx.xxxxxxx{|xx| xx.xxxxxx.xx} & (xxxxxx[:xxxxxx_xxx] || []).xxxxxxx{|xx| xx.xx_x} @xxxx_xxxxxxx_xxxxx = xxxx_xxxxxxx_xxx.xxxxxx @xxxx_xxx_xxxxxxx_xxxxx = xxxx_xxx_xxxxxxx_xxx.xxxxxx @xxxx_xxxxxx_xxx = xxxx_xxxxxxx_xxx + xxxx_xxx_xxxxxxx_xxx @xxxxxxx.xxxx!{|x,x| (@xxxx_xxxxxx_xxx.xxxxxxx?(x.xxxxxx_xx) ? 1 : 0) <=> (@xxxx_xxxxxx_xxx.xxxxxxx?(x.xxxxxx_xx) ? 1 : 0)} @xxx_xxxxxxx.xxxx!{|x,x| (@xxxx_xxxxxx_xxx.xxxxxxx?(x.xxxxxx_xx) ? 1 : 0) <=> (@xxxx_xxxxxx_xxx.xxxxxxx?(x.xxxxxx_xx) ? 1 : 0)} @xxx_xxxxxxx = xxxxxxx_xxxxxxx - ([@xxxxxxx_xxxx.xxxxxx] + @xxxxxxx.xxxxxxx{|x| x.xxxxxx} + @xxx_xxxxxxx.xxxxxxx{|xx| xx.xxxxxx}) @xxx_xxxxxxx = @xxx_xxxxxxx.xxxxxx{|x| x.xxxxxxxxxx_xxxx == 'Xxxxxxx'} @xxx_xxxxxxx.xxxx!{|x,x| (x.xxxxxxxxxx_xxxx=='Xxxxx' ? 1 : 0) <=> (x.xxxxxxxxxx_xxxx=='Xxxxx' ? 1 : 0)} @xxx_xxxxxxx = @xxx_xxxxxxx[0,3] xxxx @xxxxx_xxxxxx = [] @xxxx_xxxxxx = [] @xxxxxxxx_xxxx_xxxxxx = [] @xxxxxxxx_xxxxxx = [] @xxxxxxx = [] @xxx_xxxxxxx = [] @xxxx_xxxxxx_xxx = [] @xxx_xxxxxxx = [] @xxxx_xxxxxxx_xxxxx = 0 @xxxx_xxx_xxxxxxx_xxxxx = 0 xxx @xxxxxxx_xxxxxxxx_xxxxxxx = [] @xxxxxxx_xxxx_xxxxxxx = [] @xxxxxxx_xxxxx_xxxxxxx = [] xx xxxxxx[:xxxxxxxx_xxxx_xxxxxxx] && xxxxxx[:xxxxxxxx_xxxx_xxxxxxx].xxxx.xxxxxx != @xxxxxxxx_xxxx_xxxxxx.xxxxxx @xxxxxxx_xxxxxxxx_xxxxxxx = xxxxxx[:xxxxxxxx_xxxx_xxxxxxx] xxx xx xxxxxx[:xxxx_xxxxxxx] && xxxxxx[:xxxx_xxxxxxx].xxxx.xxxxxx != @xxxx_xxxxxx.xxxxxx @xxxxxxx_xxxx_xxxxxxx = xxxxxx[:xxxx_xxxxxxx] xxx xx xxxxxx[:xxxxx_xxxxxxx] && xxxxxx[:xxxxx_xxxxxxx].xxxx.xxxxxx != @xxxxx_xxxxxx.xxxxxx @xxxxxxx_xxxxx_xxxxxxx = xxxxxx[:xxxxx_xxxxxxx] xxx xx @xxxxxxx_xxxxxxxx_xxxxxxx.xxxxx? && @xxxxxxx_xxxx_xxxxxxx.xxxxx? && @xxxxxxx_xxxxx_xxxxxxx.xxxxx? xxxxxx [xxxxxx[:xxxxxxxx_xxxx_xxxxxxx],xxxxxx[:xxxx_xxxxxxx],xxxxxx[:xxxxx_xxxxxxx]] == [xxx,xxx,xxx] @xxxxxxx_xxxxxxx = xxxx xxx xxx xxx xxx‚Ä® Friday, June 12, 2009
  • 96. Why??? • Didn’t understand the domain. • Not thinking in object-oriented paradigm. • Not thinking in MVC. • Not pairing. • Lousy tests. Friday, June 12, 2009
  • 97. 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
  • 98. 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
  • 99. BIG METH- ODS Friday, June 12, 2009
  • 100. 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
  • 101. def response if @response.nil? @final_response = false current = source path = source.query.nil? ? source.path : quot;#{source.path}?#{source.query}quot; 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 : quot;#{current.path}?#{current.query}quot; else @final_response = true end end end end @response end Friday, June 12, 2009
  • 102. Small Pieces, Loosely Joined Friday, June 12, 2009
  • 103. Remember UNIX? Small tools doing one job well ⇒ small methods doing one job well Friday, June 12, 2009
  • 104. 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
  • 105. Don’t Do Too Much In A Method • When you see a method getting too long, break it into smaquot;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
  • 106. def self.user_agent quot;Awesome App Ruby/#{RUBY_VERSION}quot; end def self.maximum_redirects 4 end def initialize(url) @url = url end def endpoint_for(uri) endpoint = uri.path.sub(/^/?$/, '/') endpoint += quot;?#{uri.query}quot; 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 quot;Error parsing URL: '#{url}'quot; end response end def response @response ||= fetch(@url, self.class.maximum_redirects) end Friday, June 12, 2009
  • 107. 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
  • 108. 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 personaquot;y. No one’s perfect. Friday, June 12, 2009
  • 109. 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
  • 110. Sysadmins are used to fighting fires Friday, June 12, 2009
  • 111. Firefighting is not the way to lasting code quality. Friday, June 12, 2009
  • 112. Firefighting results in code that is “just whiskey” (and maybe not even that) Friday, June 12, 2009
  • 113. You may not have two to four years, but you stiquot; shouldn’t rush Friday, June 12, 2009
  • 114. Working In A Vacuum Most of us don’t. No one should. Friday, June 12, 2009
  • 115. Ethic of Reciprocity Friday, June 12, 2009
  • 116. The Golden Rule Friday, June 12, 2009
  • 117. Code unto others as you would have them code unto you. Friday, June 12, 2009
  • 118. You hate fixing other people’s bad code. Friday, June 12, 2009
  • 119. Don’t make other people fix yours! Friday, June 12, 2009
  • 120. One more tool: Continuous Integration Friday, June 12, 2009
  • 121. Every time the code changes, run the tests. Friday, June 12, 2009
  • 122. Know where a build broke and who was responsible. Friday, June 12, 2009
  • 123. CI is a good idea even if you work alone. Friday, June 12, 2009
  • 124. Some CI Options • CruiseControl.rb, cruisecontrolrb.thoughtworks.com • Integrity, integrityapp.com • RunCodeRun (hosted!), runcoderun.com • runcoderun.com/mcornick Friday, June 12, 2009
  • 125. Let’s Wrap This Up Or, “I Hope You Know This Wiquot; Go Down On Your Permanent Record” Friday, June 12, 2009
  • 126. Where we come from influences where we go. Friday, June 12, 2009
  • 127. There’s still time to change the road you’re on. Friday, June 12, 2009
  • 128. Test. No matter how, just do it. Friday, June 12, 2009
  • 129. Use tools to help you, not to do work for you. Friday, June 12, 2009
  • 130. Recognize anti-patterns. Avoid them. Friday, June 12, 2009
  • 131. Play well with others. Friday, June 12, 2009
  • 132. Take pride in your work. Appeal to your own ego. Friday, June 12, 2009
  • 133. Learn from mistakes. Learn from refactoring. Friday, June 12, 2009
  • 134. Put it all together and you will write better code. Friday, June 12, 2009
  • 135. 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