SlideShare a Scribd company logo
1 of 93
Download to read offline
hours to rate a
               Rails application
                          Elise Huard @elise_huard
                            http://jabberwocky.eu



Wednesday 31 March 2010
Acquisition




Wednesday 31 March 2010
Maintenance




Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application



                            12:00
Wednesday 31 March 2010
Team




Wednesday 31 March 2010
Team: use
                          your gut




Wednesday 31 March 2010
One man’s
       application



Wednesday 31 March 2010
innovator




                          automator




                                      Control Freak



Wednesday 31 March 2010
...




Wednesday 31 March 2010
Vision




Wednesday 31 March 2010
Methodology


Wednesday 31 March 2010
Bug Tracker
                 Version control




Wednesday 31 March 2010
Back seat
                 driver



Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application


                            10:00
Wednesday 31 March 2010
Try the app




Wednesday 31 March 2010
does it work ?



Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application



                           09:45
Wednesday 31 March 2010
Rails version



Wednesday 31 March 2010
plugins and
                  gems




Wednesday 31 March 2010
Wednesday 31 March 2010
managing updates
                                 piston
                            git submodules
                            (svn externals)




Wednesday 31 March 2010
Licenses




Wednesday 31 March 2010
NIH syndrom



Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application


                           09:00
Wednesday 31 March 2010
All that code




Wednesday 31 March 2010
config/routes.rb

                   map.root :controller => 'root', :action => 'index'

                  map.namespace :admin do |admin|
                    admin.resources :grids do |grid|
                      grid.resources :nodes
                      grid.resources :edges, :collection => {:all => :post, :update_all
                => :post}
                      grid.resources :walkers
                    end
                  end

                  map.resources :nodes, :only =>
                [:new,:create,:show,:destroy], :collection => {:directions => :put}
                  map.resources :walkers, :only =>
                [:show,:new,:create,:destroy], :collection => {:select => :get}
                  map.resources :itineraries, :only => [:show]

                   map.four_oh_four '*path' , :controller => 'four_oh_fours'




Wednesday 31 March 2010
models
                railroad -M | dot Tpng > models.png
                         rubymine ctrl-alt-D
                   uml dumper (needs maintenance)
Wednesday 31 March 2010
names


                          “There are only two hard things in
                          Computer Science: cache
                          invalidation and naming things”
                                                  Phil Karlton




Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application


                           08:30
Wednesday 31 March 2010
Coffee




Wednesday 31 March 2010
metrics

Wednesday 31 March 2010
Know thine tools




Wednesday 31 March 2010
LOC
             rake stats
             +----------------------+-------+-------+---------+---------+-----+-------+
             | Name                 | Lines |    LOC | Classes | Methods | M/C | LOC/M |
             +----------------------+-------+-------+---------+---------+-----+-------+
             | Controllers          | 2702 | 2150 |          36 |     158 |   4 |   11 |
             | Helpers              |   358 |    303 |        0 |      22 |   0 |   11 |
             | Models               | 1358 | 1104 |          30 |     117 |   3 |    7 |
             | Libraries            | 2286 | 1655 |          38 |     152 |   4 |    8 |
             | Integration tests    |     0 |      0 |        0 |       0 |   0 |    0 |
             | Functional tests     | 1687 | 1322 |          31 |     195 |   6 |    4 |
             | Unit tests           | 1356 | 1079 |          27 |     158 |   5 |    4 |
             +----------------------+-------+-------+---------+---------+-----+-------+
             | Total                | 9747 | 7613 |         162 |     802 |   4 |    7 |
             +----------------------+-------+-------+---------+---------+-----+-------+
               Code LOC: 5212     Test LOC: 2401       Code to Test Ratio: 1:0.5




Wednesday 31 March 2010
RubyParser and
                                Parsetree



                          Ryan Davis and Eric Hodel
                               (‘Ruby Sadists’)




Wednesday 31 March 2010
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
flog
                          ‘the pain your
                            code is in’




