SlideShare a Scribd company logo

Code Quality Analysis

1 of 110
Download to read offline
Code Quality Analysis
       Marty Andrews
      @martinjandrews

                        .com.au
Code Quality Analysis
Code Quality Analysis
static analysis
                  =
software analysis without execution
no app runtime required!
Code Quality Analysis

Recommended

Code Quality Learn, Measure And Organize Awareness
Code Quality   Learn, Measure And Organize AwarenessCode Quality   Learn, Measure And Organize Awareness
Code Quality Learn, Measure And Organize AwarenessJaibeer Malik
 
Measuring Code Quality in WTF/min.
Measuring Code Quality in WTF/min. Measuring Code Quality in WTF/min.
Measuring Code Quality in WTF/min. David Gómez García
 
Code Quality Assurance v4 (2013)
Code Quality Assurance v4 (2013)Code Quality Assurance v4 (2013)
Code Quality Assurance v4 (2013)Peter Kofler
 
Managing code quality with SonarQube - Radu Vunvulea
Managing code quality with SonarQube - Radu VunvuleaManaging code quality with SonarQube - Radu Vunvulea
Managing code quality with SonarQube - Radu VunvuleaITSpark Community
 
User-Perceived Source Code Quality Estimation based on Static Analysis Metrics
User-Perceived Source Code Quality Estimation based on Static Analysis MetricsUser-Perceived Source Code Quality Estimation based on Static Analysis Metrics
User-Perceived Source Code Quality Estimation based on Static Analysis MetricsISSEL
 
Code quality as a built-in process
Code quality as a built-in processCode quality as a built-in process
Code quality as a built-in processElad Maimon
 
Understanding, measuring and improving code quality in JavaScript
Understanding, measuring and improving code quality in JavaScriptUnderstanding, measuring and improving code quality in JavaScript
Understanding, measuring and improving code quality in JavaScriptMark Daggett
 
Measuring the Code Quality Using Software Metrics
Measuring the Code Quality Using Software MetricsMeasuring the Code Quality Using Software Metrics
Measuring the Code Quality Using Software MetricsGeetha Anjali
 

More Related Content

Viewers also liked

Agile code quality metrics
Agile code quality metricsAgile code quality metrics
Agile code quality metricsGil Nahmias
 
SonarQube - The leading platform for Continuous Code Quality
SonarQube - The leading platform for Continuous Code QualitySonarQube - The leading platform for Continuous Code Quality
SonarQube - The leading platform for Continuous Code QualityLarry Nung
 
Code quality
Code qualityCode quality
Code qualityProvectus
 
Python - code quality and production monitoring
Python - code quality and production monitoringPython - code quality and production monitoring
Python - code quality and production monitoringDavid Melamed
 
Measure and Improve code quality. Using automation.
Measure and Improve code quality.  Using automation.Measure and Improve code quality.  Using automation.
Measure and Improve code quality. Using automation.Vladimir Korolev
 

Viewers also liked (6)

Agile code quality metrics
Agile code quality metricsAgile code quality metrics
Agile code quality metrics
 
SonarQube - The leading platform for Continuous Code Quality
SonarQube - The leading platform for Continuous Code QualitySonarQube - The leading platform for Continuous Code Quality
SonarQube - The leading platform for Continuous Code Quality
 
Code quality
Code qualityCode quality
Code quality
 
Python - code quality and production monitoring
Python - code quality and production monitoringPython - code quality and production monitoring
Python - code quality and production monitoring
 
Measure and Improve code quality. Using automation.
Measure and Improve code quality.  Using automation.Measure and Improve code quality.  Using automation.
Measure and Improve code quality. Using automation.
 
Aspects Of Code Quality meetup
Aspects Of Code Quality   meetupAspects Of Code Quality   meetup
Aspects Of Code Quality meetup
 

Similar to Code Quality Analysis

The Magic Of Application Lifecycle Management In Vs Public
The Magic Of Application Lifecycle Management In Vs PublicThe Magic Of Application Lifecycle Management In Vs Public
The Magic Of Application Lifecycle Management In Vs PublicDavid Solivan
 
Parasoft .TEST, Write better C# Code Using Data Flow Analysis
Parasoft .TEST, Write better C# Code Using  Data Flow Analysis Parasoft .TEST, Write better C# Code Using  Data Flow Analysis
Parasoft .TEST, Write better C# Code Using Data Flow Analysis Engineering Software Lab
 
Ramesh Krishnamurthy, CTO at World DevOps Summit 2016
Ramesh Krishnamurthy, CTO at World DevOps Summit 2016Ramesh Krishnamurthy, CTO at World DevOps Summit 2016
Ramesh Krishnamurthy, CTO at World DevOps Summit 2016Indium Software
 
Improving Code Quality Through Effective Review Process
Improving Code Quality Through Effective  Review ProcessImproving Code Quality Through Effective  Review Process
Improving Code Quality Through Effective Review ProcessDr. Syed Hassan Amin
 
Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your CodeNate Abele
 
Measuring Your Code 2.0
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0Nate Abele
 
Developing a Culture of Quality Code (Midwest PHP 2020)
Developing a Culture of Quality Code (Midwest PHP 2020)Developing a Culture of Quality Code (Midwest PHP 2020)
Developing a Culture of Quality Code (Midwest PHP 2020)Scott Keck-Warren
 
Useful practices of creation automatic tests by using cucumber jvm
Useful practices of creation automatic tests by using cucumber jvmUseful practices of creation automatic tests by using cucumber jvm
Useful practices of creation automatic tests by using cucumber jvmAnton Shapin
 
Track c how do we break - jasper
Track c   how do we break - jasperTrack c   how do we break - jasper
Track c how do we break - jasperchiportal
 
Neotys PAC 2018 - Tingting Zong
Neotys PAC 2018 - Tingting ZongNeotys PAC 2018 - Tingting Zong
Neotys PAC 2018 - Tingting ZongNeotys_Partner
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperfNew Relic
 
Surekha_haoop_exp
Surekha_haoop_expSurekha_haoop_exp
Surekha_haoop_expsurekhakadi
 
The "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/OpsThe "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/OpsErik Osterman
 
Graph-Based Source Code Analysis of JavaScript Repositories
Graph-Based Source Code Analysis of JavaScript Repositories Graph-Based Source Code Analysis of JavaScript Repositories
Graph-Based Source Code Analysis of JavaScript Repositories Dániel Stein
 
