In some situations, it's useful to be able to evaluate a Rails application quickly.
I talk about how I work to get the most data as possible to get a good picture of whether an application is well-maintained, and will be easy to maintain later.
34. RubyParser and
Parsetree
Ryan Davis and Eric Hodel
(‘Ruby Sadists’)
Wednesday 31 March 2010
35. RubyParser and
Parsetree
Abstract syntax tree
RubyParser.new.parse(File.read(‘metrics.rb’),‘metric.rb’)
class Metrics s(:class,:Metrics, nil,
def probe s(:scope,
s(:defn,:probe,
puts "good" s(:args),
end s(:scope,
end s(:block,
s(:call, nil, :puts,
s(:arglist,
s(:str, "good"))))))))
Symbolic Expression (Sexp)
Ruby2Ruby
Wednesday 31 March 2010
36. flog
‘the pain your
code is in’
Wednesday 31 March 2010
37. FLOG
Weighing the AST with factors
Assignment Branch Condition (ABC)
def process_if(exp)
add_to_score :branch
process exp.shift # cond
penalize_by 0.1 do
process exp.shift # true
process exp.shift # false
end
s()
end
Wednesday 31 March 2010
39. FLOG
Very good: < 20
All Right: < 50
Wednesday 31 March 2010
40. FLAY
code similarities
Wednesday 31 March 2010
41. FLAY
RubyParser
def mass
@mass ||= self.structure.flatten.size
end
Hash of structure of nodes with mass >
threshold
self.hashes[node.structural_hash] << node
analyze:
if same hash = similar
if same node = identical
Wednesday 31 March 2010
42. FLAY
flay *.rb
Total score (lower is better) = 621
1) IDENTICAL code found in :defn (mass*2 = 188)
channel.rb:48
clip.rb:80
2) Similar code found in :defn (mass = 93)
channel.rb:150
clip.rb:110
clip.rb:116
3) Similar code found in :defs (mass = 58)
contact.rb:32
contact.rb:37
Wednesday 31 March 2010
43. Saikuro
cyclomatic
complexity
Wednesday 31 March 2010
44. Saikuro
ruby-lex
every keyword is interpreted into
‘state’
state used to calculate
if, unless, while, until, for, elsif, when, rescue
(blocks)
Recursively
Wednesday 31 March 2010
49. Roodi
app/controllers/itineraries_controller.rb:4 - Method name "show"
cyclomatic complexity is 14. It should be 8 or less.
app/models/itinerary.rb:41 - Block cyclomatic complexity is 6.
It should be 4 or less.
app/controllers/itineraries_controller.rb:4 - Method "show" has
30 lines. It should have 20 or less.
app/helpers/application_helper.rb:27 - Method "clippy" has 26
lines. It should have 20 or less.
Wednesday 31 March 2010
50. Reek
Control Couple
Data Clump
Feature Envy
Large Class
Long Method
Long Parameter List
Simulated Polymorphism
Uncommunicative Name
Wednesday 31 March 2010
51. Reek
RubyParser
extends parsed nodes
traverses nodes
returns code after Ruby2Ruby
Wednesday 31 March 2010
52. Reek
UserSessionsController has no descriptive comment (Irresponsible Module)
UserSessionsController#destroy calls current_user_session twice
(Duplication)
app/controllers/users_controller.rb -- 5 warnings:
UsersController has no descriptive comment (Irresponsible Module)
UsersController tests @aid_app at least 4 times (Simulated Polymorphism)
UsersController#create calls params 3 times (Duplication)
UsersController#create calls params[:user] 3 times (Duplication)
...
Wednesday 31 March 2010
53. Churn
Frequent changes may indicate
issue
Wednesday 31 March 2010
54. Churn
Not only classes but also methods
(RubyParser)
Version control: git, Hg, svn
Locates changes in source using logs
(as in git log)
Wednesday 31 March 2010
58. Rcov
Executes test
keeps track of the executed lines
Using C extension when possible
to hook into MRI
(experimental for 1.9)
Wednesday 31 March 2010
59. Rcov
Total coverage: comments included
Wednesday 31 March 2010
60. Rcov
good: 100% coverage
Wednesday 31 March 2010
62. Heckle
ParseTree + Ruby2Ruby
mutate
doesn’t work for ruby 1.9
(ParseTree)
time-consuming: combinatorials
more for small programs (gems,
scripts)
Wednesday 31 March 2010
63. Heckle
Initial tests pass. Let's rumble.
**********************************************************************
*** AidApp#property_names loaded with 4 possible mutations
**********************************************************************
4 mutations remaining...
Replacing AidApp#property_names with:
--- original
+++ mutation
def property_names
- (meta_policy and meta_policy.property_names_for(:aid_app))
+ (nil and meta_policy.property_names_for(:aid_app))
end
Wednesday 31 March 2010
a big company wants to acquire a startup that has a rails application.
before the sale goes through, they want to be sure they get value for money.
they call in an expert to have a look.
you are the expert.
You go to the startup, you sign an NDA, and you get access to the code.
You usually have full cooperation of the team, who would be eager for you to give a good report.
sit down with the team
they will make an introduction
and you can observe them:
looking at people you can already form an idea
you have experience which will allow you to tell whether you have a team that will produce good to great software.
One guy: usually bad sign - easier to slack off when you&#x2019;re alone
commit everything
maintainable test
broken windows
automation: manual scripts/hacks a person is not even consciously aware of
simple peer pressure in everything
I&#x2019;m sure there are many learned articles about group dynamics, about personality types in a team, etc ...
the innovator: keeps up with what&#x2019;s out there, wants to be on top of the next great thing
the automator: more a sysadmin profile maybe - someone who likes scripting and making everything run smoothly
the ant: obsessive-compulsive types who want to have every detail perfect.
You&#x2019;ll notice I don&#x2019;t include him ...
Bottom line, after you&#x2019;ve worked a while, you get a feel for what constitutes a good team. Getting to know a team can already tell you something about the application you&#x2019;re about to look at ...
On a less pleasant note, some of those people will be employed by the buyer. key players in the team
tools I think you cannot do without. Even if the bug tracker is a text file.
so you sat down with the team, you discussed the application, their philosophy, the deployment, other aspects ...
it&#x2019;s time to dive in, and see what we have here.
does it work ?
does the application match the vision ?
Is it clear at all ? &#x2018;don&#x2019;t make me think&#x2019;
do you manage to get pesky 500s and 404 ?
that shouldn&#x2019;t take too long.
then you can start inventorizing what you&#x2019;ve got.
First off, what version of rails are they using ?
I think it&#x2019;s a good sign when it&#x2019;s a reasonably recent version.
Same for plugins.
what gems, what plugins are they using ?
Is it the last version ?
I&#x2019;m a firm believer in the natural selection of open source
Are they popular ?
Are they maintained ?
are the plugins and gems easily updatable ?
another aspect you might not think of, but will interest the acquirer: what license is the code under ?
Obviously, for commercial code, the freer the better - MIT or BSD license over GPL
I think I look out for, is the Not Invented Here syndrom.
some people will not trust plugins they have not written themselves.
That&#x2019;s fine, but
- reinventing the wheel
- maintaining the wheel
- by releasing it, you express your confidence that it is good code.
- adoption and maintenance by others
OK, plugins and gems are inventorized.
you often have a sizeable code base to look at ... where to start ?
Where would you start ?
what&#x2019;s the action in the application ?
clearly named ?
may not be clear to you - domain-dependent
ideally googleable
sometimes internal jargon for the firm
ask someone in the same business what a term means
ask a developer what it means
we now have a very high level view of the application.
Now, before continuing, there is one priority
One way to start analyzing a large amount of code, is by using metrics.
I&#x2019;m going to go a little bit more in-depth about the metric tools.
There have been many presentations and blog posts about the subject, I&#x2019;m going to try to go a little bit further, to give you an idea of what&#x2019;s under the hood
the first code metric in history are lines of code.
Unfortunately, they don&#x2019;t tell you very much: imagine you add a few lines of comment, you break up an expression into several lines - for the same code you can double the number of lines.
They give you an idea of the approximate size.
Most of the metrics tool rest on ruby parsing.
RubyParser and ParseTree are both tools developed by Kevin Clarke and Ryan Biggs
Also known as the Ruby Sadists
The idea is to navigate the abstract syntax tree =
code represented as a tree
symbolic expressions are a good way to represent this tree
list-based data structures that represent semi-structured data.
. Lisp, Scheme
the output of ruby parser and parsetree is a symbolic expression.
Flog is one of the tools made by Rian Bigg
It gives a measure of code complexity.
For every tool I try to give first a description,
then some implementation details
and finally what is expected for good code
How flog works:
the AST is recursively accessed, and a calculation is made
the calculation happens with ABC
Assignment Branch Conditions - a traditional measure of code complexity.
The result is a series of number - per class and per method.
Per method, you expect something like this
guess where the name &#x2018;saikuro&#x2019; comes from
Japanese people have this habit of taking over words that indicate new concepts
bi-ru co-hee
it&#x2019;s cyclo as used by japanese people
number of linearly independent paths through a program's source code.
it&#x2019;s also a measure of code complexity
lexer: step before parsing -
split program = characters - into tokens
we come to the less quantitative tools - roodi and reek find design issues for you.
abc metric like flog
assignment in conditional
missing else in a case
class variables
Control couple: the execution of a method depends on one of the parameters (conditional on parameter). Also when one of parameters is defaulted to true or false
Data clump: variables appearing together all the time - suggesting missing abstraction
feature envy: when code fragment references other object more than it references itself, or when several objects do the same kind of manipulation on a particular kind of object
Simulated polymorphism: case statements, several ifs, is_a_kind_of?
The tool we all know to check our test coverage
Now, code coverage doesn&#x2019;t say much.
For a good test set, you need 100%, but that&#x2019;s a minimum requirement.
You can have 100% coverage without
Heckle is really interesting in theory, difficult to apply in practice.
in the next mutation, it changed this to nil
the one after that, ti change the symbol to something else
So I looked at the metrics, and I read some of the code that was flagged. time flies, and we have only 7 hours to go
and it&#x2019;s time for lunch
revigorated, it&#x2019;s time to continue
with metrics, you got to see their worst. the monster methods, the antipatterns ...
now you could also apply some normal codereading
ask them what the core is, what their best code is
code should be readable. Ideally like a book
At the very least it shouldn&#x2019;t take too much effort to understand what&#x2019;s going on.
rails is not slow, developers make bad use of the data base
it&#x2019;s not because we use an ORM that we can drop all knowledge
this is a plugin I&#x2019;d rather not see. It means that you can go several levels of has_many_through
in this case, it might be a good idea to reconsider. either using sql, or views at db level, or denormalize
We&#x2019;ve looked at models, views
in fact maybe we need a metric tool for views, too
divitis
javascript in the body
unindented
too much logic in view
it&#x2019;s time to have a closer look at the tests.
first off, it makes sense to run them
automated test suites fail when they expect not to have any maintenance
tests take maintenance
tests are software
changes will occur, and they can be of 2 natures
does that remind you of something ?
deployment is important, but not that critical
if you&#x2019;ve got a well-structured, well-written, modular application, you can change deployment fairly easily
one thing to add in your description of the application: a schematic of the deployment
they should be able to provide that, if only on a paper napkin
those were for me the important points
if what we saw up to now is ok, they will get a good report.
the following slides will get them a glowing report, with exclamation points
It&#x2019;s time to go home with your notes and write a report
Are there any questions ?
I hope you enjoyed the talk, and that you got something out of it.