Wednesday 31 March 2010
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
FLOG
              flog lib/flog.rb
                 647.8: flog total
                  13.8: flog/method average

                          87.5:   Flog#output_details
                          58.8:   Flog#process_iter
                          54.2:   Flog#flog
                          48.8:   Flog#parse_options
                          34.1:   Flog#none
                          23.2:   Flog#output_method_details
                          22.1:   Flog#score_method
                          16.0:   Flog#process_block_pass
                          15.6:   Flog#report
                          15.2:   Flog#expand_dirs_to_files
                          15.0:   Flog#klass_name


Wednesday 31 March 2010
FLOG



                          Very good: < 20
                          All Right: < 50




Wednesday 31 March 2010
FLAY
        code similarities




Wednesday 31 March 2010
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
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
Saikuro

                          cyclomatic
                          complexity




Wednesday 31 March 2010
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
Saikuro




Wednesday 31 March 2010
Saikuro




                             Good:
                          methods < 5




Wednesday 31 March 2010
Roodi
      Ruby Object Oriented Design
      Inferometer (what ?)
      “design issues”




Wednesday 31 March 2010
Roodi


                          RubyParser
                          visitor pattern
                           visitor: checker (Configurable)
                           visitable: parsed nodes
                          = extensible




Wednesday 31 March 2010
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
Reek
       Control Couple
       Data Clump
       Feature Envy
       Large Class
       Long Method
       Long Parameter List
       Simulated Polymorphism
       Uncommunicative Name




Wednesday 31 March 2010
Reek



                             RubyParser
                        extends parsed nodes
                           traverses nodes
                    returns code after Ruby2Ruby




Wednesday 31 March 2010
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
Churn




                     Frequent changes may indicate
                                issue

Wednesday 31 March 2010
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
Churn

                    +-------------------------------------------------+---------------+
                    | file_path                                       | times_changed |
                    +-------------------------------------------------+---------------+
                    | db/schema.rb                                    | 26            |
                    | config/routes.rb                                | 24            |
                    | app/controllers/application_controller.rb       | 22            |
                    | app/controllers/add_apps_controller.rb          | 22            |
                    | config/environment.rb                           | 20            |
                    | app/views/layouts/application.html.erb          | 20            |
                    | app/models/ability.rb                           | 18            |
                    ...




Wednesday 31 March 2010
Churn



                              common sense ...
                     mostly useful in maintenance phase




Wednesday 31 March 2010
Rcov




Wednesday 31 March 2010
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
Rcov




               Total coverage: comments included




Wednesday 31 March 2010
Rcov



                          good: 100% coverage




Wednesday 31 March 2010
Heckle




Wednesday 31 March 2010
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
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
rake stats
                 size
        Flog                       Flay
           code complexity          code similarities

  Roodi
   Saikuro                         Reek
        cyclomatic                        antipatterns
        complexity
                          Heckle                    Rcov

                                   test coverage

Wednesday 31 March 2010
metric_fu




Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application


                           06:30
Wednesday 31 March 2010
Lunch




Wednesday 31 March 2010
and more
                           Coffee




Wednesday 31 March 2010
read some
                            code




Wednesday 31 March 2010
Expressive code




Wednesday 31 March 2010
Database

                                db/schema.rb
                                  seed data
                          everything in migrations ?




Wednesday 31 March 2010
Nested_has_many_through



Wednesday 31 March 2010
views

                             Bad:
                             unindented
                             divitis
                             javascript in the body
                             too much logic in viewiew




Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application


                           04:30
Wednesday 31 March 2010
run tests




Wednesday 31 March 2010
Time for tests
        (or autotest/ci)




Wednesday 31 March 2010
maintainable test
                                 suite


                          tests = software

                          changes in implementation
                          changes in requirements




Wednesday 31 March 2010
maintainable test
                                 suite


                          express code responsibility
                          hide incident detail
                          DRY




Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application


                           02:30
Wednesday 31 March 2010
Deployment




Wednesday 31 March 2010
Deployment




Wednesday 31 March 2010
Deployment



           Automation, automation, automation




Wednesday 31 March 2010
Deployment


                          deployment = software
                             same rules apply




Wednesday 31 March 2010
Traffic