Jonathon Wright - Intelligent Performance Cognitive Learning (AIOps)
Jonathon Wright - Intelligent Performance Cognitive Learning (AIOps)Jonathon Wright - Intelligent Performance Cognitive Learning (AIOps)
Jonathon Wright - Intelligent Performance Cognitive Learning (AIOps)Neotys_Partner
 
20141210 rakuten techtalk
20141210 rakuten techtalk20141210 rakuten techtalk
20141210 rakuten techtalkHiroshi SHIBATA
 
Pragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScriptPragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScriptdavejohnson
 
Compliance as Code Everywhere
Compliance as Code EverywhereCompliance as Code Everywhere
Compliance as Code EverywhereMatt Ray
 
Enhancing Your Test Automation Scenario Coverage with Selenium - QA or the Hi...
Enhancing Your Test Automation Scenario Coverage with Selenium - QA or the Hi...Enhancing Your Test Automation Scenario Coverage with Selenium - QA or the Hi...
Enhancing Your Test Automation Scenario Coverage with Selenium - QA or the Hi...Perfecto by Perforce
 

Similar to Code Quality Analysis (20)

The Magic Of Application Lifecycle Management In Vs Public
The Magic Of Application Lifecycle Management In Vs PublicThe Magic Of Application Lifecycle Management In Vs Public
The Magic Of Application Lifecycle Management In Vs Public
 
Parasoft .TEST, Write better C# Code Using Data Flow Analysis
Parasoft .TEST, Write better C# Code Using  Data Flow Analysis Parasoft .TEST, Write better C# Code Using  Data Flow Analysis
Parasoft .TEST, Write better C# Code Using Data Flow Analysis
 
Ramesh Krishnamurthy, CTO at World DevOps Summit 2016
Ramesh Krishnamurthy, CTO at World DevOps Summit 2016Ramesh Krishnamurthy, CTO at World DevOps Summit 2016
Ramesh Krishnamurthy, CTO at World DevOps Summit 2016
 
Improving Code Quality Through Effective Review Process
Improving Code Quality Through Effective  Review ProcessImproving Code Quality Through Effective  Review Process
Improving Code Quality Through Effective Review Process
 
Measuring Your Code
Measuring Your CodeMeasuring Your Code
Measuring Your Code
 
Measuring Your Code 2.0
Measuring Your Code 2.0Measuring Your Code 2.0
Measuring Your Code 2.0
 
Developing a Culture of Quality Code (Midwest PHP 2020)
Developing a Culture of Quality Code (Midwest PHP 2020)Developing a Culture of Quality Code (Midwest PHP 2020)
Developing a Culture of Quality Code (Midwest PHP 2020)
 
Useful practices of creation automatic tests by using cucumber jvm
Useful practices of creation automatic tests by using cucumber jvmUseful practices of creation automatic tests by using cucumber jvm
Useful practices of creation automatic tests by using cucumber jvm
 
Track c how do we break - jasper
Track c   how do we break - jasperTrack c   how do we break - jasper
Track c how do we break - jasper
 
Neotys PAC 2018 - Tingting Zong
Neotys PAC 2018 - Tingting ZongNeotys PAC 2018 - Tingting Zong
Neotys PAC 2018 - Tingting Zong
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
 
Surekha_haoop_exp
Surekha_haoop_expSurekha_haoop_exp
Surekha_haoop_exp
 
The "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/OpsThe "Holy Grail" of Dev/Ops
The "Holy Grail" of Dev/Ops
 
Graph-Based Source Code Analysis of JavaScript Repositories
Graph-Based Source Code Analysis of JavaScript Repositories Graph-Based Source Code Analysis of JavaScript Repositories
Graph-Based Source Code Analysis of JavaScript Repositories
 
Jonathon Wright - Intelligent Performance Cognitive Learning (AIOps)
Jonathon Wright - Intelligent Performance Cognitive Learning (AIOps)Jonathon Wright - Intelligent Performance Cognitive Learning (AIOps)
Jonathon Wright - Intelligent Performance Cognitive Learning (AIOps)
 
20141210 rakuten techtalk
20141210 rakuten techtalk20141210 rakuten techtalk
20141210 rakuten techtalk
 
10 Ways To Improve Your Code
10 Ways To Improve Your Code10 Ways To Improve Your Code
10 Ways To Improve Your Code
 
Pragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScriptPragmatic Parallels: Java and JavaScript
Pragmatic Parallels: Java and JavaScript
 
Compliance as Code Everywhere
Compliance as Code EverywhereCompliance as Code Everywhere
Compliance as Code Everywhere
 
Enhancing Your Test Automation Scenario Coverage with Selenium - QA or the Hi...
Enhancing Your Test Automation Scenario Coverage with Selenium - QA or the Hi...Enhancing Your Test Automation Scenario Coverage with Selenium - QA or the Hi...
Enhancing Your Test Automation Scenario Coverage with Selenium - QA or the Hi...
 

Recently uploaded

"Testing of Helm Charts or There and Back Again", Yura Rochniak
"Testing of Helm Charts or There and Back Again", Yura Rochniak"Testing of Helm Charts or There and Back Again", Yura Rochniak
"Testing of Helm Charts or There and Back Again", Yura RochniakFwdays
 
How to write an effective Cyber Incident Response Plan
How to write an effective Cyber Incident Response PlanHow to write an effective Cyber Incident Response Plan
How to write an effective Cyber Incident Response PlanDatabarracks
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsEvangelia Mitsopoulou
 
Pragmatic UI testing with Compose Semantics.pdf
Pragmatic UI testing with Compose Semantics.pdfPragmatic UI testing with Compose Semantics.pdf
Pragmatic UI testing with Compose Semantics.pdfinfogdgmi
 
Progress Report: Ministry of IT under Dr. Umar Saif Aug 23-Feb'24
Progress Report: Ministry of IT under Dr. Umar Saif Aug 23-Feb'24Progress Report: Ministry of IT under Dr. Umar Saif Aug 23-Feb'24
Progress Report: Ministry of IT under Dr. Umar Saif Aug 23-Feb'24Umar Saif
 
The Future of Product, by Founder & CEO, Product School
The Future of Product, by Founder & CEO, Product SchoolThe Future of Product, by Founder & CEO, Product School
The Future of Product, by Founder & CEO, Product SchoolProduct School
 
