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

Does your configuration code smell?

Does your configuration code smell?

by Tushar Sharma
DevOps Pro Vilnius 2016

DevOps Pro

June 01, 2016
Tweet

More Decks by DevOps Pro

Other Decks in Technology

Transcript

  1. “Smells” Code Smell …certain structures in the code that suggest

    (sometimes they scream for) the possibility of refactoring.
  2. “Smells” Design Smells “Design smells are certain structures in the

    design that indicate violation of fundamental design principles and negatively impact design quality.”
  3. Puppet example package { 'apache2': require => Exec['apt-update'], ensure =>

    installed, } service { 'apache2': ensure => running, } user { 'tushar': ensure => present, uid => '1000', gid => '1000', shell => '/bin/bash', home => '/home/tushar' } Configuration management tools: Ansible, Chef, CFEngine, Puppet
  4. Software System IaC and Traditional SE Production code Infrastructure, configuration

    code, tools and services Apply traditional software engineering practices
  5. Configuration smells “Configuration smells are the characteristics of a configuration

    program or script that violate the recommended best practices and potentially affect the program’s quality in a negative way.”
  6. Implementation configuration smells import 'classes/*' # TODO: fix deprecated statement

    class app-studio (String $version = ‘latest') { $primary_config_file = 'config' $source_config = 'config.source' if $version == ’44’ or $version == ‘4.2’ or $version != ‘4.5’ or $version == ‘4.9’{ case $::operatingsystem { 'debian': { apt::source { 'packages.dotdeb.org-repo.app': location => 'http://repo.app.com/dotdeb/', release => $::lsbdistcodename, repos => 'all', include_src => true include_src => true } } Deprecated Statement Usage
  7. Implementation configuration smells import 'classes/*' # TODO: fix deprecated statement

    class app-studio (String $version = ‘latest') { $primary_config_file = 'config' $source_config = 'config.source' if $version == ’44’ or $version == ‘4.2’ or $version != ‘4.5’ or $version == ‘4.9’{ case $::operatingsystem { 'debian': { apt::source { 'packages.dotdeb.org-repo.app': location => 'http://repo.app.com/dotdeb/', release => $::lsbdistcodename, repos => 'all', include_src => true include_src => true } } Incomplete Task
  8. Implementation configuration smells import 'classes/*' # TODO: fix deprecated statement

    class app-studio (String $version = ‘latest') { $primary_config_file = 'config' $source_config = 'config.source' if $version == ’44’ or $version == ‘4.2’ or $version != ‘4.5’ or $version == ‘4.9’{ case $::operatingsystem { 'debian': { apt::source { 'packages.dotdeb.org-repo.app': location => 'http://repo.app.com/dotdeb/', release => $::lsbdistcodename, repos => 'all', include_src => true include_src => true } } Long Statement Complex Expression
  9. Implementation configuration smells import 'classes/*' # TODO: fix deprecated statement

    class app-studio (String $version = ‘latest') { $primary_config_file = 'config' $source_config = 'config.source' if $version == ’44’ or $version == ‘4.2’ or $version != ‘4.5’ or $version == ‘4.9’{ case $::operatingsystem { 'debian': { apt::source { 'packages.dotdeb.org-repo.app': location => 'http://repo.app.com/dotdeb/', release => $::lsbdistcodename, repos => 'all', include_src => true include_src => true } } Missing Default Case
  10. Implementation configuration smells import 'classes/*' # TODO: fix deprecated statement

    class app-studio (String $version = ‘latest') { $primary_config_file = 'config' $source_config = 'config.source' if $version == ’44’ or $version == ‘4.2’ or $version != ‘4.5’ or $version == ‘4.9’{ case $::operatingsystem { 'debian': { apt::source { 'packages.dotdeb.org-repo.app': location => 'http://repo.app.com/dotdeb/', release => $::lsbdistcodename, repos => 'all', include_src => true include_src => true } } Duplicate Entity
  11. Implementation configuration smells elsif $version in ['33', '3.3'] { }

    if $::kernelversion =~ /^(2.2)/ { $appversion = '3.5' } elsif $::kernelversion =~ /^(2.1)/ { exec {"download_app_studio": command => "wget $url", timeout => 0, } } $version = '3.4' ? {undef => $primary_config_file, default => $source_config} file { "/root/.app": mode => '644', ensure => present } } Missing Conditional
  12. Implementation configuration smells elsif $version in ['33', '3.3'] { }

    if $::kernelversion =~ /^(2.2)/ { $appversion = '3.5' } elsif $::kernelversion =~ /^(2.1)/ { exec {"download_app_studio": command => "wget $url", timeout => 0, } } $version = '3.4' ? {undef => $primary_config_file, default => $source_config} file { "/root/.app": mode => '644', ensure => present } } Improper Quote Usage
  13. Implementation configuration smells elsif $version in ['33', '3.3'] { }

    if $::kernelversion =~ /^(2.2)/ { $appversion = '3.5' } elsif $::kernelversion =~ /^(2.1)/ { exec {"download_app_studio": command => "wget $url", timeout => 0, } } $version = '3.4' ? {undef => $primary_config_file, default => $source_config} file { "/root/.app": mode => '644', ensure => present } } Unguarded Variable
  14. Implementation configuration smells elsif $version in ['33', '3.3'] { }

    if $::kernelversion =~ /^(2.2)/ { $appversion = '3.5' } elsif $::kernelversion =~ /^(2.1)/ { exec {"download_app_studio": command => "wget $url", timeout => 0, } } $version = '3.4' ? {undef => $primary_config_file, default => $source_config} file { "/root/.app": mode => '644', ensure => present } } Improper Alignment
  15. Implementation configuration smells elsif $version in ['33', '3.3'] { }

    if $::kernelversion =~ /^(2.2)/ { $appversion = '3.5' } elsif $::kernelversion =~ /^(2.1)/ { exec {"download_app_studio": command => "wget $url", timeout => 0, } } $version = '3.4' ? {undef => $primary_config_file, default => $source_config} file { "/root/.app": mode => '644', ensure => present } } Invalid Property Value
  16. Implementation configuration smells elsif $version in ['33', '3.3'] { }

    if $::kernelversion =~ /^(2.2)/ { $appversion = '3.5' } elsif $::kernelversion =~ /^(2.1)/ { exec {"download_app_studio": command => "wget $url", timeout => 0, } } $version = '3.4' ? {undef => $primary_config_file, default => $source_config} file { "/root/.app": mode => '644', ensure => present } } Misplaced Attribute
  17. class package::web { … } class package::mail { … }

    class package::environment { … } class package::user { … } package.pp
  18. class apache { package { 'apache2': … } service {

    'apache2': … } service { 'mysql': … } package { 'php5': … } file { ‘/etc/apache2/ports.conf': … } user { ‘mitchell': … } } apache.pp
  19. Multifaceted Abstraction • 
 Each abstraction should be designed to

    specify the properties of a single piece of software.
  20. Unnecessary Abstraction A class, ‘define’, or module must contain declarations

    or statements specifying the properties of a desired system.
  21. class web { exec { ‘hadoop-yarn’: … } exec {

    ‘apache-util-set’: … } exec { ‘smail-invoke’: … } exec { ‘postfix-set’: … } } init.pp
  22. package { 'apache2': … } service { 'apache2': … }

    service { 'mysql': … } package { 'php5': … } file { ‘/etc/apache2/ports.conf': … } user { ‘mitchell': … } init.pp
  23. Missing Abstraction A module suffers from the missing abstraction smell

    when resources and language elements are declared and used without encapsulating them in an abstraction.
  24. class apache { package { 'apache2': … } service {

    'apache2': … } file { ‘/etc/apache2/ports.conf': … } … } web.pp class apache { package { 'apache2': … } service { 'apache2': … } file { ‘/etc/apache2/ports.conf': … } … } server.pp
  25. Duplicate Block A duplicate block of statements more than a

    threshold indicates that probably a suitable abstraction definition is missing.
  26. package { 'apache2': … } service { 'apache2': … }

    service { 'mysql': … } package { 'php5': … } file { ‘/etc/apache2/ports.conf': … } user { ‘mitchell': … } package { 'apache2': … } service { 'apache2': … } service { 'mysql': … } package { 'php5': … } file { ‘/etc/apache2/ports.conf': … } user { ‘mitchell': … } package { 'apache2': … } service { 'apache2': … } service { 'mysql': … } package { 'php5': … } file { ‘/etc/apache2/ports.conf': … } user { ‘mitchell': … } init.pp
  27. Insufficient Modularisation An abstraction suffers from this smell when it

    is large or complex and thus can be modularized further.
  28. Unstructured Module Each module in a configuration repository must have

    a well-defined and consistent module structure. RepoName Manifests Modules README … Apache Adobe … files lib manifests spec templates tests README …
  29. Weekend Modularity This smell arises when a module exhibits high

    coupling and low cohesion. Modularity ratio (A) = Cohesion(A) Coupling(A)
  30. Detecting configuration smells Implementation configuration smells • Puppet-lint [1] •

    Additional custom rules in Puppeteer Design configuration smells • Puppeteer [2] — an open source tool 1. http://puppet-lint.com/ 2. https://github.com/tushartushar/Puppeteer
  31. Mining GitHub Repositories Repositories 4,621 Puppet files 142,662 Class declarations

    132,323 Define declarations 39,263 File resources 117,286 Package resources 49,841 Service resources 18,737 Exec declarations 43,468 Lines of code (Puppet only) 8,948,611 http://www.tusharma.in/research/does-your-configuration-code-smell-msr-2016/
  32. Let us summarize M E L S U P E

    E R I I P T U I N M Y I I A A B N C
  33. Let us summarize M E L S U P E

    E R I I P T U I A N M Y I I A A B N C
  34. Let us summarize S M E L S U P

    E E R L I I P T U I A N M Y I I A A B N C
  35. Let us summarize S M E L S U P

    P E E R L I I P T U I A N M Y I I T A A B N C