Wednesday 31 March 2010
Performance tests
                             Bottlenecks




Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application


                            01:00
Wednesday 31 March 2010
Brownie Points




Wednesday 31 March 2010
Continuous
              integration




                          ... and they’re using it

Wednesday 31 March 2010
Documentation of
                              any kind




     ... and it’s up to date

Wednesday 31 March 2010
monitoring
        exception notification
            Log analyzers




Wednesday 31 March 2010
testing javascripts
    Continuous performance testing




Wednesday 31 March 2010
12 hours To
                          Rate a Rails
                          Application


                           00:00
Wednesday 31 March 2010
http://railroad.rubyforge.org/
   http://www.igvita.com/2008/12/11/ruby-ast-for-fun-and-profit/
   http://ruby.sadi.st/Ruby_Sadist.html
   http://goruco2008.confreaks.com/04_davis.html
   http://cwd.dhemery.com/2009/11/wmaat/
   http://c2.com/cgi/wiki?AbcMetric
   http://hissa.nist.gov/HHRFdata/Artifacts/ITLdoc/235/title.htm
   http://blog.rubybestpractices.com/posts/judofyr/sexp-for-
   rubyists.html


   Elise Huard @elise_huard
   elise@elisehuard.be
   http://jabberwocky.eu


Wednesday 31 March 2010

More Related Content

Similar to 12 Hours To Rate A Rails Application

12 hours to rate a rails application
12 hours to rate a rails application12 hours to rate a rails application
12 hours to rate a rails applicationehuard
 
how to rate a Rails application
how to rate a Rails applicationhow to rate a Rails application
how to rate a Rails applicationehuard
 
Nick Sieger-Exploring Rails 3 Through Choices
Nick Sieger-Exploring Rails 3 Through Choices Nick Sieger-Exploring Rails 3 Through Choices
Nick Sieger-Exploring Rails 3 Through Choices ThoughtWorks
 
Amebaサーチのデータを用いた応用
Amebaサーチのデータを用いた応用Amebaサーチのデータを用いた応用
Amebaサーチのデータを用いた応用moai kids
 
Robotic Testing to the Rescue - Paul Dubois (DoubleFine)
Robotic Testing to the Rescue - Paul Dubois (DoubleFine)Robotic Testing to the Rescue - Paul Dubois (DoubleFine)
Robotic Testing to the Rescue - Paul Dubois (DoubleFine)Kore VM
 
MOSES: Community finding using Model-based Overlapping Seed ExpanSion
MOSES: Community finding using Model-based Overlapping Seed ExpanSionMOSES: Community finding using Model-based Overlapping Seed ExpanSion
MOSES: Community finding using Model-based Overlapping Seed ExpanSionaaronmcdaid
 
Robot Localisation: An Introduction - Luis Contreras 2020.06.09 | RoboCup@Hom...
Robot Localisation: An Introduction - Luis Contreras 2020.06.09 | RoboCup@Hom...Robot Localisation: An Introduction - Luis Contreras 2020.06.09 | RoboCup@Hom...
Robot Localisation: An Introduction - Luis Contreras 2020.06.09 | RoboCup@Hom...robocupathomeedu
 
MongoDB & Mongomapper 4 real
MongoDB & Mongomapper 4 realMongoDB & Mongomapper 4 real
MongoDB & Mongomapper 4 realjan_mindmatters
 
Home Page Live(Www2007)
Home Page Live(Www2007)Home Page Live(Www2007)
Home Page Live(Www2007)tomelf2007
 
Kyo - Functional Scala 2023.pdf
Kyo - Functional Scala 2023.pdfKyo - Functional Scala 2023.pdf
Kyo - Functional Scala 2023.pdfFlavio W. Brasil
 
Model-Driven Software Development - Introduction & Overview
Model-Driven Software Development - Introduction & OverviewModel-Driven Software Development - Introduction & Overview
Model-Driven Software Development - Introduction & OverviewEelco Visser
 

Similar to 12 Hours To Rate A Rails Application (12)

12 hours to rate a rails application
12 hours to rate a rails application12 hours to rate a rails application
12 hours to rate a rails application
 
