About the dangers of refactoring

545 views
533 views

Published on

Published in: Technology, Art & Photos
1 Comment
0 Likes
Statistics
Notes
  • Be the first to like this

No Downloads
Views
Total views
545
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
1
Likes
0
Embeds 0
No embeds

No notes for slide

About the dangers of refactoring

  1. 1. About the dangers of refactoring Andrei Pratasavitski May Perl + Perl Mova 2012-05-12
  2. 2. RefactoringCode refactoring is a "disciplined techniquefor restructuring an existing body of code,altering its internal structure without changingits external behavior" [Martin Fowler inhttp://refactoring.com/], undertaken in order toimprove some of the nonfunctional attributesof the software. Wikipedia
  3. 3. РефакторингРефакторинг или рефакторирование (англ.refactoring) — процесс изменениявнутренней структуры программы, незатрагивающий её внешнего поведения иимеющий целью облегчить понимание еёработы. RU.Wikipedia
  4. 4. РефакторингРефакторинг (англ. refactoring) —перетворення програмного коду, змінавнутрішньої структури програмногозабезпечення для полегшення розуміннякоду і легшого внесення подальших змінбез зміни зовнішньої поведінки самоїсистеми. UA.Wikipedia
  5. 5. Refactoring● Restructuring an existing body of code● Non-functional● Without changing its external behavior
  6. 6. THE AXIOMDevelopers DO love refactoring
  7. 7. Refactoring● Makes developers lives easy and happy● Brighter● Creates an illusion of hardworking brains● And...
  8. 8. And refactoring...● ...does NOTHING for users
  9. 9. RefactoringWhat they want to do... What they do...
  10. 10. Why is Refactoring a dirty word?● Writing code is easier than reading it.● So, “refactoring” often means “rewriting”.● Understanding code requires reading it.● How can you rewrite code that you dont understand?● Probably not very well...
  11. 11. You cant refactor the world...● The world is often a messy place.● If code deals with the real word it probably will be messy too.● Refactoring cant make the world less complex or messy.
  12. 12. Refactoring gone wrong● People tend to delete what they dont understand in the misguided hope that “it was not used”.● They do it too early, and too often. Its not like voting!● They tend to over generalize and violate YAGNI.
  13. 13. Refactoring has risks...● You might... break something● ... refactor the code in such a way that the maintainer doesnt understand.● ... annoy your colleagues● … refactor something for the wrong priority● … make the code harder to maintain● … waste time by treading water
  14. 14. (Thanks to Yves Orton)Developer Craft(December 2011)
  15. 15. This is what business says
  16. 16. This is what business saysBecause ...andbusiness developerswants wantresults... beauty!
  17. 17. This is what business says ...and developers want beauty!
  18. 18. This is what business says
  19. 19. Code WTF
  20. 20. Code WTF
  21. 21. Code WTF
  22. 22. Code WTFWTF
  23. 23. Code WTFWTF ● Watch
  24. 24. Code WTFWTF ● Watch ● Think
  25. 25. Code WTFWTF ● Watch ● Think ● Figure out
  26. 26. Code WTFWTF ● Watch ● Think ● Figure out Philippe (BooK) Bruhat
  27. 27. Code evil is...
  28. 28. Code evil is...● ...map in void context● ...goto● ...repeating code● ...using properties instead of accessors● ...to not use foreign keys● ...to do on Perl side what DB can do
  29. 29. Code evil is...● ...map in void context● ...goto● ...repeating code● ...using properties instead of accessors● ...to not use foreign keys● ...to do on Perl side what DB can do Why?
  30. 30. Because...● ...it looks ugly!● ...it is hard to read!● ...it is a bad practice!● ...it will bring benefits in the future!● ...there is another way to do it!● ...it sucks!● ...I dont like it!
  31. 31. But how about... ...performance?
  32. 32. map in void context
  33. 33. map in void contextuse Benchmark qw(cmpthese);my @arr;my $times = 1_000_000;sub ss { $_[0] =~ s/1/a/; }cmpthese( $times, { map1 => sub { @arr = 1..100; map s/1/a/, @arr; }, map2 => sub { @arr = 1..100; map { s/1/a/ } @arr; }, map3 => sub { @arr = 1..100; map &ss($_), @arr; }, map4 => sub { @arr = 1..100; map { &ss($_) } @arr; }, for1 => sub { @arr = 1..100; for (@arr) { s/1/a/ }; }, for2 => sub { @arr = 1..100; s/1/a/ for @arr; }, for3 => sub { @arr = 1..100; do { s/1/a/ } for @arr; }, for4 => sub { @arr = 1..100; for (@arr) { &ss($_) }; }, for5 => sub { @arr = 1..100; &ss($_) for @arr; }, for6 => sub { @arr = 1..100; do { &ss($_) } for @arr; }, for7 => sub { @arr = 1..100; do &ss($_) for @arr; }, });
  34. 34. map in void contextuse Benchmark qw(cmpthese);my @arr;my $times = 1_000_000;sub ss { $_[0] =~ s/1/a/; }cmpthese( $times, { map1 => sub { @arr = 1..100; map s/1/a/, @arr; }, map2 => sub { @arr = 1..100; map { s/1/a/ } @arr; }, map3 => sub { @arr = 1..100; map &ss($_), @arr; }, map4 => sub { @arr = 1..100; map { &ss($_) } @arr; }, for1 => sub { @arr = 1..100; for (@arr) { s/1/a/ }; }, for2 => sub { @arr = 1..100; s/1/a/ for @arr; }, for3 => sub { @arr = 1..100; do { s/1/a/ } for @arr; }, for4 => sub { @arr = 1..100; for (@arr) { &ss($_) }; }, for5 => sub { @arr = 1..100; &ss($_) for @arr; }, for6 => sub { @arr = 1..100; do { &ss($_) } for @arr; }, for7 => sub { @arr = 1..100; do &ss($_) for @arr; }, });
  35. 35. map in void contextuse Benchmark qw(cmpthese);my @arr;my $times = 1_000_000;sub ss { $_[0] =~ s/1/a/; }cmpthese( $times, { map1 => sub { @arr = 1..100; map s/1/a/, @arr; }, map2 => sub { @arr = 1..100; map { s/1/a/ } @arr; }, map3 => sub { @arr = 1..100; map &ss($_), @arr; }, map4 => sub { @arr = 1..100; map { &ss($_) } @arr; }, for1 => sub { @arr = 1..100; for (@arr) { s/1/a/ }; }, for2 => sub { @arr = 1..100; s/1/a/ for @arr; }, for3 => sub { @arr = 1..100; do { s/1/a/ } for @arr; }, for4 => sub { @arr = 1..100; for (@arr) { &ss($_) }; }, for5 => sub { @arr = 1..100; &ss($_) for @arr; }, for6 => sub { @arr = 1..100; do { &ss($_) } for @arr; }, for7 => sub { @arr = 1..100; do &ss($_) for @arr; }, });
  36. 36. map in void contextuse Benchmark qw(cmpthese);my @arr;my $times = 1_000_000;sub ss { $_[0] =~ s/1/a/; }cmpthese( $times, { map1 => sub { @arr = 1..100; map s/1/a/, @arr; }, map2 => sub { @arr = 1..100; map { s/1/a/ } @arr; }, map3 => sub { @arr = 1..100; map &ss($_), @arr; }, map4 => sub { @arr = 1..100; map { &ss($_) } @arr; }, for1 => sub { @arr = 1..100; for (@arr) { s/1/a/ }; }, for2 => sub { @arr = 1..100; s/1/a/ for @arr; }, for3 => sub { @arr = 1..100; do { s/1/a/ } for @arr; }, for4 => sub { @arr = 1..100; for (@arr) { &ss($_) }; }, for5 => sub { @arr = 1..100; &ss($_) for @arr; }, for6 => sub { @arr = 1..100; do { &ss($_) } for @arr; }, for7 => sub { @arr = 1..100; do &ss($_) for @arr; }, });
  37. 37. Results for7 map4 map3 for6 map2 for4 for5 for3 for1 for2 map1for7 -- -91% -91% -93% -93% -94% -94% -95% -95% -96% -96%map4 963% -- -5% -26% -29% -32% -33% -45% -52% -52% -53%map3 1022% 6% -- -22% -25% -28% -29% -42% -49% -50% -51%for6 1338% 35% 28% -- -4% -8% -9% -26% -35% -36% -37%map2 1396% 41% 33% 4% -- -4% -5% -23% -32% -33% -34%for4 1461% 47% 39% 9% 4% -- -1% -20% -29% -30% -32%for5 1476% 48% 40% 10% 5% 1% -- -19% -29% -30% -31%for3 1844% 83% 73% 35% 30% 25% 23% -- -12% -13% -15%for1 2110% 108% 97% 54% 48% 42% 40% 14% -- -1% -3%for2 2137% 110% 99% 56% 49% 43% 42% 15% 1% -- -2%map1 2181% 115% 103% 59% 52% 46% 45% 17% 3% 2% --
  38. 38. Results for7 map4 map3 for6 map2 for4 for5 for3 for1 for2 map1for7 -- -91% -91% -93% -93% -94% -94% -95% -95% -96% -96%map4 963% -- -5% -26% -29% -32% -33% -45% -52% -52% -53%map3 1022% 6% -- -22% -25% -28% -29% -42% -49% -50% -51%for6 1338% 35% 28% -- -4% -8% -9% -26% -35% -36% -37%map2 1396% 41% 33% 4% -- -4% -5% -23% -32% -33% -34%for4 1461% 47% 39% 9% 4% -- -1% -20% -29% -30% -32%for5 1476% 48% 40% 10% 5% 1% -- -19% -29% -30% -31%for3 1844% 83% 73% 35% 30% 25% 23% -- -12% -13% -15%for1 2110% 108% 97% 54% 48% 42% 40% 14% -- -1% -3%for2 2137% 110% 99% 56% 49% 43% 42% 15% 1% -- -2%map1 2181% 115% 103% 59% 52% 46% 45% 17% 3% 2% --
  39. 39. Resultscmpthese( $times, { for1 => sub { @arr = 1..100; for (@arr) { s/1/a/ }; }, for2 => sub { @arr = 1..100; s/1/a/ for @arr; }, map1 => sub { @arr = 1..100; map s/1/a/, @arr; }, }); for1 for2 map1for1 -- -1% -4%for2 1% -- -3%map1 4% 3% --
  40. 40. Resultscmpthese( $times, { for1 => sub { @arr = 1..100; for (@arr) { s/1/a/ }; }, for2 => sub { @arr = 1..100; s/1/a/ for @arr; }, map1 => sub { @arr = 1..100; map s/1/a/, @arr; }, }); for1 for2 map1for1 -- -1% -4%for2 1% -- -3%map1 4% 3% --
  41. 41. map in void context ...is faster
  42. 42. map in void context ...is faster ...a bit
  43. 43. map in void context ...is faster ...a bit ...sometimes
  44. 44. map in void context 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  45. 45. Have a look at... 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  46. 46. Have a look at... 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  47. 47. Have a look at... 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  48. 48. Have a look at... 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  49. 49. Have a look at... 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  50. 50. Have a look at... 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  51. 51. Have a look at... 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  52. 52. Have a look at... 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  53. 53. Repeating code
  54. 54. Repeating codemy ($row, @rows)my $tmp = $sth->fetchrow_hashref();while ( $row = $sth->fetchrow_hashref() ) { if ( $row->{field} eq $tmp->{field} ) { push @rows, $row; } else { # do something with $tmp and @rows $tmp = $row; }}
  55. 55. Repeating codemy ($row, @rows)my $tmp = $sth->fetchrow_hashref();while ( $row = $sth->fetchrow_hashref() ) { if ( $row->{field} eq $tmp->{field} ) { push @rows, $row; } else { # do something with $tmp and @rows $tmp = $row; }}# do something with $tmp and @rows
  56. 56. Repeating codemy ($row, @rows)my $tmp = $sth->fetchrow_hashref();while ( $row = $sth->fetchrow_hashref() ) { if ( $row->{field} eq $tmp->{field} ) { push @rows, $row; } else { &do_something($tmp, @rows); $tmp = $row; }}&do_something($tmp, @rows);
  57. 57. Repeating code 1. map1 | 2181% | map s/1/a/, @arr; 2. for2 | 2137% | s/1/a/ for @arr; 3. for1 | 2110% | for (@arr) { s/1/a/ }; 4. for3 | 1844% | do { s/1/a/ } for @arr; 5. for5 | 1476% | &ss($_) for @arr; 6. for4 | 1461% | for (@arr) { &ss($_) }; 7. map2 | 1396% | map { s/1/a/ } @arr; 8. for6 | 1338% | do { &ss($_) } for @arr; 9. map3 | 1022% | map &ss($_), @arr;10. map4 | 963% | map { &ss($_) } @arr;11. for7 | 0% | do &ss($_) for @arr;
  58. 58. Repeating code ...can be useful
  59. 59. Repeating code ...can be useful...if you remember that method/function call is expensive
  60. 60. Properties instead of accessors
  61. 61. Properties instead of accessors$request->stash(key => value);
  62. 62. Properties instead of accessorsmy $stash = $request->stash();$stash->{key} = value;
  63. 63. Properties instead of accessorsmy $stash = $request->{stash};$stash->{key} = value;
  64. 64. goto is evil?
  65. 65. goto is evil? Really?
  66. 66. goto is evil?$ ack-grep -a ^s*gotos+ /usr/lib/perl/5.14/*.pm | wc -l10$ ack-grep -a ^s*gotos+ /usr/share/perl/5.14/*.pm | wc -l29
  67. 67. goto is evil?All those cases havegoto &somewhere; in AUTOLOAD
  68. 68. goto is evil?
  69. 69. goto is evil?Yes, its evil!
  70. 70. Do on Perl side what DB can do
  71. 71. Do on Perl side what DB can domy @days = &days_from_period(2010-08-01, 2010-08-31);# here @days = (2010-08-01, 2010-08-01, 2010-08-01, ... 2010-08-31)my %result = ();my $sth = $dbh->prepare(<<SQL);SELECT SUM(amount) AS resultFROM Table t LEFT JOIN AnotherTable at USING(field) LEFT JOIN YetAnotherTable yat ON (...)WHERE payday = ? AND (long_long_list_of_conditions)SQLfor my $day (@days) { $sth->execute($day); $result{day} = $stf->fetchrow_arrayref()->[0] || 0;}
  72. 72. # my @days = &days_from_period(2010-08-01, 2010-08-31);# here @days = (2010-08-01, 2010-08-01, 2010-08-01, ... 2010-08-31)my %result = ();# my $sth = $dbh->prepare(<<SQL);my $sql = <<SQL;SELECT payday, SUM(amount) AS resultFROM Table t LEFT JOIN AnotherTable at USING(field) LEFT JOIN YetAnotherTable yat ON (...)WHERE payday BETWEEN ? AND ? AND (long_long_list_of_conditions)GROUP BY paydaySQL# for my $day (@days) {# $sth->execute($day);# $result{day} = $stf->fetchrow_arrayref()->[0] || 0; %result = $sth->selectall_hashref($sql, payday, undef, 2010-08-01, 2010-08-31);# }
  73. 73. my %result = ();my $sql = <<SQL;SELECT payday, SUM(amount) AS resultFROM Table t LEFT JOIN AnotherTable at USING(field) LEFT JOIN YetAnotherTable yat ON (...)WHERE payday BETWEEN ? AND ? AND (long_long_list_of_conditions)GROUP BY paydaySQL%result = $sth->selectall_hashref($sql, payday, undef, 2010-08-01, 2010-08-31);
  74. 74. Do on Perl side what DB can do
  75. 75. Do on Perl side what DB can do SELECTSELECT SUM(amount) AS result payday,FROM Table t SUM(amount) AS result LEFT JOIN AnotherTable at FROM Table t USING(field) LEFT JOIN AnotherTable at LEFT JOIN YetAnotherTable yat USING(field) ON (...) LEFT JOIN YetAnotherTable yatWHERE ON (...) payday = ? WHERE AND payday BETWEEN ? AND ? (long_long_list_of_conditions) AND (long_long_list_of_conditions) GROUP BY payday
  76. 76. Do on Perl side what DB can do X10 slower! SELECTSELECT SUM(amount) AS result payday,FROM Table t SUM(amount) AS result LEFT JOIN AnotherTable at FROM Table t USING(field) LEFT JOIN AnotherTable at LEFT JOIN YetAnotherTable yat USING(field) ON (...) LEFT JOIN YetAnotherTable yatWHERE ON (...) payday = ? WHERE AND payday BETWEEN ? AND ? (long_long_list_of_conditions) AND (long_long_list_of_conditions) GROUP BY payday
  77. 77. I dont tell you
  78. 78. I dont tell you“ Do NOT refactor! ”
  79. 79. I tell you“ Do NOT refactor just because you can! ”
  80. 80. Think you!
  81. 81. Thank you!

×