Synergy in Leadership and Product Excellence: A Blueprint for Growth by CPO, ...
Synergy in Leadership and Product Excellence: A Blueprint for Growth by CPO, ...Synergy in Leadership and Product Excellence: A Blueprint for Growth by CPO, ...
Synergy in Leadership and Product Excellence: A Blueprint for Growth by CPO, ...Product School
 
Dynamical systems simulation in Python for science and engineering
Dynamical systems simulation in Python for science and engineeringDynamical systems simulation in Python for science and engineering
Dynamical systems simulation in Python for science and engineeringMassimo Talia
 
Revolutionizing The Banking Industry: The Monzo Way by CPO, Monzo
Revolutionizing The Banking Industry: The Monzo Way by CPO, MonzoRevolutionizing The Banking Industry: The Monzo Way by CPO, Monzo
Revolutionizing The Banking Industry: The Monzo Way by CPO, MonzoProduct School
 
Relationship Counselling: From Disjointed Features to Product-First Thinking ...
Relationship Counselling: From Disjointed Features to Product-First Thinking ...Relationship Counselling: From Disjointed Features to Product-First Thinking ...
Relationship Counselling: From Disjointed Features to Product-First Thinking ...Product School
 
Artificial Intelligence, Design, and More-than-Human Justice
Artificial Intelligence, Design, and More-than-Human JusticeArtificial Intelligence, Design, and More-than-Human Justice
Artificial Intelligence, Design, and More-than-Human JusticeJosh Gellers
 
Introducing the New FME Community Webinar - Feb 21, 2024 (2).pdf
Introducing the New FME Community Webinar - Feb 21, 2024 (2).pdfIntroducing the New FME Community Webinar - Feb 21, 2024 (2).pdf
Introducing the New FME Community Webinar - Feb 21, 2024 (2).pdfSafe Software
 
Leveraging SLF4j for Effective Logging in IBM App Connect Enterprise.docx
Leveraging SLF4j for Effective Logging in IBM App Connect Enterprise.docxLeveraging SLF4j for Effective Logging in IBM App Connect Enterprise.docx
Leveraging SLF4j for Effective Logging in IBM App Connect Enterprise.docxVotarikari Shravan
 
Harnessing the Power of GenAI for Exceptional Product Outcomes by Booking.com...
Harnessing the Power of GenAI for Exceptional Product Outcomes by Booking.com...Harnessing the Power of GenAI for Exceptional Product Outcomes by Booking.com...
Harnessing the Power of GenAI for Exceptional Product Outcomes by Booking.com...Product School
 
"Platform Engineering with Development Containers", Igor Fesenko
"Platform Engineering with Development Containers", Igor Fesenko"Platform Engineering with Development Containers", Igor Fesenko
"Platform Engineering with Development Containers", Igor FesenkoFwdays
 
Roundtable_-_API_Research__Testing_Tools.pdf
Roundtable_-_API_Research__Testing_Tools.pdfRoundtable_-_API_Research__Testing_Tools.pdf
Roundtable_-_API_Research__Testing_Tools.pdfMostafa Higazy
 
Are Human-generated Demonstrations Necessary for In-context Learning?
Are Human-generated Demonstrations Necessary for In-context Learning?Are Human-generated Demonstrations Necessary for In-context Learning?
Are Human-generated Demonstrations Necessary for In-context Learning?MENGSAYLOEM1
 
Building Bridges: Merging RPA Processes, UiPath Apps, and Data Service to bu...
Building Bridges:  Merging RPA Processes, UiPath Apps, and Data Service to bu...Building Bridges:  Merging RPA Processes, UiPath Apps, and Data Service to bu...
Building Bridges: Merging RPA Processes, UiPath Apps, and Data Service to bu...DianaGray10
 
Leonis Insights: The State of AI (7 trends for 2023 and 7 predictions for 2024)
Leonis Insights: The State of AI (7 trends for 2023 and 7 predictions for 2024)Leonis Insights: The State of AI (7 trends for 2023 and 7 predictions for 2024)
Leonis Insights: The State of AI (7 trends for 2023 and 7 predictions for 2024)Jay Zhao
 

Recently uploaded (20)

"Testing of Helm Charts or There and Back Again", Yura Rochniak
"Testing of Helm Charts or There and Back Again", Yura Rochniak"Testing of Helm Charts or There and Back Again", Yura Rochniak
"Testing of Helm Charts or There and Back Again", Yura Rochniak
 
How to write an effective Cyber Incident Response Plan
How to write an effective Cyber Incident Response PlanHow to write an effective Cyber Incident Response Plan
How to write an effective Cyber Incident Response Plan
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applications
 
Pragmatic UI testing with Compose Semantics.pdf
Pragmatic UI testing with Compose Semantics.pdfPragmatic UI testing with Compose Semantics.pdf
Pragmatic UI testing with Compose Semantics.pdf
 
Progress Report: Ministry of IT under Dr. Umar Saif Aug 23-Feb'24
Progress Report: Ministry of IT under Dr. Umar Saif Aug 23-Feb'24Progress Report: Ministry of IT under Dr. Umar Saif Aug 23-Feb'24
Progress Report: Ministry of IT under Dr. Umar Saif Aug 23-Feb'24
 
The Future of Product, by Founder & CEO, Product School
The Future of Product, by Founder & CEO, Product SchoolThe Future of Product, by Founder & CEO, Product School
The Future of Product, by Founder & CEO, Product School
 
Synergy in Leadership and Product Excellence: A Blueprint for Growth by CPO, ...
Synergy in Leadership and Product Excellence: A Blueprint for Growth by CPO, ...Synergy in Leadership and Product Excellence: A Blueprint for Growth by CPO, ...
Synergy in Leadership and Product Excellence: A Blueprint for Growth by CPO, ...
 
Dynamical systems simulation in Python for science and engineering
Dynamical systems simulation in Python for science and engineeringDynamical systems simulation in Python for science and engineering
Dynamical systems simulation in Python for science and engineering
 
Revolutionizing The Banking Industry: The Monzo Way by CPO, Monzo
Revolutionizing The Banking Industry: The Monzo Way by CPO, MonzoRevolutionizing The Banking Industry: The Monzo Way by CPO, Monzo
Revolutionizing The Banking Industry: The Monzo Way by CPO, Monzo
 
Relationship Counselling: From Disjointed Features to Product-First Thinking ...
Relationship Counselling: From Disjointed Features to Product-First Thinking ...Relationship Counselling: From Disjointed Features to Product-First Thinking ...
Relationship Counselling: From Disjointed Features to Product-First Thinking ...
 
