Code Stinkers Anonymous

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    3 Favorites

    Code Stinkers Anonymous - Presentation Transcript

    1. Code Stinkers Anonymous Mark Cornick • Viget Labs RubyNation • June 12, 2009 Friday, June 12, 2009
    2. Hello 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 wi\" 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
    11. BASIC 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 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
    14. COBOL 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
    17. FORTRAN 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
    20. Perl 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
    25. 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 \"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
    28. Sysadmins aren’t agile 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
    31. C++ Friday, June 12, 2009
    32. Friday, June 12, 2009
    33. Python Friday, June 12, 2009
    34. Python seemed cool to me, but I didn’t get it. Friday, June 12, 2009
    35. Java Friday, June 12, 2009
    36. I never learned Java. Really. Friday, June 12, 2009
    37. The Predicament 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
    41. The Result 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
    45. The Goal 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
    52. BUT Friday, June 12, 2009
    53. Refactoring is like sugar. It’s sweet, but too much is bad for you. Friday, June 12, 2009
    54. WHY? Friday, June 12, 2009
    55. Time spent refactoring could be spent actua\"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
    59. Number one: Friday, June 12, 2009
    60. TEST Friday, June 12, 2009
    61. No, really. Friday, June 12, 2009
    62. TEST! Friday, June 12, 2009
    63. 99 out of 100 developers agree: writing tests leads to writing better code Friday, June 12, 2009
    64. Test First 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
    79. BUT 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. \"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)
    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 Potentia\"y Very Embarrassing To The Presenter Friday, June 12, 2009
    92. MVC Learn it. Know it. Live it. Friday, June 12, 2009
    93. Obese Controllers 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?(\"xxxx_xxxxxxxxxx\") xx @xxxx_xxxxxxxxxx_xxx_xxxxxxx xxxxxx[:xxxxxxxx_xxxx_xxxxxxx].xxxxxx(\"xxxx_xxxxxxxxxx\") 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?(\"xxxx_xxxxxx\") xx @xxxx_xxxxxx_xxx_xxxxxxx xxxxxx[:xxxx_xxxxxxx].xxxxxx(\"xxxx_xxxxxx\") 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] = \"Xxxxxxx xxxxxxxx, xxxxxx xxx xxxx xxxxxx xxxxx.\" @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| \"#{xxxxxxx('%09x',xxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}\" <=> \"#{xxxxxxx('%09x',xxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}\"} @xxxxxxxx_xxxx_xxxxxx = @xxxxxxxx_xxxx_xxxxxx.xxxx{|x,x| \"#{xxxxxxx('%09x',xxxxxx_xxxxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}\" <=> \"#{xxxxxxx('%09x',xxxxxx_xxxxxxxx_xxxx_xxxxxx[x[0]])} #{x[0]}\"}‚Ä® @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 : \"#{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
    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 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
    106. 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
    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 persona\"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 sti\" 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 Wi\" 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

    + Mark CornickMark Cornick, 5 months ago

    custom

    775 views, 3 favs, 0 embeds more stats

    As a professional developer, especially one who wor more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 775
      • 775 on SlideShare
      • 0 from embeds
    • Comments 0
    • Favorites 3
    • Downloads 18
    Most viewed embeds

    more

    All embeds

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories