Refactoring and Readability

Refactoring and Readability

Refactoring is:

worth practicing as a discrete skill
bound to an implied value judgement of "better" code
best served with a separate commit workflow
unsafe without automated testing

Readability is:

crucial to code quality
best achieved by "switching hats" during refactoring
to be prioritized over premature optimization.
beneficial to more than just technical debt

E8c82943a6b1f2acdf4b7fbf4538e1fd?s=128

Bruce Gray

June 14, 2019
Tweet

Transcript

  1. Refactoring and Readability Southeast Linuxfest
 
 2019-06-14

  2. None
  3. Refactoring and Readability http://speakerdeck.com/util
 
 <bruce.gray@acm.org> <<< >>> >>> <<<

  4. OK, so we're doing this...
 


  5. OK, so we're doing this...
 -- Aaron Burr


  6. OK, so we're doing this...
 -- Aaron Burr
 (Also)

  7. OK, so we're doing this...
 -- Aaron Burr
 -- Brock

    Sampson
  8. ( This space intentionally left blank )

  9. Refactoring and Readability http://speakerdeck.com/util
 
 <bruce.gray@acm.org> <<< >>> >>> <<<

  10. Pump Up…

  11. Q&A ⅔

  12. /me

  13. Util

  14. RosettaCode:
 where Perl 6 goes to
 Flex Shine

  15. CodeFights 40 languages

  16. Assume Modern

  17. sub foo { die if @_ != 3; my ($x,

    $y, $z) = @_; ⋮ }
  18. # Assume all my Perl 5 code begins with: use

    strict; use warnings; use 5.020; use experimental qw<signatures>;
  19. use strict; use warnings; use 5.020; use experimental qw<signatures>; sub

    foo ( $x, $y, $z ) { ⋮
  20. use strict; use warnings; use 5.020; use experimental qw<signatures>; sub

    foo ( $x, $y, $z ) { ⋮
  21. sub foo ( $x, $y, $z ) { ⋮

  22. last;

  23. Refactoring

  24. None
  25. Refactoring Safely

  26. Refactoring Sanely

  27. git init
 git add .
 git commit -m 'Initial commit'

  28. sqlite + cUrl + perl + md5

  29. Modes Fix Add Refactor

  30. 
 Forces Surrounding Code Code Easy to write Standard form

    Ease of change Easy to read Performance (Speed) Boundaries of Responsibility (Slicing)
  31. 
 Forces Surrounding Code Code Easy to write Standard form

    Ease of change Easy to read Performance (Speed) Boundaries of Responsibility
  32. Mechanics

  33. sub final_form ($fighter) { ... code ... }

  34. sub trigger_final_form ($fighter) { ... code ... }

  35. sub final_form ($fighter) { return trigger_final_form($fighter); } sub trigger_final_form ($fighter)

    { ... code ... }
  36. sub trigger_final_form ($fighter) { ... code ... }

  37. Refactor to Debug:
 Wrapping

  38. sub should_log ( $department ) { my $r; if (

    $audits{$department} ) { $r = 1 } elsif ( $department eq 'IA' ) { $r = 1 } else { $r = 0 } return $r; }
  39. sub should_log ( $department ) { return 1 if $audits{$department};

    return 1 if $department eq 'IA'; return 0; }
  40. sub should_log ( $department ) { return 1 if $audits{$department};

    return 1 if $department eq 'IA'; return 0; }
  41. sub should_log_WRAPPED ( $department ) { return 1 if $audits{$department};

    return 1 if $department eq 'IA'; return 0; }
  42. sub should_log_WRAPPED ( $department ) { return 1 if $audits{$department};

    return 1 if $department eq 'IA'; return 0; } sub should_log ( $department ) { my $r = should_log_WRAPPED($department); return $r;
  43. sub should_log_WRAPPED ( $department ) { return 1 if $audits{$department};

    return 1 if $department eq 'IA'; return 0; } sub should_log ( $department ) { say "> should_log:", Dumper $department; my $r = should_log_WRAPPED($department); say "< should_log:", Dumper $r; return $r;
  44. sub should_log_WRAPPED ( $department ) { return 1 if $audits{$department};

    return 1 if $department eq 'IA'; return 0; } sub should_log ( $department ) { my $r = should_log_WRAPPED($department); return $r; perl -d pgm c should_log n p $department n p $r $r = 0 c
  45. 
 Forces Surrounding Code Code Easy to write Standard form

    Ease of change Easy to read Performance (Speed) Boundaries of Responsibility
  46. 
 Forces Surrounding Code Code Easy to write Standard form

    Ease of change Easy to read Performance (Speed) Boundaries of Responsibility
  47. Rules Of Optimization wiki.c2.com First Rule Of Optimization - Don't.

    Second Rule Of Optimization - Don't... yet. Profile Before Optimizing
  48. That's another show...

  49. 
 Forces Surrounding Code Code Easy to write Standard form

    Ease of change Easy to read Performance (Speed) Boundaries of Responsibility
  50. Readability

  51. Readability

  52. Wholesale (changes)

  53. print_machine( $machine, $format, $start ); reset_machine( $machine, $init_value ); confuse_machine(

    $machine, $level, $ray ); print_register( $register ); reset_register( $register ); amend_register( $register, $new_value );
  54. print_machine( $machine, $format, $start ); reset_machine( $machine, $init_value ); confuse_machine(

    $machine, $level, $ray ); print_register( $register ); reset_register( $register ); amend_register( $register, $new_value );
  55. print_machine( $machine, $format, $start ); reset_machine( $machine, $init_value ); confuse_machine(

    $machine, $level, $ray ); print_register( $register ); reset_register( $register ); amend_register( $register, $new_value );
  56. print_machine( $machine, $format, $start ); reset_machine( $machine, $init_value ); confuse_machine(

    $machine, $level, $ray ); print_register( $register ); reset_register( $register ); amend_register( $register, $new_value );
  57. $machine->print( $format, $start ); $machine->reset( $init_value ); $machine->confuse( $level, $ray

    ); $register->print( $register ); $register->reset( $register ); $register->amend( $register, $new_value );
  58. print_machine( $machine, $format, $start ); reset_machine( $machine, $init_value ); confuse_machine(

    $machine, $level, $ray ); print_register( $register ); reset_register( $register ); amend_register( $register, $new_value );
  59. print_machine( $machine, $format, $start );

  60. print_machine( $machine, $format, $start );

  61. print_machine( $machine, $format, $start ); $machine->print( $format, $start );

  62. Dense

  63. for my $car (@vehicles) { my $color = $colors_by_type[ $car->type

    ]; if ( not $color->available ) { $color = $colors_by_type[ rand @colors_by_type ]; } $car->assemble_inspect_and_ship($color); $dealers[ $car->order_source ]++; }
  64. for my $car (@vehicles) { my $color = get_car_color(@car); $car->assemble_paint_and_ship($color);

    $dealers->give_credit_for_order($car); }
  65. Wow!

  66. def factorial(n): n0 = 1 n1 = 1 n2 =

    2 n3 = 6 n4 = 24 n5 = 120 n6 = 720 n7 = 5040 n8 = 40320 n9 = 362880 n10 = 3628800 n11 = 39916800 n12 = 479001600 n13 = 6227020800 n14 = 87178291200 n15 = 1307674368000 if n == 0: return n0 elif n == 1: return n1 elif n == 2: return n2 elif n == 3: return n3 elif n == 4: return n4 elif n == 5: return n5 elif n == 6: return n6 elif n == 7: return n7 elif n == 8: return n8 elif n == 9: return n9 elif n == 10: return n10 elif n == 11: return n11 elif n == 12: return n12 elif n == 13: return n13 elif n == 14: return n14 elif n == 15: return n15
  67. def factorial(n): n0 = 1 n1 = 1 n2 =

    2 n3 = 6 n4 = 24 n5 = 120 n6 = 720 n7 = 5040 n8 = 40320 n9 = 362880 n10 = 3628800 n11 = 39916800 n12 = 479001600 n13 = 6227020800 n14 = 87178291200 n15 = 1307674368000 if n == 0: return n0 elif n == 1: return n1 elif n == 2: return n2 elif n == 3: return n3 elif n == 4: return n4 elif n == 5: return n5 elif n == 6: return n6 elif n == 7: return n7 elif n == 8: return n8 elif n == 9: return n9 elif n == 10: return n10 elif n == 11: return n11 elif n == 12: return n12 elif n == 13: return n13 elif n == 14: return n14 elif n == 15: return n15
  68. def factorial(n): if n == 0: return 1 elif n

    == 1: return 1 elif n == 2: return 2 elif n == 3: return 6 elif n == 4: return 24 elif n == 5: return 120 elif n == 6: return 720 elif n == 7: return 5040 elif n == 8: return 40320 elif n == 9: return 362880 elif n == 10: return 3628800 elif n == 11: return 39916800 elif n == 12: return 479001600 elif n == 13: return 6227020800 elif n == 14: return 87178291200 elif n == 15: return 1307674368000
  69. def factorial(n): fact = [ 1, 1, 2, 6, 24,

    120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000] return fact[n]
  70. def factorial(n): f = 1 for x in range(2, n+1):

    f *= x return f
  71. @factorials = 1, |[\*] 1 .. *; # Perl 6

  72. @factorials = 1, |[\*] 1 .. *; # Perl 6

    fact = [1] # Caches between calls! def factorial(n): while len(fact)-1 < n: fact.append( fact[-1] * len(fact) ) return fact[n]
  73. def factorial(n): f = 1 for x in range(2, n+1):

    f *= x return f
  74. import math factorial = math.factorial

  75. Can't miss

  76. http://www.smbc-comics.com/comic/2010-11-26

  77. Enter the Matrix Final Chapter

  78. foo(); bar(); foo(); bar(); foo(); bar(); foo(); bar();

  79. for (1 .. 4) { foo(); bar(); }

  80. 31w + 55x + 46y + 30z = 76 84w

    + 92x + 37y + 72z = 16 57w + 37x + 34y + 85z = 71 93w + 62x + 71y + 49z = 42 86w + 48x + 36y + 42z = 88 -34w + 71x + 47y + 32z = 73 21w + 32x + 34y + 19z = 54 -99w + 25x + 39y + 62z = 23
  81. [ 1, 0, 0, 0, 31, 55, 46, 30, 76

    ], [ 0, 1, 0, 0, 84, 92, 37, 72, 16 ], [ 0, 0, 1, 0, 57, 37, 34, 85, 71 ], [ 0, 0, 0, 1, 93, 62, 71, 49, 42 ], [ 0, 0, 0, 0, 86, 48, 36, 42, 88 ], [ 0, 0, 0, 0, -34, 71, 47, 32, 73 ], [ 0, 0, 0, 0, 21, 32, 34, 19, 54 ], [ 0, 0, 0, 0, -99, 25, 39, 62, 23 ],
  82. [ 1, 0, 0, 0, 31, 55, 46, 30, 76

    ], [ 0, 1, 0, 0, 84, 92, 37, 72, 16 ], [ 0, 0, 1, 0, 57, 37, 34, 85, 71 ], [ 0, 0, 0, 1, 93, 62, 71, 49, 42 ], [ 0, 0, 0, 0, 86, 48, 36, 42, 88 ], [ 0, 0, 0, 0, -34, 71, 47, 32, 73 ], [ 0, 0, 0, 0, 21, 32, 34, 19, 54 ], [ 0, 0, 0, 0, -99, 25, 39, 62, 23 ],
  83. [ 1, 0, 0, 0, 31, 55, 46, 30, 76

    ], [ 0, 1, 0, 0, 84, 92, 37, 72, 16 ], [ 0, 0, 1, 0, 57, 37, 34, 85, 71 ], [ 0, 0, 0, 1, 93, 62, 71, 49, 42 ], [ 0, 0, 0, 0, 86, 48, 36, 42, 88 ], [ 0, 0, 0, 0, -34, 71, 47, 32, 73 ], [ 0, 0, 0, 0, 21, 32, 34, 19, 54 ], [ 0, 0, 0, 0, -99, 25, 39, 62, 23 ],
  84. def gauss(m): n, p = len(m), len(m[0]) for i in

    range(n): k = i + argmax(m[i:n],i) m[i], m[k] = m[k], m[i] ⋮
  85. k = i + argmax( m[i:n], i )

  86. def argmax(m,i): col = [abs(row[i]) for row in m] return

    col.index(max(col))
  87. def argmax(m,i): col = [abs(row[i]) for row in m] return

    col.index(max(col))
  88. def argmax(m,i): col = [abs(row[i]) for row in m] return

    col.index(max(col)) # Double work!
  89. # Perl 5 use List::UtilsBy qw<max_by>; $tallest = max_by {

    $_->height } @people; # Perl 6 $tallest = @people.max( *.height ); # Python (since 2.5 in 2006) tallest = max(people, key=lambda x: x.height);
  90. max( range(i, n), key = lambda x: abs(m[x][i]) )

  91. max( range(i, n), key = lambda x: abs(m[x][i]) )

  92. k = i + argmax( m[i:n], i ) k =

    max(range(i, n), key = lambda x: abs(m[x][i]))
  93. k = i + argmax( m[i:n], i ) k =

    max(range(i, n), key = lambda x: abs(m[x][i])) $k = max_by { abs($m[$_][$i]) } $i..$#m; #P5
  94. def column_index_with_max_abs_value(m,i): return max(range(i, n), key = lambda x: abs(m[x][i]))

    k = column_index_with_max_abs_value(m,i)
  95. Perl 6 == 
 Perl 5 minus Warts plus Awesome

  96. Thanks!

  97. Key knowledge (Perl) • List::Util first max min sum all

    any none uniq shuffle • List::UtilsBy max_by min_by count_by • perlfunc Perl Functions by Category • Test::Tutorial Intro to Automated Testing • Devel::Cover Shows code that lacks testing • Benchmark Performance comparisons • Devel::NYTProf Perfomance profiler
  98. Copyrights

  99. Copyright Information: Images • Camelia • (c) 2009 by Larry

    Wall
 http://github.com/perl6/mu/raw/master/misc/ camelia.txt • New rules for Science Journalism • Zach Weinersmith
 http://www.smbc-comics.com/comic/ 2010-11-26 • Packages • © Randall Munroe
 https://xkcd.com/576/

  100. Copyright Information: This Talk This work is licensed under a

    Creative Commons Attribution 4.0 International License. CC BY https://creativecommons.org/licenses/by/4.0/
  101. Links • The original book, for Java. Now also for

    Ruby and JS
 https://refactoring.com/ • Book: Refactoring JavaScript
 http://refactoringjs.com/ • http://wiki.c2.com/?RulesOfOptimization • http://wiki.c2.com/?ProfileBeforeOptimizing
  102. History • v 0.99 2019-06-06
 Presented at Atlanta Perlmongers (shelved)

    • v 1.01 2019-06-14
 Presented at Southeast LinuxFest