In sharing we trust. Taking advantage of a diverse consortium to build a tran...
In sharing we trust. Taking advantage of a diverse consortium to build a tran...In sharing we trust. Taking advantage of a diverse consortium to build a tran...
In sharing we trust. Taking advantage of a diverse consortium to build a tran...
 
Artificial Intelligence, Design, and More-than-Human Justice
Artificial Intelligence, Design, and More-than-Human JusticeArtificial Intelligence, Design, and More-than-Human Justice
Artificial Intelligence, Design, and More-than-Human Justice
 
Introducing the New FME Community Webinar - Feb 21, 2024 (2).pdf
Introducing the New FME Community Webinar - Feb 21, 2024 (2).pdfIntroducing the New FME Community Webinar - Feb 21, 2024 (2).pdf
Introducing the New FME Community Webinar - Feb 21, 2024 (2).pdf
 
Leveraging SLF4j for Effective Logging in IBM App Connect Enterprise.docx
Leveraging SLF4j for Effective Logging in IBM App Connect Enterprise.docxLeveraging SLF4j for Effective Logging in IBM App Connect Enterprise.docx
Leveraging SLF4j for Effective Logging in IBM App Connect Enterprise.docx
 
Harnessing the Power of GenAI for Exceptional Product Outcomes by Booking.com...
Harnessing the Power of GenAI for Exceptional Product Outcomes by Booking.com...Harnessing the Power of GenAI for Exceptional Product Outcomes by Booking.com...
Harnessing the Power of GenAI for Exceptional Product Outcomes by Booking.com...
 
"Platform Engineering with Development Containers", Igor Fesenko
"Platform Engineering with Development Containers", Igor Fesenko"Platform Engineering with Development Containers", Igor Fesenko
"Platform Engineering with Development Containers", Igor Fesenko
 
Roundtable_-_API_Research__Testing_Tools.pdf
Roundtable_-_API_Research__Testing_Tools.pdfRoundtable_-_API_Research__Testing_Tools.pdf
Roundtable_-_API_Research__Testing_Tools.pdf
 
Are Human-generated Demonstrations Necessary for In-context Learning?
Are Human-generated Demonstrations Necessary for In-context Learning?Are Human-generated Demonstrations Necessary for In-context Learning?
Are Human-generated Demonstrations Necessary for In-context Learning?
 
Building Bridges: Merging RPA Processes, UiPath Apps, and Data Service to bu...
Building Bridges:  Merging RPA Processes, UiPath Apps, and Data Service to bu...Building Bridges:  Merging RPA Processes, UiPath Apps, and Data Service to bu...
Building Bridges: Merging RPA Processes, UiPath Apps, and Data Service to bu...
 
Leonis Insights: The State of AI (7 trends for 2023 and 7 predictions for 2024)
Leonis Insights: The State of AI (7 trends for 2023 and 7 predictions for 2024)Leonis Insights: The State of AI (7 trends for 2023 and 7 predictions for 2024)
Leonis Insights: The State of AI (7 trends for 2023 and 7 predictions for 2024)
 

