Upgrade to Pro — share decks privately, control downloads, hide ads and more …

You Can't Miss What You Can't Measure

You Can't Miss What You Can't Measure

Adrift at sea, a GPS device will report your precise latitude and longitude, but if you don't know what those numbers mean, you're just as lost as before. Similarly, there are many tools that offer a wide variety of metrics about your code, but other than making you feel good, what are you supposed to do with this knowledge? Let's answer that question by exploring what the numbers mean, how static code analysis can add value to your development process, and how it can help us chart the unexplored seas of legacy code.

Kerri Miller

March 07, 2013
Tweet

More Decks by Kerri Miller

Other Decks in Programming

Transcript

  1. Monday, April 8, 13 I was born and raised in

    Vermont, where foliage season is a high point. Every year hundreds of thousands of people come to view the fall colors. Getting around Bend means you need to learn the one-way streets, the roundabouts, and avoid all the SUVs.. getting around Vermont poses some exciting challenges even during the best of times. The joke is that getting directions from a Vermonter results in this:
  2. Y’uh can’ git the’uh fruhm he’uh [You can’t get there

    from here] Monday, April 8, 13 ..and its kind of true. Let me show you an example.
  3. Monday, April 8, 13 This is a map of southeastern

    vermont. Now, say you were visiting during foliage season,
  4. Monday, April 8, 13 and you hear about an AMAZING

    organic milk tasting in Brookline. Google maps, you say? Good luck getting wifi. Time for your gas station map.
  5. Monday, April 8, 13 ok, so you somehow have a

    map with Brookline on it.. its not really a town, its like.. a rumor of a town. You have to go down through Brattleboro, and then back up West River Road. easy peasy, right? What you don't know is this:
  6. Monday, April 8, 13 The road is a mess still

    from Hurricane Irene, 2 years. So you ask a local, and get one of those classic "turn left 2 miles before the dead end, then turn right where the Hitchens place burned down in '53" ..but eventually you get there.
  7. Monday, April 8, 13 You suffered a little, had a

    bit of an adventure, and learned a viable route between point A and point B, you see the milk tasting and some pretty leaves. Good enough, right? Probably.. but what if you lived in Putney and worked in Brookline, and had to drive this route twice a day? Is there a qualitatively or quantitatively better route?
  8. Monday, April 8, 13 It turns out, there is.. Its

    faster, more scenic, and by almost every measure, its "better".. but good luck getting your mapping software to suggest it! its a dirt road without a name that’s only open 7, 8 month out of the year.. but if you know about it, its going to save you 20 minutes on each trip. Classic shortcut.
  9. RED ➭ GREEN ➭ REFACTOR Monday, April 8, 13 We

    write some code, get the tests working, and then its time to refactor. ..or maybe we're staring at a mudball of legacy code, and every time we touch it, bits break off and fall to the floor. We need to figure out how to make the voyage from point A to point B, from initialization to final output, "better" If its a car trip, its relatively easy. We look at maps, we set our GPS wayfinders, our we chat up locals. How will I know when my code is "good enough"? Where's the guide then? ..or I have a new client hand me a 75k line Rails app. Where's my map?
  10. Monday, April 8, 13 Luckily we have code metrics, which

    can act as compass, GPS, map, native guide, and locale-specific survival kit. Individually they may not get you through to your destination, but together they can turn a voyage through an uncharted region into a routine drive across the ridge for milk. When I was first thinking about this talk, I pitched it to a former coworker, who said, “Sounds good.. but you’re just telling me to eat my vegetables, right?” Well you should eat vegetables.. but c’mon, you all know that.. and you probably know about some code metrics tools. Maybe you got metric_fu working... anyone? anyone ever get it working? ok, I need to talk to you later... so maybe you got that working, maybe you wired up Code Climate.. anyone use code climate? ...cool.. so yeah, you got some kind of metrics tool running, and you experience this:
  11. 1. Denial 2. Anger 3. Bargaining 4. Depression 5. Acceptance

    Monday, April 8, 13 Actually, its more likely that you experienced it this way:
  12. 1. Depression 2. Bargaining 3. Anger 4. Acceptance 5. Denial

    Monday, April 8, 13 You get sad.. you decide to fix it.. you get angry that someone else writes bad code.. you accept that nobody is perfect, especially not your shitty coworkers... you commit a fix, and then never look at code metrics again. ..because they told you you’re bad. A cold, unfeeling program said you or your team are BAD at what you do. So why should you accept the harsh judgy judgements of these tools?
  13. Monday, April 8, 13 You’ve probably heard the quote -

    “Programs are meant to be read by humans and only incidentally for computers to execute” We’re writing code to communicate logic, intent, work that needs to be done, and these tools don’t have a heart, or feelings.. they don’t really think you look funny and smell bad -- they’re trying to tell you something about your code. They’re trying to tell you that you may not be communicating the way you think you are. Who’s read _why’s poignant guide? It broke my brain when I first encountered it.. “Man, I gotta find out more about ruby!” ..but one of the things _why talked about in it was that Ruby was an expressive, literate language, that you could read aloud a chunk of code and understand it.
  14. @customers = Person.find_by_contents(@phrase, :columns => ['first_name', 'last_name', 'business_name', 'email_address', 'phone1'],

    :include => { :contacts => :customer }, :limit => 50).collect { |person| person.contacts.collect { |contact| contact.customer } }.flatten Monday, April 8, 13 Any volunteers? This isn’t even the worst code I could find in apps I manage, this was just one that could fit on a slide.. man, this sucks. Read aloud, it tells me nothing.. I mean, nested collects? I’ve got to hold state at.. what, 2? 3? 4? levels of abstraction? Who wrote this piece of crap?
  15. {10:51}[1.9.3]~/project:master ✓ ➭ git blame app/controllers/customers_... ... cf2ee204 (Kerri Miller

    2012-02-18 12:09:22 -0700 36) Monday, April 8, 13 Oh... let’s move on!! :D
  16. Monday, April 8, 13 Oblique Strategies cards Brian Eno &

    Peter Schmidt 55 cards for stimulating fresh ideas and perspectives ▪ Use an old idea. ▪ Emphasize the flaws ▪ Work at a different speed. ▪ What would your closest friend do? Code metrics aren’t about eating your vegetables, or forcing you to do something right. Sure, they can scold us when we stray from their particular vision of “good” - but they can also serve to change our context for looking at our code, jump-starting creative approaches, or maybe just starting a discussion on your team about “good” Ok! So how do we /use/ these tools? How can they improve our test-driven development cycle? You’re all doing test-first, right? well.. you’re all writing tests? Who here tests-first? good! writes tests, but not always test first? no shame... anyone have 100% coverage? 80% or greater?
  17. TEST COVERAGE Monday, April 8, 13 SURPRISE! The fact that

    you know what your test coverage is means you’re already using code metrics.. Given our obsession with testing, test coverage is one of the go-to metrics in Ruby land.. and its usually one of the firs things to look at when taking stock of an existing project. There are 3 ways to calculate test coverage
  18. TEST COVERAGE C0 — % of lines of code that

    have been executed C1 — % of branches that have been followed at least once C2 — % of unique paths through the source code that have been followed Monday, April 8, 13 Most of our focus is on that first variety - its what rcov, simplecov, etc are surfacing. Low coverage /tends/ to mean less-well tested code, but a higher coverage percentage doesn't necessarily mean that the code is tested. Its entirely possible to get 100% coverage without writing a single assertion! So what's the right number?
  19. Monday, April 8, 13 Man, I don't know.. seriously, I

    can't tell you. You've got to figure out for your own teams and projects what's right for you. DHH calls test coverage "security theater" and advocates only testing what you care about, while Uncle Bob points out that 100% coverage is a result of a "proper" development process. Myself, I think if you're following a healthy TDD process, in the mold of GOOSGBT, your tests, at a minimum, are descriptive of your /intent/ and are clues to future developers about the problems you faced, in terms of requirements and the pain points you ran into along the way. You should strive for healthy coverage, but don't knock yourself out trying to get to 100%.. just like lines-of-code as a measurement of productivity, 100% test coverage is just too easy to bullshit.
  20. LINES OF CODE Monday, April 8, 13 One of the

    most basic code metrics is "lines of code" Its earned a deservedly bad rap -- the horror stories of large enterprise companies using lines of code as a way to measure developer productivity generally make most of us cringe at the thought of applying it to ourselves. Its just too easy a number to game. It does have some basic usefulness though as a measure of overall size. Still, many studies do show a rough correlation between LOC and the overall cost and length of development, between LoC and complexity, and, ergo, between LOC and number of defects. So while it may not be a precise indication of anything (in particular, "progress"), it is not a completely useless metric. The lower your LOC measurement is, the better off you probably are.
  21. LINES OF CODE {20:32}[1.9.3]~/project:master ✓ ➭ rake stats +----------------------+-------+-------+---------+---------+-----+-------+ |

    Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 2297 | 1566 | 18 | 106 | 5 | 12 | | Helpers | 177 | 137 | 0 | 18 | 0 | 5 | | Models | 3948 | 2522 | 35 | 272 | 7 | 7 | | Libraries | 164 | 92 | 4 | 12 | 3 | 5 | | Model specs | 2863 | 2143 | 1 | 2 | 2 | 1069 | | View specs | 5 | 3 | 0 | 0 | 0 | 0 | | Controller specs | 4283 | 3632 | 0 | 0 | 0 | 0 | | Helper specs | 152 | 108 | 0 | 0 | 0 | 0 | | Library specs | 51 | 36 | 0 | 0 | 0 | 0 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 13940 | 10239 | 58 | 410 | 7 | 22 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 4317 Test LOC: 5922 Code to Test Ratio: 1:1.4 Monday, April 8, 13 I would wager those of you who work in Rails have all run this command at least once or twice. This is a simple counting of the lines of code in a sample Rails app, or at least, the lines in your app that DHH thinks are code.. you'll notice that Views and Javascript/Coffeescript aren't included.. This in itself isn't terribly interesting, but it does reveal some things - a service app is going to be much slimmer than a large, monolithic app. quality aside for the moment, what kind of effort has been made in generating tests? This is one of the first commands I use when starting work on a new project, just to get a rough sense of things. Its like standing in the middle of the garage I have to clean and turning around in a circle, and saying "whew... ok.. gonna need more trash bags and should probably get a mop, too" In the end, though, these numbers are really high level, and tend to remain relatively static from day to day or week to week. If you find yourself on a project where you're trying to move the needle on these stats, its time to update your resume. Its sad that in 2013 there are still major software development groups that focus on this. Avoid them.
  22. STATIC vs DYNAMIC Monday, April 8, 13 Code Coverage and

    LoC demonstrate the two basic kinds of code metrics and analysis tools. Calculating the LoC is "Static Analysis", performed without evaluating or executing the code, while Dynamic Analysis tools actually run the code and create metrics based on the characteristics of its behavior. Test coverage is the most common type of dynamic analysis, along with benchmarking and performance profiling. There’s far more Static Analysis tools available to Rubyists these days. These tools can never really understand the code per se. They just search for patterns that might indicate problematic code, and usually spit out a number or rating or chart to show you.. something.
  23. "Data is easy. Information is hard." -Dr Ying Li Monday,

    April 8, 13 I said that Static tools /might/ indicate problematic code, and the word -- “might” -- really has to be stressed here since static analysis will usually return a fair number of false positives. For example, there might be pretty good reasons for there to be an empty rescue block that suppress all errors, or a complicated metaprogramming cul de sac, or a piece of code being duplicated 4 time. Sometimes code just HAS to be this way. So, don’t try and code with the aim of passing some arbitrary threshold. That will most likely make your code a mess, and waste your time. Instead use code metrics and analysis as a helper to find possibly problematic code early.
  24. COMPLEXITY Monday, April 8, 13 The metric I use most

    these days is complexity. Roughly speaking, its a decent measurement of how painful it is to understand a given piece of code. There's three basic forms of complexity metrics..
  25. CYCLOMATIC Monday, April 8, 13 Proposed by Thomas K. McCabe,

    Sr, Cyclomatic complexity is a count of the linearly independent paths through source code. guh, I can’t say that, hang on..
  26. lin·e·ar·li Monday, April 8, 13 ..linearly independent paths through source

    code. Method with more paths are harder to understand, modify, debug - there's more states that it could exist in for your brain to track. This number roughly.. roughly.. tracks the number of unit tests you are likely to generate, since each branch represents an inflection or function point in your code.
  27. ASSIGNMENTS BRANCHES CONDITIONALS Monday, April 8, 13 The aggregate total

    number of: Assignments - "foo = bar" or "baz += 1" Branches - a function call, class method call, or new operator (This is very, very similar to cyclomatic complexity) Conditionals - a logical or Boolean test - "== != <= >= < > etc"
  28. class Test def blah a = eval "1+1" # 1.2

    (a=) + 6.0 (eval) if a == 2 then # 1.2 (if) + 1.2(==) + 0.4 (fixnum) puts "yay" # 1.2 (puts) end end end # 11.2 total FLOG Monday, April 8, 13 Certainly the highest profile of the complexity tools available in the Ruby community, this is Ryan Davis' opinionated complexity scoring tool. It calculates a standard ABC complexity score, then adds points for instances of harder-to-understand Ruby constructs, like eval Flog is very much my go-to for calculating how easy or difficult a given block of Ruby will be to understand. What's a good Flog score? a score of 10 for a model, 20 for a controller is about right. Anything higher than around 60 should be a "fix this NOW" target. Brian Helmkamp Fun fact: The highest Flog score ever seen on Code Climate for a single method is 11,354.
  29. • Extract Method • Decompose Objects • Rethink your domain

    model Monday, April 8, 13 Like most code smells, high complexity is a pointer to a deeper problem rather than a problem in-and-of itself. Tread carefully in your refactorings. Often the simplest solutions (e.g. applying Extract Method) are not the best and rethinking your domain model is required, and sometimes.. SOMETIMES... optimizing this value may actually make things worse.
  30. CHURN Monday, April 8, 13 If we step to a

    slightly higher level for a minute, churn is a fabulous metric. It looks at your version control history for a given time period and counts the number of times a given file’s code has changed. Understanding where your most volatile code lives is amazingly useful, and can help identify + brittle code + business critical areas of concern + 'God' objects + where you don't understand the problem Here's the churn values for a pair of files in one of my long-running Rails projects.
  31. app/models/user.rb = 84 app/models/invoice.rb = 88 Monday, April 8, 13

    The raw churn score is itself interesting. How these numbers compare to our project as a whole tell us these files are frequently touched, but we can do better.
  32. Wonderland Trail Length: 47.2 miles Monday, April 8, 13 The

    Wonderland Trail circles the base of Mt Rainier. The first half is approx. 47.2 miles. Now, I’m not in the shape I used to be, but I can certainly do 10 miles a day, so a quick 5 day hike wouldn’t be so bad, would it?
  33. Wonderland Trail Length: 47.2 miles Monday, April 8, 13 This

    is an elevation graph.. 47 miles of up and down over ridges? 10 miles/day is still doable, but my knees are starting to throb just thinking of schlepping over those rocks.. Just like a raw Churn number, the raw number of miles is misleading.. what happens if we look at those two roughly equal files, but add the dimension of time?
  34. app/models/user.rb = 84 app/models/invoice.rb = 88 Monday, April 8, 13

    Here's the churn values for the past year, binned by week: The User model changed a lot during 3 different periods - clearly someone was working on a major project, perhaps a refactor or something. The Invoice model.. frack, this code is changing like, every 3 days. Its not CSS, its not a config file - something is up with this code. Sometimes a churning file is just a config, maybe a Gemfile or something that changes with some amount of frequency but you really don't care. Sometimes a complex file is just a junk drawer of static methods that no one ever touches.. and sometimes, its a problem. By itself, Churn can tell you a lot about the tempo of the project, and can reveal some possible problem spots. Complexity and Test Coverage similarly can give us a high and low level details, but we can do better. Once we start mixing metrics together, we can get a more complete picture of our code.
  35. Monday, April 8, 13 Turbulence is a great tool based

    on work by Michael Feathers that mashes together churn and complexity to help identify code that really needs to change. A piece of code having high complexity implies a risk of errors, or at least headaches, happening every single time its touched by a developer. Further, the higher complexity a piece of code has, the less likely it is to be refactored. Face it, we're lazy, all of us. Its easier to tack on another elsif than decompose a 100 line method. If a method has a high churn /and/ a high complexity, it really should have priority. So we take a look at our project and...
  36. Monday, April 8, 13 oh god.. oh god... This one

    model has complexity of over 1600, and a churn of over a thousand. Its so heinously bad, its skewing the entire graph. This is CLEARLY a candidate for a attention, before the badness multiplies... I love this tool, but find this particular chart difficult to read, so I usually pipe its output into a treemap.
  37. {10:54}[1.9.3]~/project:master ✓ ➭ git blame app/models/subscription.rb ... c9ce82b4 (Kerri Miller

    2012-05-18 10:19:47 -0700 Monday, April 8, 13 Oh... let’s move on!! :D
  38. {20:32}[1.9.3]~/project:master ✓ ➭ flog -a app/models/subscription.rb 1609.9: flog total 61.9:

    flog/method average 408.8: Subscription#update app/models/subscription.rb:472 323.2: Subscription#new app/models/subscription.rb:250 252.0: Subscription#reply app/models/subscription.rb:137 230.5: Subscription::send_notifications app/models/subscription.rb:78 33.6: Subscription#none 25.5: Subscription#can_expire? app/models/subscription.rb:155 11.7: Subscription::reject_no_ack app/models/subscription.rb:205 4.8: Subscription#initialize app/models/subscription.rb:64 4.4: Subscription#expire! app/models/subscription.rb:183 3.7: Subscription#unexpire! app/models/subscription.rb:194 3.4: Subscription#reason_text app/models/subscription.rb:172 2.2: Subscription#is_current? app/models/subscription.rb:178 2.0: Subscription#to_s app/models/subscription.rb:71 Monday, April 8, 13 Ok... looks like a handful of god methods. Flog has a “show details” flag that will tell us what exactly its grumpy about.
  39. {20:33}[1.9.3]~/project:master ✓ ➭ flog -d app/models/subscription.rb 321.7: flog total 32.2:

    flog/method average 230.5: Subscription::send_notifications app/models/subscription.rb:78 47.8: branch 31.7: ticket 23.1: assignment 17.9: user 17.6: [] 12.2: empty? 9.8: support_queue 8.1: deliver 8.0: class 7.6: email_address 7.0: == Monday, April 8, 13 So here I’m focusing down on just the send_notifications method.. Yeah.. lots of branching, ticket and user are getting dot-chained in here somewhere, lots of array games going on... we can probably fix this with the extract_method hammer..
  40. {08:16}[1.9.3]~/project:master ✓ ➭ flog -a app/models/subscription.rb 52.8: Subscription::send_notifications app/models/subscription.rb:80 28.8:

    Subscription#none 25.5: Subscription#can_expire? app/models/subscription.rb:119 10.2: Subscription::set_mail_options app/models/subscription.rb:221 9.8: Subscription::email_staff app/models/subscription.rb:268 8.5: Subscription::filter_subscriptions app/models/subscription.rb:17 7.9: Subscription::email_reviewers app/models/subscription.rb:258 7.3: Subscription::email_subscribers app/models/subscription.rb:169 6.3: Subscription::subscriber_emails app/models/subscription.rb:204 5.0: Subscription::log_rate_limited app/models/subscription.rb:239 4.8: Subscription#initialize app/models/subscription.rb:65 4.7: Subscription::extract_email_addresses app/models/subscription.rb 4.6: Subscription::filter_rate_limited app/models/subscription.rb:248 4.4: Subscription#expire! app/models/subscription.rb:147 4.0: Subscription::wants_notifications_on_own_posts? app/models/subsc 3.7: Subscription#unexpire! app/models/subscription.rb:158 3.4: Subscription#reason_text app/models/subscription.rb:136 3.2: Subscription::valid_recipient? app/models/subscription.rb:187 2.4: Subscription::ok_to_email? app/models/subscription.rb:183 2.2: Subscription#is_current? app/models/subscription.rb:142 2.0: Subscription#to_s app/models/subscription.rb:73 1.5: Subscription::find_reviewers app/models/subscription.rb:254 1.4: Subscription::mail_subject app/models/subscription.rb:217 Monday, April 8, 13 Boom! everything is nicely simplified.. but now I have a couple dozen private methods that are nice and simple, but used only by this slimmed- down send_notifications method.. they really should get thrown into their own model..
  41. {08:43}[1.9.3]~/project:master ✓ ➭ flog -a app/models/subscription.rb 27.9: Subscription#none 25.5: Subscription#can_expire?

    app/models/subscription.rb:78 4.8: Subscription#initialize app/models/subscription.rb:65 4.4: Subscription#expire! app/models/subscription.rb:106 3.7: Subscription#unexpire! app/models/subscription.rb:117 3.4: Subscription#reason_text app/models/subscription.rb:95 2.2: Subscription#is_current? app/models/subscription.rb:101 2.0: Subscription#to_s app/models/subscription.rb:73 {08:43}[1.9.3]~/project:master ✓ ➭ flog -a app/models/subscriber_notifier.rb 136.6: flog total 8.5: flog/method average 54.1: SubscriberNotifier::send_notifications app/models/subscriber_notif 12.0: SubscriberNotifier::email_subscribers app/models/subscriber_notifi 10.2: SubscriberNotifier::set_mail_options app/models/subscriber_notifie 9.8: SubscriberNotifier::email_staff app/models/subscriber_notifier.rb 8.5: SubscriberNotifier::filter_subscriptions app/models/subscriber_not 7.9: SubscriberNotifier::email_reviewers app/models/subscriber_notifier 6.3: SubscriberNotifier::subscriber_emails app/models/subscriber_notifi 5.0: SubscriberNotifier::log_rate_limited app/models/subscriber_notifie 4.7: SubscriberNotifier::extract_email_addresses app/models/subscriber_ 4.6: SubscriberNotifier::filter_rate_limited app/models/subscriber_noti 4.0: SubscriberNotifier::wants_notifications_on_own_posts? app/models/s 3.2: SubscriberNotifier::valid_recipient? app/models/subscriber_notifie 2.4: SubscriberNotifier::ok_to_email? app/models/subscriber_notifier.rb Monday, April 8, 13 A little more juggling around, and I’ve got a nice service object. I do a few more rounds of refactoring work on Subscriptions, and take a new look at my project..
  42. Monday, April 8, 13 Now that subscriptions isn’t skewing the

    data so horribly, we can clearly see our next hot spot we need to attack.. but that’s for another day. So hopefully this exercise demonstrates how mixing some of these metrics together helps makes problem areas in your code super obvious. We could’ve mixed in overall size of classes, average number of lines per method, average complexity per method.. for myself and my projects - large, poorly designed legacy Rails apps - complexity and churn are the major indicators of problems. The more you gather and pay attention to metrics, the more they’ll speak up and clue you in to what’s important to you and your team. Churn, Complexity, Coverage, and Size.. what other metrics could we gather?
  43. > gem install flay Monday, April 8, 13 You want

    DRY code, but don’t want it to chafe? Syntax Tree Dupication tools such as flay can identify identical or similar code, which usually results from copying and pasting.. It scans for large, identical syntax trees, and uses fuzzy matching to find code which differs only by the specific identifiers and constants used. Again, false positives are a thing here. Some duplications reported by Flay should be left alone.. although Identical code is generally worse than similar code, you also have to consider the context. Remember, that DRY is about single, authoritative representation within a system -- It's not "don't type the same characters into the keyboard multiple times." Common false positives are things like simple Rails controllers that are nicely RESTful, but they're better left damp than introducing a harder-to- understand meta-programmed base class to remove duplication.
  44. rails_best_practices reek roodi pelusa cane BEST PRACTICES & STYLE Monday,

    April 8, 13 Beyond numerical analysis, there are a number of static analysis tools that can give advice about best practices and style. They look for specific code smells, in the case rails_best_practices and reek, or can examine our OO habits, as roodi and pelusa do. Cane is an interesting one, in that it examines code style - whitespace or line length, that sort of thing - measures complexity, and looks for documentations. if the number or value of violations meet a certain threshold, it fails out.. it was built originally to fail out CI builds when code quality metrics started to head south - nip the problem in the bud, so to speak. Its a nice omnibus tool that I use when I’m looking at overall code quality, but not part of my day-to-day workflow.
  45. Monday, April 8, 13 Object Relational mapping can generate a

    literal map of your code and how it interoperates, looking at dependancies and has/belongs relationships I generated this graph -- which is absolutely unreadable at this resolution -- using a gem called railroady. This a snapshot of one system I work with - you can just about make out the snarl of interlocking relationships in this middle tier, how above it all there’s an uber-model that ties into everything. It also shows nicely where some subsystem seams are, over on the left - there’s a couple system there that need to get calved off into their own services. In the case of this code, it really highlights how the system grew organically, without any real design at all. What a mess.. yeah, pass a copy of this to new developers on their first day.. better yet, hit Kinko’s and print this out nice and big, and hang it on the wall.. keep the mess in front of you, so you can see what’s going on.
  46. Monday, April 8, 13 Because honestly, our code is a

    mess. /Your/ code is a mess. All code is prone to rot, decay, and entropy. A quick fix here, a cut-and-pasted line there.. it adds up, invisibly, until your code is just a mudball you’re so used to seeing day in and day out, that you’re numb to the crap.. or maybe you /want/ to write good code, but don’t really follow all the little leaps someone makes in a blog post about refactoring, at least, not enough to really grok it. ..or maybe you’re a lone developer who doesn’t have someone with more experience to pair with, to learn from. Metrics can help. They can act as a rumble strip along the highway - a jolt to wake us up, a small, non-fatal reminder that you’re straying. Ruby is blessed with a rich ecosystem of code metrics tools, and the tools I’ve talked about here are far from the only ones available. Get Code Climate working. Toss Cane,or the new 3.0 release of metric_fu into your CI build. There’s no magic in to code metrics, and the tools are easy to get started with, so it's worth trying them out and getting a feel for how they match up (or don't) with your sense of code quality. Use what works for you, and leave the rest behind. Discover something about your code. Start some conversations about craftsmanship, examine your habits, improve your game. ..because in the end, that’s the point. there's a lot our code can tell us about the work that we are doing, if we decide we want to listen. What’s your code saying to you?
  47. THANKS! ★ @kerrizor ★ glass artist ★ vespa mechanic ★

    lighting designer ★ professional poker player ★ Senior Developer @ Amazon, Contour.com, Blue Box Group Monday, April 8, 13