how to rate a Rails application
how to rate a Rails applicationhow to rate a Rails application
how to rate a Rails application
 
Nick Sieger-Exploring Rails 3 Through Choices
Nick Sieger-Exploring Rails 3 Through Choices Nick Sieger-Exploring Rails 3 Through Choices
Nick Sieger-Exploring Rails 3 Through Choices
 
Relational Calculus
Relational CalculusRelational Calculus
Relational Calculus
 
Amebaサーチのデータを用いた応用
Amebaサーチのデータを用いた応用Amebaサーチのデータを用いた応用
Amebaサーチのデータを用いた応用
 
Robotic Testing to the Rescue - Paul Dubois (DoubleFine)
Robotic Testing to the Rescue - Paul Dubois (DoubleFine)Robotic Testing to the Rescue - Paul Dubois (DoubleFine)
Robotic Testing to the Rescue - Paul Dubois (DoubleFine)
 
MOSES: Community finding using Model-based Overlapping Seed ExpanSion
MOSES: Community finding using Model-based Overlapping Seed ExpanSionMOSES: Community finding using Model-based Overlapping Seed ExpanSion
MOSES: Community finding using Model-based Overlapping Seed ExpanSion
 
Robot Localisation: An Introduction - Luis Contreras 2020.06.09 | RoboCup@Hom...
Robot Localisation: An Introduction - Luis Contreras 2020.06.09 | RoboCup@Hom...Robot Localisation: An Introduction - Luis Contreras 2020.06.09 | RoboCup@Hom...
Robot Localisation: An Introduction - Luis Contreras 2020.06.09 | RoboCup@Hom...
 
MongoDB & Mongomapper 4 real
MongoDB & Mongomapper 4 realMongoDB & Mongomapper 4 real
MongoDB & Mongomapper 4 real
 
Home Page Live(Www2007)
Home Page Live(Www2007)Home Page Live(Www2007)
Home Page Live(Www2007)
 
Kyo - Functional Scala 2023.pdf
Kyo - Functional Scala 2023.pdfKyo - Functional Scala 2023.pdf
Kyo - Functional Scala 2023.pdf
 
Model-Driven Software Development - Introduction & Overview
Model-Driven Software Development - Introduction & OverviewModel-Driven Software Development - Introduction & Overview
Model-Driven Software Development - Introduction & Overview
 

More from ehuard

Euroclojure 2017
Euroclojure 2017Euroclojure 2017
Euroclojure 2017ehuard
 
Ruby goes to Hollywood
Ruby goes to HollywoodRuby goes to Hollywood
Ruby goes to Hollywoodehuard
 
Ruby hollywood nordic
Ruby hollywood nordicRuby hollywood nordic
Ruby hollywood nordicehuard
 
Ruby goes to hollywood
Ruby goes to hollywoodRuby goes to hollywood
Ruby goes to hollywoodehuard
 
Ruby hollywood
Ruby hollywoodRuby hollywood
Ruby hollywoodehuard
 
Concurrency: Rubies, plural
Concurrency: Rubies, pluralConcurrency: Rubies, plural
Concurrency: Rubies, pluralehuard
 
Concurrency
ConcurrencyConcurrency
Concurrencyehuard
 
Concurrency
ConcurrencyConcurrency
Concurrencyehuard
 
Barcamp Ghent2009
Barcamp Ghent2009Barcamp Ghent2009
Barcamp Ghent2009ehuard
 
Tokyo Cabinet
Tokyo CabinetTokyo Cabinet
Tokyo Cabinetehuard
 
The real-time web
The real-time webThe real-time web
The real-time webehuard
 
Rails and the internet of things
Rails and the internet of thingsRails and the internet of things
Rails and the internet of thingsehuard
 

More from ehuard (13)

Euroclojure 2017
Euroclojure 2017Euroclojure 2017
Euroclojure 2017
 
Ruby goes to Hollywood
Ruby goes to HollywoodRuby goes to Hollywood
Ruby goes to Hollywood
 
Ruby hollywood nordic
Ruby hollywood nordicRuby hollywood nordic
Ruby hollywood nordic
 
Ruby goes to hollywood
Ruby goes to hollywoodRuby goes to hollywood
Ruby goes to hollywood
 
Ruby hollywood
Ruby hollywoodRuby hollywood
Ruby hollywood
 
Concurrency: Rubies, plural
Concurrency: Rubies, pluralConcurrency: Rubies, plural
Concurrency: Rubies, plural
 
Concurrency
ConcurrencyConcurrency
Concurrency
 
Concurrency
ConcurrencyConcurrency
Concurrency
 
Barcamp Ghent2009
Barcamp Ghent2009Barcamp Ghent2009
Barcamp Ghent2009
 
Tokyo Cabinet
Tokyo CabinetTokyo Cabinet
Tokyo Cabinet
 
The real-time web
The real-time webThe real-time web
The real-time web
 
Rails and the internet of things
Rails and the internet of thingsRails and the internet of things
Rails and the internet of things
 
Oauth
OauthOauth
Oauth
 

Recently uploaded

Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Manik S Magar
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 

Recently uploaded (20)

Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!Anypoint Exchange: It’s Not Just a Repo!
Anypoint Exchange: It’s Not Just a Repo!
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 

12 Hours To Rate A Rails Application

  • 1. hours to rate a Rails application Elise Huard @elise_huard http://jabberwocky.eu Wednesday 31 March 2010
  • 4. 12 hours To Rate a Rails Application 12:00 Wednesday 31 March 2010
  • 6. Team: use your gut Wednesday 31 March 2010
  • 7. One man’s application Wednesday 31 March 2010
  • 8. innovator automator Control Freak Wednesday 31 March 2010
  • 12. Bug Tracker Version control Wednesday 31 March 2010
  • 13. Back seat driver Wednesday 31 March 2010
  • 14. 12 hours To Rate a Rails Application 10:00 Wednesday 31 March 2010
  • 15. Try the app Wednesday 31 March 2010
  • 16. does it work ? Wednesday 31 March 2010
  • 17. 12 hours To Rate a Rails Application 09:45 Wednesday 31 March 2010
  • 19. plugins and gems Wednesday 31 March 2010
  • 21. managing updates piston git submodules (svn externals) Wednesday 31 March 2010
  • 24. 12 hours To Rate a Rails Application 09:00 Wednesday 31 March 2010
  • 25. All that code Wednesday 31 March 2010
  • 26. config/routes.rb map.root :controller => 'root', :action => 'index' map.namespace :admin do |admin| admin.resources :grids do |grid| grid.resources :nodes grid.resources :edges, :collection => {:all => :post, :update_all => :post} grid.resources :walkers end end map.resources :nodes, :only => [:new,:create,:show,:destroy], :collection => {:directions => :put} map.resources :walkers, :only => [:show,:new,:create,:destroy], :collection => {:select => :get} map.resources :itineraries, :only => [:show] map.four_oh_four '*path' , :controller => 'four_oh_fours' Wednesday 31 March 2010
  • 27. models railroad -M | dot Tpng > models.png rubymine ctrl-alt-D uml dumper (needs maintenance) Wednesday 31 March 2010
  • 28. names “There are only two hard things in Computer Science: cache invalidation and naming things” Phil Karlton Wednesday 31 March 2010
  • 29. 12 hours To Rate a Rails Application 08:30 Wednesday 31 March 2010
  • 32. Know thine tools Wednesday 31 March 2010
  • 33. LOC rake stats +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 2702 | 2150 | 36 | 158 | 4 | 11 | | Helpers | 358 | 303 | 0 | 22 | 0 | 11 | | Models | 1358 | 1104 | 30 | 117 | 3 | 7 | | Libraries | 2286 | 1655 | 38 | 152 | 4 | 8 | | Integration tests | 0 | 0 | 0 | 0 | 0 | 0 | | Functional tests | 1687 | 1322 | 31 | 195 | 6 | 4 | | Unit tests | 1356 | 1079 | 27 | 158 | 5 | 4 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 9747 | 7613 | 162 | 802 | 4 | 7 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 5212 Test LOC: 2401 Code to Test Ratio: 1:0.5 Wednesday 31 March 2010
  • 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
  • 38. FLOG flog lib/flog.rb 647.8: flog total 13.8: flog/method average 87.5: Flog#output_details 58.8: Flog#process_iter 54.2: Flog#flog 48.8: Flog#parse_options 34.1: Flog#none 23.2: Flog#output_method_details 22.1: Flog#score_method 16.0: Flog#process_block_pass 15.6: Flog#report 15.2: Flog#expand_dirs_to_files 15.0: Flog#klass_name 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
  • 46. Saikuro Good: methods < 5 Wednesday 31 March 2010
  • 47. Roodi Ruby Object Oriented Design Inferometer (what ?) “design issues” Wednesday 31 March 2010
  • 48. Roodi RubyParser visitor pattern visitor: checker (Configurable) visitable: parsed nodes = extensible 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
  • 55. Churn +-------------------------------------------------+---------------+ | file_path | times_changed | +-------------------------------------------------+---------------+ | db/schema.rb | 26 | | config/routes.rb | 24 | | app/controllers/application_controller.rb | 22 | | app/controllers/add_apps_controller.rb | 22 | | config/environment.rb | 20 | | app/views/layouts/application.html.erb | 20 | | app/models/ability.rb | 18 | ... Wednesday 31 March 2010
  • 56. Churn common sense ... mostly useful in maintenance phase 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
  • 64. rake stats size Flog Flay code complexity code similarities Roodi Saikuro Reek cyclomatic antipatterns complexity Heckle Rcov test coverage Wednesday 31 March 2010
  • 66. 12 hours To Rate a Rails Application 06:30 Wednesday 31 March 2010
  • 68. and more Coffee Wednesday 31 March 2010
  • 69. read some code Wednesday 31 March 2010
  • 71. Database db/schema.rb seed data everything in migrations ? Wednesday 31 March 2010
  • 73. views Bad: unindented divitis javascript in the body too much logic in viewiew Wednesday 31 March 2010
  • 74. 12 hours To Rate a Rails Application 04:30 Wednesday 31 March 2010
  • 76. Time for tests (or autotest/ci) Wednesday 31 March 2010
  • 77. maintainable test suite tests = software changes in implementation changes in requirements Wednesday 31 March 2010
  • 78. maintainable test suite express code responsibility hide incident detail DRY Wednesday 31 March 2010
  • 79. 12 hours To Rate a Rails Application 02:30 Wednesday 31 March 2010
  • 82. Deployment Automation, automation, automation Wednesday 31 March 2010
  • 83. Deployment deployment = software same rules apply Wednesday 31 March 2010
  • 85. Performance tests Bottlenecks Wednesday 31 March 2010
  • 86. 12 hours To Rate a Rails Application 01:00 Wednesday 31 March 2010
  • 88. Continuous integration ... and they’re using it Wednesday 31 March 2010
  • 89. Documentation of any kind ... and it’s up to date Wednesday 31 March 2010
  • 90. monitoring exception notification Log analyzers Wednesday 31 March 2010
  • 91. testing javascripts Continuous performance testing Wednesday 31 March 2010
  • 92. 12 hours To Rate a Rails Application 00:00 Wednesday 31 March 2010
  • 93. http://railroad.rubyforge.org/ http://www.igvita.com/2008/12/11/ruby-ast-for-fun-and-profit/ http://ruby.sadi.st/Ruby_Sadist.html http://goruco2008.confreaks.com/04_davis.html http://cwd.dhemery.com/2009/11/wmaat/ http://c2.com/cgi/wiki?AbcMetric http://hissa.nist.gov/HHRFdata/Artifacts/ITLdoc/235/title.htm http://blog.rubybestpractices.com/posts/judofyr/sexp-for- rubyists.html Elise Huard @elise_huard elise@elisehuard.be http://jabberwocky.eu Wednesday 31 March 2010