Code Quality Analysis

  • 1. Code Quality Analysis Marty Andrews @martinjandrews .com.au
  • 4. static analysis = software analysis without execution
  • 5. no app runtime required!
  • 9. Whole Team Collective Coding Ownership Standard Test-Driven Development Customer Pair Design Planning Tests Programming Improvement Game Simple Design Continuous Sustainable Integration Pace Metaphor Small Releases circa 2001. duplicated from xprogramming.com
  • 10. Collective Coding Ownership Standard Test-Driven Development Pair Design Programming Improvement Simple Design Continuous Sustainable Integration Pace circa 2001. duplicated from xprogramming.com
  • 12. smell the code
  • 13. “A code smell is a surface indication that usually corresponds to a deeper problem in the system.” -- Martin Fowler, paraphrasing Kent Beck
  • 14. “If it stinks, change it.” -- Grandma Beck
  • 15. Tools
  • 16. code samples from runwayapp.com
  • 18. Summary statistics from your Rails app
  • 19. Look for a good code to test ratio
  • 20. $ sudo gem install rails $ rails my_app $ cd my_app $ rake stats
  • 21. ~/Data/runway $ rake stats (in /Users/marty/Data/runway) +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 333 | 275 | 12 | 45 | 3| 4| | Helpers | 113 | 104 | 0| 10 | 0| 8| | Models | 828 | 681 | 12 | 96 | 8| 5| | Libraries | 874 | 750 | 24 | 113 | 4| 4| | Model specs | 1662 | 1395 | 0| 0| 0| 0| | Controller specs | 544 | 434 | 0| 5| 0| 84 | | Helper specs | 114 | 95 | 0| 0| 0| 0| +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 4468 | 3734 | 48 | 269 | 5| 11 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 1810 Test LOC: 1924 Code to Test Ratio: 1:1.1
  • 22. 681 | 12 | 96 | 8| 5 750 | 24 | 113 | 4| 4 1395 | 0| 0| 0| 0 434 | 0| 5| 0| 84 95 | 0| 0| 0| 0 -----+---------+---------+-----+------- 3734 | 48 | 269 | 5| 11 -----+---------+---------+-----+------- 4 Code to Test Ratio: 1:1.1
  • 23. use rake stats for regular human review
  • 26. Control Couple Long Parameter List Duplication Nested Iterators Feature Envy Uncommunicative Name Large Class Utility Function Long Method
  • 27. Look for warnings that you haven’t thought about
  • 28. $ sudo gem install reek $ reek [file ...]
  • 29. ~/Data/runway $ find app -name quot;*.rbquot; | xargs reek quot;app/controllers/actions_controller.rbquot; -- 3 warnings: ActionsController#action calls current_user.actions multiple times (Duplication) ActionsController#action calls params[id] multiple times (Duplication) ActionsController#actions calls current_user.actions multiple times (Duplication) quot;app/controllers/application.rbquot; -- 1 warnings: ApplicationController#site_version doesn't depend on instance state (Utility Function) quot;app/helpers/home_helper.rbquot; -- 1 warnings: HomeHelper::folder_tab has approx 6 statements (Long Method) quot;app/models/token.rbquot; -- 21 warnings: Token#parse_incubation_day_of_the_month refers to base more than self (Feature Envy)
  • 30. ActionsController#action calls current_user.actions multiple times (Duplication) ActionsController#action calls params[id] multiple times (Duplication) ActionsController#actions calls current_user.actions multiple times (Duplication) quot;app/controllers/application.rbquot; -- 1 warnings: ApplicationController#site_version doesn't depend on instance state (Utility Function) quot;app/helpers/home_helper.rbquot; -- 1 warnings: HomeHelper::folder_tab has approx 6 statements (Long Method) quot;app/models/token.rbquot; -- 21 warnings: Token#parse_incubation_day_of_the_month refers to base more than self (Feature Envy)
  • 31. [Feature Envy] Element#update_from refers to response more than self def parse_incubation_day_of_the_month if @remainder =~ /^(d+)(th|st|nd|rd)$/i day = $1.to_i base = day <= @today.day ? @today >> 1 : @today day -=1 until Date.valid_civil?(base.year, base.month, day) Date.new(base.year, base.month, day) end end
  • 34. use reek for regular human review
  • 37. “ABC” like algorithm Assignments Branches Conditionals
  • 38. Look for high scores (> 40)
  • 39. $ sudo gem install flog $ flog [dir ...]
  • 40. ~/Data/runway $ flog app 1426.9: flog total 7.9: flog/method average 89.7: ActionFormat#format 81.7: ActionParser#parse 60.4: Token#parse_incubation_date 42.3: Token#parse_incubation_days 35.2: Token#tokenize 29.8: Token#parse 27.8: Token#parse_period 27.6: Action#apply_defaults_from_name 25.3: Action#none 24.9: RankingsController#update 24.2: ActionsHelper#none 22.9: ActionsHelper#action_contexts 21.9: ActionsHelper#action_tags 20.9: Token#parse_incubation_month 20.2: ActionParser#attributes [More content removed...]
  • 41. ~/Data/runway $ flog app 1426.9: flog total 7.9: flog/method average 89.7: ActionFormat#format 81.7: ActionParser#parse 60.4: Token#parse_incubation_date 42.3: Token#parse_incubation_days 35.2: Token#tokenize 29.8: Token#parse 27.8: Token#parse_period
  • 42. 89.7: ActionFormat#format def format @tokens = [] @semi = false append(quot;Waiting forquot;) if @action.waiting? append(@action.name) unless @action.name.blank? append_with_semi(@action.due_at.strftime(quot;<%d/%m/%Y-%H:%Mquot;)) if @action.solid? if @action.incubating? append_with_semi(@action.effective_at.strftime(quot;+%d/%m/%Y-%H:%Mquot;)) elsif [quot;laterquot;, quot;donequot;].include?(@action.status) append_with_semi(quot;+#{@action.status}quot;) end append_with_semi(@action.contexts.sort.map(&:shorthand)) unless @action.contexts.blank? unless @action.waiting? append_with_semi(@action.time.shorthand) unless @action.time.blank? append_with_semi(@action.energy.shorthand) unless @action.energy.blank? end append_with_semi(@action.tags.sort.map(&:shorthand)) unless @action.tags.blank? append(quot;!quot;) if @action.today? @tokens.flatten.join(quot; quot;) end
  • 44. ~/Data/rails $ flog . 201079.7: flog total 14.1: flog/method average 3841.5: main#none 866.1: Parser#none 709.7: timezone#Europe/London 707.5: timezone#America/St_Johns 695.0: timezone#America/Chicago 693.3: timezone#America/New_York 674.3: timezone#Europe/Dublin 670.9: timezone#America/Halifax 662.2: JoinAssociation#association_join 661.2: timezone#Atlantic/Azores 656.7: timezone#Europe/Lisbon 556.3: timezone#Europe/Brussels [More content removed...]
  • 45. 841.5: main#none 866.1: Parser#none 709.7: timezone#Europe/London 707.5: timezone#America/St_Johns 695.0: timezone#America/Chicago 693.3: timezone#America/New_York 674.3: timezone#Europe/Dublin 670.9: timezone#America/Halifax 662.2: JoinAssociation#association_join 661.2: timezone#Atlantic/Azores 656.7: timezone#Europe/Lisbon 556.3: timezone#Europe/Brussels [More content removed...]
  • 46. def association_join connection = reflection.active_record.connection join = case reflection.macro when :has_and_belongs_to_many quot; #{join_type} %s ON %s.%s = %s.%s quot; % [ table_alias_for(options[:join_table], aliased_join_table_name), connection.quote_table_name(aliased_join_table_name), options[:foreign_key] || reflection.active_record.to_s.foreign_key, connection.quote_table_name(parent.aliased_table_name), reflection.active_record.primary_key] + quot; #{join_type} %s ON %s.%s = %s.%s quot; % [ table_name_and_alias, connection.quote_table_name(aliased_table_name), klass.primary_key, connection.quote_table_name(aliased_join_table_name), options[:association_foreign_key] || klass.to_s.foreign_key ] when :has_many, :has_one case when reflection.options[:through] through_conditions = through_reflection.options[:conditions] ? quot;AND #{interpolate_s jt_foreign_key = jt_as_extra = jt_source_extra = jt_sti_extra = nil first_key = second_key = as_extra = nil if through_reflection.options[:as] # has_many :through against a polymorphic join jt_foreign_key = through_reflection.options[:as].to_s + '_id' jt_as_extra = quot; AND %s.%s = %squot; % [ connection.quote_table_name(aliased_join_table_name), connection.quote_column_name(through_reflection.options[:as].to_s + '_type'), klass.quote_value(parent.active_record.base_class.name) ] else jt_foreign_key = through_reflection.primary_key_name
  • 47. ] else jt_foreign_key = through_reflection.primary_key_name end case source_reflection.macro when :has_many if source_reflection.options[:as] first_key = quot;#{source_reflection.options[:as]}_idquot; second_key = options[:foreign_key] || primary_key as_extra = quot; AND %s.%s = %squot; % [ connection.quote_table_name(aliased_table_name), connection.quote_column_name(quot;#{source_reflection.options[:as]}_typequot;), klass.quote_value(source_reflection.active_record.base_class.name) ] else first_key = through_reflection.klass.base_class.to_s.foreign_key second_key = options[:foreign_key] || primary_key end unless through_reflection.klass.descends_from_active_record? jt_sti_extra = quot; AND %s.%s = %squot; % [ connection.quote_table_name(aliased_join_table_name), connection.quote_column_name(through_reflection.active_record.inheritance_col through_reflection.klass.quote_value(through_reflection.klass.sti_name)] end when :belongs_to first_key = primary_key if reflection.options[:source_type] second_key = source_reflection.association_foreign_key jt_source_extra = quot; AND %s.%s = %squot; % [ connection.quote_table_name(aliased_join_table_name), connection.quote_column_name(reflection.source_reflection.options[:foreign_ty klass.quote_value(reflection.options[:source_type]) ]
  • 48. connection.quote_column_name(reflection.source_reflection.options[:foreign_ty klass.quote_value(reflection.options[:source_type]) ] else second_key = source_reflection.primary_key_name end end quot; #{join_type} %s ON (%s.%s = %s.%s%s%s%s) quot; % [ table_alias_for(through_reflection.klass.table_name, aliased_join_table_name), connection.quote_table_name(parent.aliased_table_name), connection.quote_column_name(parent.primary_key), connection.quote_table_name(aliased_join_table_name), connection.quote_column_name(jt_foreign_key), jt_as_extra, jt_source_extra, jt_sti_extra ]+ quot; #{join_type} %s ON (%s.%s = %s.%s%s) quot; % [ table_name_and_alias, connection.quote_table_name(aliased_table_name), connection.quote_column_name(first_key), connection.quote_table_name(aliased_join_table_name), connection.quote_column_name(second_key), as_extra ] when reflection.options[:as] && [:has_many, :has_one].include?(reflection.macro) quot; #{join_type} %s ON %s.%s = %s.%s AND %s.%s = %squot; % [ table_name_and_alias, connection.quote_table_name(aliased_table_name), quot;#{reflection.options[:as]}_idquot;, connection.quote_table_name(parent.aliased_table_name), parent.primary_key, connection.quote_table_name(aliased_table_name), quot;#{reflection.options[:as]}_typequot;, klass.quote_value(parent.active_record.base_class.name)
  • 49. connection.quote_table_name(aliased_table_name), quot;#{reflection.options[:as]}_typequot;, klass.quote_value(parent.active_record.base_class.name) ] else foreign_key = options[:foreign_key] || reflection.active_record.name.foreign_key quot; #{join_type} %s ON %s.%s = %s.%s quot; % [ table_name_and_alias, aliased_table_name, foreign_key, parent.aliased_table_name, reflection.options[:primary_key] || parent.primary_key ] end when :belongs_to quot; #{join_type} %s ON %s.%s = %s.%s quot; % [ table_name_and_alias, connection.quote_table_name(aliased_table_name), reflection.klass.primary_key, connection.quote_table_name(parent.aliased_table_name), options[:foreign_key] || reflection.primary_key_name ] else quot;quot; end || '' join << %(AND %s) % [ klass.send(:type_condition, aliased_table_name)] unless klass.descends_from_active_record [through_reflection, reflection].each do |ref| join << quot;AND #{interpolate_sql(sanitize_sql(ref.options[:conditions], aliased_table_name) end join end
  • 51. lib/tasks/quality.rake require 'flog' desc quot;Analyze for code complexityquot; task :flog do flog = Flog.new flog.flog_files ['app'] threshold = 30 bad_methods = flog.totals.select do |name, score| score > threshold end bad_methods.sort { |a,b| a[1] <=> b[1] }.each do |name, score| puts quot;%8.1f: %squot; % [score, name] end raise quot;#{bad_methods.size} methods have a flog complexity > #{threshold}quot; unless bad_methods.empty? end
  • 52. ~/Data/runway $ rake flog (in /Users/marty/Data/runway) 35.2: Token#tokenize 42.3: Token#parse_incubation_days 60.4: Token#parse_incubation_date 81.7: ActionParser#parse 89.7: ActionFormat#format rake aborted! 5 methods have a flog complexity > 30
  • 53. use flog in your CI build
  • 55. Structural similarity checking of Sexp nodes (syntax tokens)
  • 57. Look for high scores (> 30)
  • 58. $ sudo gem install flay $ flay [dir ...]
  • 59. ~/Data/runway $ flay app [Processing files...] Total score (lower is better) = 286 1) Similar code found in :defn (mass = 60) app/controllers/signups_controller.rb:5 app/controllers/user_sessions_controller.rb:6 2) Similar code found in :if (mass = 54) app/controllers/forgot_passwords_controller.rb:15 app/controllers/signups_controller.rb:16 3) Similar code found in :defn (mass = 50) app/helpers/actions_helper.rb:43 app/helpers/actions_helper.rb:49 [More content removed...]
  • 60. ~/Data/runway $ flay app [Processing files...] Total score (lower is better) = 286 1) Similar code found in :defn (mass = 60) app/controllers/signups_controller.rb:5 app/controllers/user_sessions_controller.rb:6 2) Similar code found in :if (mass = 54) app/controllers/forgot_passwords_controller.rb:15 app/controllers/signups_controller.rb:16 3) Similar code found in :defn (mass = 50) app/helpers/actions_helper.rb:43 app/helpers/actions_helper.rb:49 [More content removed...]
  • 61. 1) Similar code found in :defn (mass = 60) app/controllers/signups_controller.rb:5 app/controllers/user_sessions_controller.rb:6 def create user = User.new(params[:signup]) if user.save head(:status => :created, :location => home_path) else head(:status => :unprocessable_entity) end end def create user_session = UserSession.new(params[:user_session]) if user_session.save head(:status => :created, :location => home_path) else head(:status => :unprocessable_entity) end end
  • 64. actionmailer/install.rb require 'rbconfig' require 'find' require 'ftools' include Config # this was adapted from rdoc's install.rb by way of Log4r $sitedir = CONFIG[quot;sitelibdirquot;] unless $sitedir version = CONFIG[quot;MAJORquot;] + quot;.quot; + CONFIG[quot;MINORquot;] $libdir = File.join(CONFIG[quot;libdirquot;], quot;rubyquot;, version) $sitedir = $:.find {|x| x =~ /site_ruby/ } if !$sitedir $sitedir = File.join($libdir, quot;site_rubyquot;) elsif $sitedir !~ Regexp.quote(version) $sitedir = File.join($sitedir, version) end end # the actual gruntwork Dir.chdir(quot;libquot;) Find.find(quot;action_mailerquot;, quot;action_mailer.rbquot;) { |f| if f[-3..-1] == quot;.rbquot; File::install(f, File.join($sitedir, *f.split(///)), 0644, true) else File::makedirs(File.join($sitedir, *f.split(///))) end }
  • 65. activesupport/install.rb require 'rbconfig' require 'find' require 'ftools' include Config # this was adapted from rdoc's install.rb by ways of Log4r $sitedir = CONFIG[quot;sitelibdirquot;] unless $sitedir version = CONFIG[quot;MAJORquot;] + quot;.quot; + CONFIG[quot;MINORquot;] $libdir = File.join(CONFIG[quot;libdirquot;], quot;rubyquot;, version) $sitedir = $:.find {|x| x =~ /site_ruby/ } if !$sitedir $sitedir = File.join($libdir, quot;site_rubyquot;) elsif $sitedir !~ Regexp.quote(version) $sitedir = File.join($sitedir, version) end end # the actual gruntwork Dir.chdir(quot;libquot;) Find.find(quot;active_supportquot;, quot;active_support.rbquot;) { |f| if f[-3..-1] == quot;.rbquot; File::install(f, File.join($sitedir, *f.split(///)), 0644, true) else File::makedirs(File.join($sitedir, *f.split(///))) end }
  • 66. activerecord/install.rb require 'rbconfig' require 'find' require 'ftools' include Config # this was adapted from rdoc's install.rb by ways of Log4r $sitedir = CONFIG[quot;sitelibdirquot;] unless $sitedir version = CONFIG[quot;MAJORquot;] + quot;.quot; + CONFIG[quot;MINORquot;] $libdir = File.join(CONFIG[quot;libdirquot;], quot;rubyquot;, version) $sitedir = $:.find {|x| x =~ /site_ruby/ } if !$sitedir $sitedir = File.join($libdir, quot;site_rubyquot;) elsif $sitedir !~ Regexp.quote(version) $sitedir = File.join($sitedir, version) end end # the actual gruntwork Dir.chdir(quot;libquot;) Find.find(quot;active_recordquot;, quot;active_record.rbquot;) { |f| if f[-3..-1] == quot;.rbquot; File::install(f, File.join($sitedir, *f.split(///)), 0644, true) else File::makedirs(File.join($sitedir, *f.split(///))) end }
  • 67. actionpack/install.rb require 'rbconfig' require 'find' require 'ftools' include Config # this was adapted from rdoc's install.rb by way of Log4r $sitedir = CONFIG[quot;sitelibdirquot;] unless $sitedir version = CONFIG[quot;MAJORquot;] + quot;.quot; + CONFIG[quot;MINORquot;] $libdir = File.join(CONFIG[quot;libdirquot;], quot;rubyquot;, version) $sitedir = $:.find {|x| x =~ /site_ruby/ } if !$sitedir $sitedir = File.join($libdir, quot;site_rubyquot;) elsif $sitedir !~ Regexp.quote(version) $sitedir = File.join($sitedir, version) end end # the actual gruntwork Dir.chdir(quot;libquot;) Find.find(quot;action_controllerquot;, quot;action_controller.rbquot;, quot;action_viewquot;, quot;action_view.rbquot;) { |f| if f[-3..-1] == quot;.rbquot; File::install(f, File.join($sitedir, *f.split(///)), 0644, true) else File::makedirs(File.join($sitedir, *f.split(///))) end }
  • 69. lib/tasks/quality.rake require 'flay' desc quot;Analyze for code duplicationquot; task :flay do threshold = 25 flay = Flay.new({:fuzzy => false, :verbose => false, :mass => threshold}) flay.process(*Flay.expand_dirs_to_files(['app'])) flay.report raise quot;#{flay.masses.size} chunks of code have a duplicate mass > #{threshold}quot; unless flay.masses.empty? end
  • 70. ~/Data/runway $ rake flay (in /Users/marty/Data/runway) Total score (lower is better) = 164 1) Similar code found in :defn (mass = 60) app/controllers/signups_controller.rb:5 app/controllers/user_sessions_controller.rb:6 2) Similar code found in :if (mass = 54) app/controllers/forgot_passwords_controller.rb:15 app/controllers/signups_controller.rb:16 3) Similar code found in :defn (mass = 50) app/helpers/actions_helper.rb:43 app/helpers/actions_helper.rb:49 rake aborted! 3 chunks of code have a duplicate mass > 25
  • 71. use flay in your CI build
  • 73. Checks for design problems
  • 74. Class Name Block Cyclomatic Complexity Method Name Method Cyclomatic Complexity Module Name Assignment In Conditional Class Line Count Case Missing Else Method Line Count Empty Rescue Body Module Line Count For Loop Check Parameter Number
  • 75. Look for any errors
  • 76. $ sudo gem install roodi $ roodi [pattern ...]
  • 77. ~/Data/runway $ roodi quot;app/**/*.rbquot; app/models/action_format.rb:10 Method name quot;formatquot; has a cyclomatic complexity is 12. It should be 8 or less. app/models/action_parser.rb:50 Block cyclomatic complexity is 11. It should be 4 or less. app/models/action.rb:107 Case statement is missing an else clause. app/models/action.rb:103 Method quot;apply_defaults_from_namequot; has 23 lines. It should have 20 or less. app/controllers/application.rb:52 Found = in conditional. It should probably be an ==
  • 78. Method name quot;formatquot; has a cyclomatic complexit It should be 8 or less. app/models/action_parser.rb:50 Block cyclomatic complexity is 11. It should be 4 or less. app/models/action.rb:107 Case statement is missing an else clause. app/models/action.rb:103 Method quot;apply_defaults_from_namequot; has 23 lines. It should have 20 or less. app/controllers/application.rb:52 Found = in conditional. It should probably be an ==
  • 79. app/models/action_parser.rb:50 Block cyclomatic complexity is 11. It should be 4 or less. meta.each do |token| case token.klass when :context unless token.value.blank? @contexts ||= [] @contexts << token.value end when :time @time = token.value when :energy @energy = token.value when :tag @tags << token.value unless token.value.blank? when :semi_colon # Ignore when :available, :today, :later, :done @status = token.klass.to_s @effective_at = token.value when :due_at @due_at = token.value end end
  • 80. app/models/action_parser.rb:50 Block cyclomatic complexity is 11. It should be 4 or less. 1 meta.each do |token| case token.klass 2 when :context 3 unless token.value.blank? @contexts ||= [] 4 @contexts << token.value end 5 when :time @time = token.value 6 when :energy @energy = token.value 7 8 when :tag @tags << token.value unless token.value.blank? 9 when :semi_colon # Ignore 10 when :available, :today, :later, :done @status = token.klass.to_s @effective_at = token.value 11 when :due_at @due_at = token.value end end
  • 81. app/controllers/application.rb:52 Found = in conditional. It should probably be an == def extract_authenticity_token if token = request.headers[quot;HTTP_X_RUNWAY_AUTHENTICITY_TOKENquot;] params[request_forgery_protection_token] = token end end
  • 84. ./actionpack/lib/action_controller/vendor/html- scanner/html/node.rb:417 Method name quot;matchquot; cyclomatic complexity is 47. It should be 8 or less.
  • 85. def match(conditions) conditions = validate_conditions(conditions) # check content of child nodes if conditions[:content] if children.empty? return false unless match_condition(quot;quot;, conditions[:content]) else return false unless children.find { |child| child.match(conditions[:content]) } end end # test the name return false unless match_condition(@name, conditions[:tag]) if conditions[:tag] # test attributes (conditions[:attributes] || {}).each do |key, value| return false unless match_condition(self[key], value) end # test parent return false unless parent.match(conditions[:parent]) if conditions[:parent] # test children return false unless children.find { |child| child.match(conditions[:child]) } if conditio # test ancestors if conditions[:ancestor] return false unless catch :found do p = self throw :found, true if p.match(conditions[:ancestor]) while p = p.parent end end # test descendants
  • 86. # test descendants if conditions[:descendant] return false unless children.find do |child| # test the child child.match(conditions[:descendant]) || # test the child's descendants child.match(:descendant => conditions[:descendant]) end end # count children if opts = conditions[:children] matches = children.select do |c| (c.kind_of?(HTML::Tag) and (c.closing == :self or ! c.childless?)) end matches = matches.select { |c| c.match(opts[:only]) } if opts[:only] opts.each do |key, value| next if key == :only case key when :count if Integer === value return false if matches.length != value else return false unless value.include?(matches.length) end when :less_than return false unless matches.length < value when :greater_than return false unless matches.length > value else raise quot;unknown count condition #{key}quot; end end end
  • 87. else raise quot;unknown count condition #{key}quot; end end end # test siblings if conditions[:sibling] || conditions[:before] || conditions[:after] siblings = parent ? parent.children : [] self_index = siblings.index(self) if conditions[:sibling] return false unless siblings.detect do |s| s != self && s.match(conditions[:sibling]) end end if conditions[:before] return false unless siblings[self_index+1..-1].detect do |s| s != self && s.match(conditions[:before]) end end if conditions[:after] return false unless siblings[0,self_index].detect do |s| s != self && s.match(conditions[:after]) end end end true end
  • 89. lib/tasks/quality.rake require 'roodi' require 'roodi_task' RoodiTask.new 'roodi', ['app/**/*.rb', 'lib/**/*.rb'], 'roodi.yml'
  • 90. roodi.yml # AssignmentInConditionalCheck: {} # CaseMissingElseCheck: {} ClassLineCountCheck: { line_count: 300 } ClassNameCheck: { pattern: !ruby/regexp /^[A-Z][a-zA-Z # ClassVariableCheck: {} CyclomaticComplexityBlockCheck: { complexity: 8 } CyclomaticComplexityMethodCheck: { complexity: 10 } EmptyRescueBodyCheck: { } ForLoopCheck: { } MethodLineCountCheck: { line_count: 20 } MethodNameCheck: { pattern: !ruby/regexp /^[_a-z<>=[|+ ModuleLineCountCheck: { line_count: 300 } ModuleNameCheck: { pattern: !ruby/regexp /^[A-Z][a-zA-Z ParameterNumberCheck: { parameter_count: 5 }
  • 91. ~/Data/runway $ rake roodi (in /Users/marty/Data/runway) app/models/action_format.rb:10 - Method name quot;formatquot; cyclomatic complexity is 12. It should be 10 or less. app/models/action_parser.rb:11 - Method name quot;attributesquot; cyclomatic complexity is 12. It should be 10 or less. app/models/action_parser.rb:30 - Method name quot;parsequot; cyclomatic complexity is 14. It should be 10 or less. app/models/token.rb:173 - Method name quot;parse_incubation_datequot; cyclomatic complexity is 11. It should be 10 or less. app/models/token.rb:226 - Method name quot;parse_incubation_daysquot; cyclomatic complexity is 12. It should be 10 or less. app/models/action_parser.rb:50 - Block cyclomatic complexity is 11. It should be 8 or less. app/models/token.rb:11 - Block cyclomatic complexity is 10. It should be 8 or less. app/models/action.rb:103 - Method quot;apply_defaults_from_namequot; has 23 lines. It should have 20 or less. app/models/action_parser.rb:30 - Method quot;parsequot; has 23 lines. It should have 20 or less. rake aborted! Found 9 errors.
  • 92. use roodi in your CI build
  • 94. reports on everything you’ve seen today plus more!
  • 95. $ sudo gem sources -a http://gems.github.com $ sudo gem install jscruggs-metric_fu
  • 103. use metrics_fu for regular human review
  • 105. lib/tasks/quality.rake (part 1) require 'flog' desc quot;Analyze for code complexityquot; task :flog do flog = Flog.new flog.flog_files ['app'] threshold = 40 bad_methods = flog.totals.select do |name, score| score > threshold end bad_methods.sort { |a,b| a[1] <=> b[1] }.each do |name, score| puts quot;%8.1f: %squot; % [score, name] end raise quot;#{bad_methods.size} methods have a flog complexity > #{threshold}quot; unless bad_methods.empty? end
  • 106. lib/tasks/quality.rake (part 2) require 'flay' desc quot;Analyze for code duplicationquot; task :flay do threshold = 25 flay = Flay.new({:fuzzy => false, :verbose => false, :mass => threshold}) flay.process(*Flay.expand_dirs_to_files(['app'])) flay.report raise quot;#{flay.masses.size} chunks of code have a duplicate mass > #{threshold}quot; unless flay.masses.empty? end
  • 107. lib/tasks/quality.rake (part 3) require 'roodi' require 'roodi_task' require 'metric_fu' RoodiTask.new 'roodi', ['app/**/*.rb', 'lib/**/*.rb'], 'roodi.yml' task :quality => [:flog, :flay, :roodi, 'metrics:all']
  • 108. continuous integration flog flay roodi regular human review metric_fu rake stats reek and more
  • 109. Resources me @martinjandrews marty@cogentconsulting.com.au code samples from runwayapp.com reek wiki.github.com/kevinrutherford/reek flog ruby.sadi.st/Flog.html flay ruby.sadi.st/Flay.html roodi roodi.rubyforge.org metric_fu metric-fu.rubyforge.org

Editor's Notes