Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Seven Ineffective Coding Habits of Many Programmers

2,273 views

Published on

Presented at DevTernity (1st December 2016)
Video available at https://www.youtube.com/watch?v=SUIUZ09mnwM

Habits help you manage the complexity of code. You apply existing skill and knowledge automatically to the detail while focusing on the bigger picture. But because you acquire habits largely by imitation, and rarely question them, how do you know your habits are effective? Many of the habits that programmers have for naming, formatting, commenting and unit testing do not stand up as rational and practical on closer inspection. This talk examines seven coding habits that are not as effective as programmers believe, and suggests alternatives.

Published in: Software
  • Can you earn $7000 a month from home? Are you feeling trapped by your life? Stuck in a dead-end job you hate, but too scared to call it quits, because after all, the rent's due on the first of the month, right? Are you ready to change your life for the better? ▲▲▲ http://ishbv.com/ezpayjobs/pdf
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • MADE $30 ON MY FIRST DAY! Being a fresh graduate and having lots of free time, I stumbled upon your site when I was searching for work at home opportunities, good thing I did! Just on my first day of joining I already made $30! Now I'm averaging close to $80 a day just for filling out surveys! ♥♥♥ https://tinyurl.com/vd3y33w
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • The Scrambler Unlock Her Legs | 95% Off by Bobby Rio-Rob Judge? ■■■ http://scamcb.com/unlockher/pdf
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Seven Ineffective Coding Habits of Many Programmers

  1. 1. Seven Ineffective Coding Habits of Many Programmers @KevlinHenney
  2. 2. / WordFriday
  3. 3. code, noun  a set of instructions for a computer  a computer program, or a portion thereof  a system of words, figures or symbols used to represent others, especially for the purposes of secrecy  a set of conventions or principles governing behaviour or activity in a particular domain Concise Oxford English Dictionary ∙ Oxford English Dictionary ∙ Merriam-Webster's Collegiate Dictionary
  4. 4. habit, noun  a settled or regular tendency or practice  an acquired mode of behaviour that has become nearly or completely involuntary  bodily condition or constitution  a costume characteristic of a calling, rank, or function Concise Oxford English Dictionary ∙ Oxford English Dictionary ∙ Merriam-Webster's Collegiate Dictionary
  5. 5. As a I want So that $Role $Feature $Benefit
  6. 6. As a I want So that programmer $Feature $Benefit
  7. 7. As a I want So that programmer effective coding habits $Benefit
  8. 8. As a I want So that programmer effective coding habits I can be less ineffective
  9. 9. As a I want So that programmer effective coding habits I can be more effective
  10. 10. As a I want So that programmer effective coding habits I can spend less time determining the meaning of code and more time coding meaningfully
  11. 11. As a I want So that programmer ??? I can spend less time determining the meaning of code and more time coding meaningfully
  12. 12. Noisy Code
  13. 13. Signal-to-noise ratio (often abbreviated SNR or S/N) is a measure used in science and engineering that compares the level of a desired signal to the level of background noise. Signal-to-noise ratio is sometimes used informally to refer to the ratio of useful information to false or irrelevant data in a conversation or exchange. http://en.wikipedia.org/wiki/Signal_to_noise_ratio
  14. 14. To be, or not to be: that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take arms against a sea of troubles, And by opposing end them? William Shakespeare Hamlet
  15. 15. Continuing existence or cessation of existence: those are the scenarios. Is it more empowering mentally to work towards an accommodation of the downsizings and negative outcomes of adversarial circumstance, or would it be a greater enhancement of the bottom line to move forwards to a challenge to our current difficulties, and, by making a commitment to opposition, to effect their demise? Tom Burton Long Words Bother Me
  16. 16. function leftpad (str, len, ch) { str = String(str); var i = -1; if (!ch && ch !== 0) ch = ' '; len = len - str.length; while (++i < len) { str = ch + str; } return str; }
  17. 17. http://www.theregister.co.uk/2016/03/23/npm_left_pad_chaos/
  18. 18. function leftpad(content, length, pad) { content = String(content) pad = String(pad || pad === 0 ? pad : ' ')[0] var left = Math.max(length - content.length, 0) return pad.repeat(left) + content }
  19. 19. var cache = [ '', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' ]; function leftPad (str, len, ch) { // convert `str` to `string` str = str + ''; // `len` is the `pad`'s length now len = len - str.length; // doesn't need to pad if (len <= 0) return str; // `ch` defaults to `' '` if (!ch && ch !== 0) ch = ' '; // convert `ch` to `string` ch = ch + ''; // cache common use cases if (ch === ' ' && len < 10) return cache[len] + str; // `pad` starts with an empty string var pad = ''; // loop while (true) { // add `ch` to `pad` if `len` is odd if (len & 1) pad += ch; // divide `len` by 2, ditch the remainder len >>= 1; // "double" the `ch` so this operation count grows logarithmically on `len` // each time `ch` is "doubled", the `len` would need to be "doubled" too // similar to finding a value in binary search tree, hence O(log(n)) if (len) ch += ch; // `len` is 0, exit the loop else break; } // pad `str`! return pad + str; }
  20. 20. Comments A delicate matter, requiring taste and judgement. I tend to err on the side of eliminating comments, for several reasons. First, if the code is clear, and uses good type names and variable names, it should explain itself. Second, comments aren't checked by the compiler, so there is no guarantee they're right, especially after the code is modified. A misleading comment can be very confusing. Third, the issue of typography: comments clutter code. Rob Pike, "Notes on Programming in C"
  21. 21. There is a famously bad comment style: i=i+1; /* Add one to i */ and there are worse ways to do it: /********************************** * * * Add one to i * * * **********************************/ i=i+1; Don't laugh now, wait until you see it in real life. Rob Pike, "Notes on Programming in C"
  22. 22. A common fallacy is to assume authors of incomprehensible code will somehow be able to express themselves lucidly and clearly in comments. Kevlin Henney https://twitter.com/KevlinHenney/status/381021802941906944
  23. 23. Unsustainable Spacing
  24. 24. To be, or not to be: that is the question: Whether 'tis nobler in the mind to suffer The slings and arrows of outrageous fortune, Or to take arms against a sea of troubles, And by opposing end them? William Shakespeare Hamlet
  25. 25. Continuing existence or cessation of existence: those are the scenarios. Is it more empowering mentally to work towards an accommodation of the downsizings and negative outcomes of adversarial circumstance, or would it be a greater enhancement of the bottom line to move forwards to a challenge to our current difficulties, and, by making a commitment to opposition, to effect their demise? Tom Burton Long Words Bother Me
  26. 26. Continuing existence or cessation of existence: those are the more empowe to work towa accommodati downsizings outcomes of circumstance a greater enh the bottom li forwards to a our current d by making a opposition, t demise?
  27. 27. How many programmers lay out their code Column 80
  28. 28. How people read
  29. 29. To answer the question "What is clean design?" most succinctly: a clean design is one that supports visual thinking so people can meet their informational needs with a minimum of conscious effort. Daniel Higginbotham ∙ "Clean Up Your Mess — A Guide to Visual Design for Everyone" ∙ http://www.visualmess.com/
  30. 30. You convey information by the way you arrange a design's elements in relation to each other. This information is understood immediately, if not consciously, by the people viewing your designs. Daniel Higginbotham ∙ "Clean Up Your Mess — A Guide to Visual Design for Everyone" ∙ http://www.visualmess.com/
  31. 31. This is great if the visual relationships are obvious and accurate, but if they're not, your audience is going to get confused. They'll have to examine your work carefully, going back and forth between the different parts to make sure they understand. Daniel Higginbotham ∙ "Clean Up Your Mess — A Guide to Visual Design for Everyone" ∙ http://www.visualmess.com/
  32. 32. public int howNotToLayoutAMethodHeader(int firstArgument, String secondArgument) public int ensureArgumentsAreAlignedLikeThis( int firstArgument, String secondArgument) public int orEnsureArgumentsAreGroupedLikeThis( int firstArgument, String secondArgument) public int butNotAlignedLikeThis(int firstArgument, String secondArgument)
  33. 33. int doNotFormat = likeThis(someArgumentOrExpression, anotherArgumentOrExpression); int insteadFormat = somethingLikeThis( someArgumentOrExpression, anotherArgumentOrExpression); int orFormat = somethingLikeThis( someArgumentOrExpression, anotherArgumentOrExpression);
  34. 34. int asItIs = unstable(someArgumentOrExpression, anotherArgumentOrExpression); int butThisIs = stable( someArgumentOrExpression, anotherArgumentOrExpression); int andThisIs = stable( someArgumentOrExpression, anotherArgumentOrExpression);
  35. 35. public ResultType arbitraryMethodName(FirstArgumentType firs SecondArgumentType sec ThirdArgumentType thir LocalVariableType localVariable = method(firstArgument, secondArgument) if (localVariable.isSomething(thirdArgument, SOME_SHOUTY_CONSTANT)) { doSomethingWith(localVariable); } return localVariable.getSomething(); }
  36. 36. public ResultType arbitraryMethodName( FirstArgumentType firstArgument, SecondArgumentType secondArgument, ThirdArgumentType thirdArgument) { LocalVariableType localVariable = method(firstArgument, secondArgument); if (localVariable.isSomething( thirdArgument, SOME_SHOUTY_CONSTANT)) { doSomething(localVariable); } return localVariable.getSomething(); }
  37. 37. XXXXXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXX XX XXXXXXXXXXXXX XXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXX XXXXXXXXXXXXX XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXX
  38. 38. public ResultType arbitraryMethodName( FirstArgumentType firstArgument, SecondArgumentType secondArgument, ThirdArgumentType thirdArgument) { LocalVariableType localVariable = method(firstArgument, secondArgument); if (localVariable.isSomething( thirdArgument, SOME_SHOUTY_CONSTANT)) { doSomething(localVariable); } return localVariable.getSomething(); }
  39. 39. XXXXXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXX XX XXXXXXXXXXXXX XXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXX XXXXXXXXXXXXX XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXX
  40. 40. public ResultType arbitraryMethodName( FirstArgumentType firstArgument, SecondArgumentType secondArgument, ThirdArgumentType thirdArgument) { LocalVariableType localVariable = method(firstArgument, secondArgument); if (localVariable.isSomething( thirdArgument, SOME_SHOUTY_CONSTANT)) { doSomething(localVariable); } return localVariable.getSomething(); }
  41. 41. XXXXXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXXXXXXX XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXX XX XXXXXXXXXXXXX XXXXXXXXXXX XXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX XXXXXXXXXXX XXXXXXXXXXXXX XXXXXX XXXXXXXXXXXXX XXXXXXXXXXXX
  42. 42. Lego Naming
  43. 43. Agglutination is a process in linguistic morphology derivation in which complex words are formed by stringing together morphemes, each with a single grammatical or semantic meaning. Languages that use agglutination widely are called agglutinative languages. http://en.wikipedia.org/wiki/Agglutination
  44. 44. pneumonoultramicroscopicsilicovolcanoconiosis Rindfleischetikettierungsüberwachungsaufgabenübertragungsgesetz fylkestrafikksikkerhetsutvalgssekretariatslederfunksjonene muvaffakiyetsizleştiricileştiriveremeyebileceklerimizdenmişsinizcesine hippopotomonstrosesquipedaliophobia
  45. 45. http://www.bonkersworld.net/object-world/
  46. 46. http://www.bonkersworld.net/object-world/ OBJECT-ORIENTED VenetianBlind Door Television Picture Glass Sofa TelevisionRemoteControl Peephole
  47. 47. People will be using the words you choose in their conversation for the next 20 years. You want to be sure you do it right. Unfortunately, many people get all formal [...]. Just calling it what it is isn't enough.
  48. 48. public interface ConditionChecker { boolean checkCondition(); ... }
  49. 49. public interface Condition { boolean isTrue(); ... }
  50. 50. They have to tack on a flowery, computer science-y, impressive sounding, but ultimately meaningless word, like Object, Thing, Component, Part, Manager, Entity, or Item.
  51. 51. AccessViolationException ArgumentOutOfRangeException ArrayTypeMismatchException BadImageFormatException CannotUnloadAppDomainException EntryPointNotFoundException IndexOutOfRangeException InvalidOperationException OverflowException
  52. 52. AccessViolation ArgumentOutOfRange ArrayTypeMismatch BadImageFormat CannotUnloadAppDomain EntryPointNotFound IndexOutOfRange InvalidOperation Overflow
  53. 53. ArgumentException ArithmeticException ContextMarshalException FieldAccessException FormatException NullReferenceException ObjectDisposedException RankException TypeAccessException
  54. 54. Argument Arithmetic ContextMarshal FieldAccess Format NullReference ObjectDisposed Rank TypeAccess
  55. 55. InvalidArgument InvalidArithmeticOperation FailedContextMarshal InvalidFieldAccess InvalidFormat NullDereferenced OperationOnDisposedObject ArrayRankMismatch InvalidTypeAccess
  56. 56. Omit needless words. William Strunk and E B White The Elements of Style
  57. 57. Underabstraction
  58. 58. http://fragmental.tw/2009/04/29/tag-clouds-see-how-noisy-your-code-is/
  59. 59. http://fragmental.tw/2009/04/29/tag-clouds-see-how-noisy-your-code-is/
  60. 60. if (portfolioIdsByTraderId.get(trader.getId()) .containsKey(portfolio.getId())) { ... } Dan North, "Code in the Language of the Domain" 97 Things Every Programmer Should Know
  61. 61. if (trader.canView(portfolio)) { ... } Dan North, "Code in the Language of the Domain" 97 Things Every Programmer Should Know
  62. 62. Unencapsulated State
  63. 63. public class BankAccount { ... public decimal Balance; ... }
  64. 64. public class BankAccount { ... public decimal Balance { get; set; } ... }
  65. 65. public class BankAccount { ... public decimal Balance { get ... set ... } ... }
  66. 66. Don't ever invite a vampire into your house, you silly boy. It renders you powerless.
  67. 67. public class BankAccount { ... public decimal Balance { get ... } public void Deposit(decimal amount) ... public void Withdraw(decimal amount) ... ... }
  68. 68. Getters and Setters
  69. 69. public class Money implements ... { ... public int getUnits() ... public int getHundredths() ... public Currency getCurrency() ... ... public void setUnits(int newUnits) ... public void setHundredths(int newHundredths) ... public void setCurrency(Currency newCurrency) ... ... }
  70. 70. public final class Money implements ... { ... public int getUnits() ... public int getHundredths() ... public Currency getCurrency() ... ... }
  71. 71. Just because you have a getter, doesn't mean you should have a setter.
  72. 72. public final class Money implements ... { ... public int getUnits() ... public int getHundredths() ... public Currency getCurrency() ... ... }
  73. 73. public final class Money implements ... { ... public int units() ... public int hundredths() ... public Currency currency() ... ... }
  74. 74. "Get something" is an imperative with an expected side effect.
  75. 75. Uncohesive Tests
  76. 76. Everybody knows that TDD stands for Test Driven Development. However, people too often concentrate on the words "Test" and "Development" and don't consider what the word "Driven" really implies. For tests to drive development they must do more than just test that code performs its required functionality: they must clearly express that required functionality to the reader. That is, they must be clear specifications of the required functionality. Tests that are not written with their role as specifications in mind can be very confusing to read. Nat Pryce and Steve Freeman "Are Your Tests Really Driving Your Development?"
  77. 77. Stack<Book>
  78. 78. public class Stack<T> { private  public Stack()  public void push(T newTop)  public void pop()  public int depth()  public T top()  }
  79. 79. public class StackTests { @Test public void testConstructor()  @Test public void testPush()  @Test public void testPop()  @Test public void testDepth()  @Test public void testTop()  }
  80. 80. public class StackTests { @Test public void constructor()  @Test public void push()  @Test public void pop()  @Test public void depth()  @Test public void top()  }
  81. 81. methodtest test test method method test test
  82. 82. public class Stack_spec { public static class A_new_stack { @Test public void is_empty()  } public static class An_empty_stack { @Test() public void throws_when_queried_for_its_top_item()  @Test() public void throws_when_popped()  @Test public void acquires_depth_by_retaining_a_pushed_item_as_its_top()  } public static class A_non_empty_stack { @Test public void becomes_deeper_by_retaining_a_pushed_item_as_its_top()  @Test public void on_popping_reveals_tops_in_reverse_order_of_pushing()  } }
  83. 83. public class Stack_spec { public static class A_new_stack { @Test public void is_empty()  } public static class An_empty_stack { @Test() public void throws_when_queried_for_its_top_item()  @Test() public void throws_when_popped()  @Test public void acquires_depth_by_retaining_a_pushed_item_as_its_top()  } public static class A_non_empty_stack { @Test public void becomes_deeper_by_retaining_a_pushed_item_as_its_top()  @Test public void on_popping_reveals_tops_in_reverse_order_of_pushing()  } }
  84. 84. public class Stack_spec { public static class A_new_stack { @Test public void is_empty()  } public static class An_empty_stack { @Test() public void throws_when_queried_for_its_top_item()  @Test() public void throws_when_popped()  @Test public void acquires_depth_by_retaining_a_pushed_item_as_its_top()  } public static class A_non_empty_stack { @Test public void becomes_deeper_by_retaining_a_pushed_item_as_its_top()  @Test public void on_popping_reveals_tops_in_reverse_order_of_pushing()  } }
  85. 85. function leftpad (str, len, ch) { str = String(str); var i = -1; if (!ch && ch !== 0) ch = ' '; len = len - str.length; while (++i < len) { str = ch + str; } return str; }
  86. 86. function leftpad(content, length, pad) { content = String(content) pad = String(pad || pad === 0 ? pad : ' ')[0] var left = Math.max(length - content.length, 0) return pad.repeat(left) + content }
  87. 87. functiontest test test
  88. 88. function assert(condition) { if(!condition) throw { name: "AssertionError", message: "assertion failed" } } function testPasses(toTry) { try { toTry() return true } catch (failure) { return false } } function report(testName, passed) { document.write(testName.fontcolor(passed ? "green" : "red") + "<br>") } function test(testCases) { for (var testName in testCases) if (testCases.hasOwnProperty(testName)) report(testName, testPasses(testCases[testName])) }
  89. 89. test({ "Padding an empty string to a length of 0 results in an empty string": () => assert(leftpad("", 0, "X") === ""), "Padding a non-empty string to a shorter length results in the same string": () => assert(leftpad("foobar", 3, "X") === "foobar"), "Padding a non-empty string to a negative length results in the same string": () => assert(leftpad("foobar", -3, "X") === "foobar"), "Padding a non-empty string to its length results in the same string": () => assert(leftpad("foobar", 6, "X") === "foobar"), "Padding to a longer length with a single character fills to the left": () => assert(leftpad("foobar", 8, "X") === "XXfoobar"), "Padding to a longer length with surplus characters fills using only first": () => assert(leftpad("foobar", 10, "XY") === "XXXXfoobar"), "Padding to a longer length with an empty string fills with space": () => assert(leftpad("foobar", 8, "") === " foobar"), "Padding to a longer length with no specified fill fills with space": () => assert(leftpad("foobar", 9) === " foobar"), "Padding to a longer length with integer 0 fills with 0": () => assert(leftpad("foobar", 7, 0) === "0foobar"), "Padding to a longer length with single-digit integer fills with digit": () => assert(leftpad("foobar", 10, 1) === "1111foobar"), "Padding to a longer length with multiple-digit integer fills with first digit": () => assert(leftpad("foobar", 10, 42) === "4444foobar"), "Padding to a longer length with negative integer fills with -": () => assert(leftpad("foobar", 8, -42) === "--foobar"), "Padding a non-string uses string representation": () => assert(leftpad(4.2, 5, 0) === "004.2") })
  90. 90. Padding an empty string to a length of 0 results in an empty string Padding a non-empty string to a shorter length results in the same string Padding a non-empty string to a negative length results in the same string Padding a non-empty string to its length results in the same string Padding to a longer length with a single character fills to the left Padding to a longer length with surplus characters fills using only first Padding to a longer length with an empty string fills with space Padding to a longer length with no specified fill fills with space Padding to a longer length with integer 0 fills with 0 Padding to a longer length with single-digit integer fills with digit Padding to a longer length with multiple-digit integer fills with first digit Padding to a longer length with negative integer fills with - Padding a non-string uses string representation
  91. 91. Padding an empty string to a length of 0 results in an empty string Padding a non-empty string to a shorter length results in the same string Padding a non-empty string to a negative length results in the same string Padding a non-empty string to its length results in the same string Padding to a longer length with a single character fills to the left Padding to a longer length with surplus characters fills using only first Padding to a longer length with an empty string fills with space Padding to a longer length with no specified fill fills with space Padding to a longer length with integer 0 fills with 0 Padding to a longer length with single-digit integer fills with digit Padding to a longer length with multiple-digit integer fills with first digit Padding to a longer length with negative integer fills with - Padding a non-string uses string representation
  92. 92. A test case should be just that: it should correspond to a single case.
  93. 93. As a I want So that programmer ??? I can spend less time determining the meaning of code and more time coding meaningfully
  94. 94. As a I want So that programmer code to communicate directly and with intent I can spend less time determining the meaning of code and more time coding meaningfully
  95. 95. At some level the style becomes the substance.

×