Slide 1

Slide 1 text

YOU CAN’T MISS WHAT YOU CAN’T MEASURE Monday, April 8, 13 With apologies to Funkadelic..

Slide 2

Slide 2 text

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:

Slide 3

Slide 3 text

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.

Slide 4

Slide 4 text

Monday, April 8, 13 This is a map of southeastern vermont. Now, say you were visiting during foliage season,

Slide 5

Slide 5 text

Monday, April 8, 13 in scenic Putney

Slide 6

Slide 6 text

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.

Slide 7

Slide 7 text

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:

Slide 8

Slide 8 text

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.

Slide 9

Slide 9 text

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?

Slide 10

Slide 10 text

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.

Slide 11

Slide 11 text

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?

Slide 12

Slide 12 text

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:

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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?

Slide 15

Slide 15 text

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.

Slide 16

Slide 16 text

@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?

Slide 17

Slide 17 text

{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

Slide 18

Slide 18 text

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?

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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?

Slide 21

Slide 21 text

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.

Slide 22

Slide 22 text

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.

Slide 23

Slide 23 text

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.

Slide 24

Slide 24 text

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.

Slide 25

Slide 25 text

"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.

Slide 26

Slide 26 text

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..

Slide 27

Slide 27 text

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..

Slide 28

Slide 28 text

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.

Slide 29

Slide 29 text

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"

Slide 30

Slide 30 text

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.

Slide 31

Slide 31 text

• 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.

Slide 32

Slide 32 text

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.

Slide 33

Slide 33 text

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.

Slide 34

Slide 34 text

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?

Slide 35

Slide 35 text

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?

Slide 36

Slide 36 text

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.

Slide 37

Slide 37 text

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...

Slide 38

Slide 38 text

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.

Slide 39

Slide 39 text

Monday, April 8, 13 That’s... well, better, but subscription model, Y U SO BAD?!?!? WHO WROTE THIS CRAP?

Slide 40

Slide 40 text

{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

Slide 41

Slide 41 text

{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.

Slide 42

Slide 42 text

{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..

Slide 43

Slide 43 text

{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..

Slide 44

Slide 44 text

{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..

Slide 45

Slide 45 text

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?

Slide 46

Slide 46 text

> 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.

Slide 47

Slide 47 text

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.

Slide 48

Slide 48 text

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.

Slide 49

Slide 49 text

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?

Slide 50

Slide 50 text

THANKS! ★ @kerrizor ★ glass artist ★ vespa mechanic ★ lighting designer ★ professional poker player ★ Senior Developer @ Amazon, Contour.com, Blue Box Group Monday, April 8, 13