Editor's Notes

  1. 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.
  2. 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.
  3. sit down with the team they will make an introduction and you can observe them: looking at people you can already form an idea
  4. you have experience which will allow you to tell whether you have a team that will produce good to great software.
  5. One guy: usually bad sign - easier to slack off when you&amp;#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
  6. I&amp;#x2019;m sure there are many learned articles about group dynamics, about personality types in a team, etc ... the innovator: keeps up with what&amp;#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.
  7. You&amp;#x2019;ll notice I don&amp;#x2019;t include him ... Bottom line, after you&amp;#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&amp;#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
  8. tools I think you cannot do without. Even if the bug tracker is a text file.
  9. so you sat down with the team, you discussed the application, their philosophy, the deployment, other aspects ...
  10. it&amp;#x2019;s time to dive in, and see what we have here.
  11. does it work ? does the application match the vision ? Is it clear at all ? &amp;#x2018;don&amp;#x2019;t make me think&amp;#x2019; do you manage to get pesky 500s and 404 ?
  12. that shouldn&amp;#x2019;t take too long.
  13. then you can start inventorizing what you&amp;#x2019;ve got. First off, what version of rails are they using ? I think it&amp;#x2019;s a good sign when it&amp;#x2019;s a reasonably recent version.
  14. Same for plugins. what gems, what plugins are they using ? Is it the last version ?
  15. I&amp;#x2019;m a firm believer in the natural selection of open source Are they popular ? Are they maintained ?
  16. are the plugins and gems easily updatable ?
  17. 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
  18. I think I look out for, is the Not Invented Here syndrom. some people will not trust plugins they have not written themselves. That&amp;#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
  19. OK, plugins and gems are inventorized.
  20. you often have a sizeable code base to look at ... where to start ? Where would you start ?
  21. what&amp;#x2019;s the action in the application ?
  22. 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
  23. we now have a very high level view of the application. Now, before continuing, there is one priority
  24. One way to start analyzing a large amount of code, is by using metrics.
  25. I&amp;#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&amp;#x2019;m going to try to go a little bit further, to give you an idea of what&amp;#x2019;s under the hood
  26. the first code metric in history are lines of code. Unfortunately, they don&amp;#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.
  27. 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.
  28. 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
  29. 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.
  30. The result is a series of number - per class and per method.
  31. Per method, you expect something like this
  32. guess where the name &amp;#x2018;saikuro&amp;#x2019; comes from Japanese people have this habit of taking over words that indicate new concepts bi-ru co-hee it&amp;#x2019;s cyclo as used by japanese people number of linearly independent paths through a program&apos;s source code. it&amp;#x2019;s also a measure of code complexity
  33. lexer: step before parsing - split program = characters - into tokens
  34. we come to the less quantitative tools - roodi and reek find design issues for you.
  35. abc metric like flog assignment in conditional missing else in a case class variables
  36. 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?
  37. The tool we all know to check our test coverage
  38. Now, code coverage doesn&amp;#x2019;t say much. For a good test set, you need 100%, but that&amp;#x2019;s a minimum requirement. You can have 100% coverage without
  39. Heckle is really interesting in theory, difficult to apply in practice.
  40. in the next mutation, it changed this to nil the one after that, ti change the symbol to something else
  41. 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
  42. and it&amp;#x2019;s time for lunch
  43. revigorated, it&amp;#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
  44. code should be readable. Ideally like a book At the very least it shouldn&amp;#x2019;t take too much effort to understand what&amp;#x2019;s going on.
  45. rails is not slow, developers make bad use of the data base it&amp;#x2019;s not because we use an ORM that we can drop all knowledge
  46. this is a plugin I&amp;#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
  47. We&amp;#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
  48. it&amp;#x2019;s time to have a closer look at the tests. first off, it makes sense to run them
  49. 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
  50. does that remind you of something ?
  51. deployment is important, but not that critical if you&amp;#x2019;ve got a well-structured, well-written, modular application, you can change deployment fairly easily
  52. 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
  53. 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
  54. It&amp;#x2019;s time to go home with your notes and write a report Are there any questions ?
  55. I hope you enjoyed the talk, and that you got something out of it.