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

ElixirConf.EU 2016: Credo - Analysing ASTs for Fun and Profit

ElixirConf.EU 2016: Credo - Analysing ASTs for Fun and Profit

Today's developer tools are mostly used in a very technocratic fashion where there's success and failure, 1 and 0. Either a tool thinks you're totally wrong or you're 100% right. You get shouted at or praised. There is no middle ground. Except there is. Credo, the first teaching code linter for Elixir, puts its focus on the in-between: How errors can be opportunities for learning. How AST analysis can be fun and educational. And how one can combine these features into a professional tool that gives straight results while still treating its users as human beings.

René Föhring

May 11, 2016
Tweet

More Decks by René Föhring

Other Decks in Programming

Transcript

  1. CREDO
    Analysing ASTs for Fun and Profit
    René Föhring, @rrrene

    View full-size slide

  2. @rrrene
    read in pirate voice

    View full-size slide

  3. @rrrene
    read in pirate voice
    |> java |> ruby |> elixir

    View full-size slide

  4. @rrrene
    read in pirate voice
    |> java |> ruby |> elixir
    www.neopoly.com/jobs

    View full-size slide

  5. 2014
    inch-ci.org
    Tool for evaluating inline code documentation

    View full-size slide

  6. 2015
    elixirstatus.com
    Tool for community announcements

    View full-size slide

  7. Code
    2016
    Docs
    2014
    inch-ci.org
    Community
    2015
    elixirstatus.com Credo
    Today‘s topic!

    View full-size slide

  8. Excursion:
    What is static analysis?

    View full-size slide

  9. 11 def runApiCall(list, mode \\ nil) do
    12 options = %{}
    13 list |> IO.inspect
    14 API.call(list, mode)
    15 end
    $ mix compile
    example.ex:11: warning: default arguments in run/1
    are never used
    example.ex:12: warning: variable options is unused

    View full-size slide

  10. 11 def runApiCall(list, mode \\ nil) do
    12 options = %{}
    13 list |> IO.inspect
    14 API.call(list, mode)
    15 end
    $ mix compile
    example.ex:11: warning: default arguments in run/2
    are never used
    example.ex:12: warning: variable options is unused

    View full-size slide

  11. abstract syntax tree (AST)
    {, , }

    View full-size slide

  12. abstract syntax tree (AST)
    {, , }
    # 1 + 2
    {:+, [line: 1], [1, 2]}

    View full-size slide

  13. abstract syntax tree (AST)
    {, , }
    # 1 + 2
    {:+, [line: 1], [1, 2]}
    # 42 |> inspect()
    {:|>, [line: 1], [42, {:inspect, [line: 1], []}]}

    View full-size slide

  14. abstract syntax tree (AST)
    {, , }
    # 1 + 2
    {:+, [line: 1], [1, 2]}
    # 42 |> inspect()
    {:|>, [line: 1], [42, {:inspect, [line: 1], []}]}
    # try it yourself
    Code.string_to_quoted!

    View full-size slide

  15. Ruby - RuboCop
    Python - pylint
    JavaScript - ESLint
    Elixir - ?

    View full-size slide

  16. Ruby - RuboCop
    Python - pylint
    JavaScript - ESLint
    Elixir - Dogma

    View full-size slide

  17. $ mix dogma
    Inspecting 78 files.
    .X....XXX.XX.XX.XXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXX
    78 files, 624 errors!
    == lib/plug/adapters/cowboy/conn.ex ==
    92: CommentFormat: Comments should start with a single space
    82: CommentFormat: Comments should start with a single space
    121: FunctionArity: Arity of `parse_multipart` should be less than 4 (was 5).
    117: FunctionArity: Arity of `parse_multipart` should be less than 4 (was 5).
    38: FunctionArity: Arity of `send_file` should be less than 4 (was 6).
    47: LineLength: Line length should not exceed 80 chars (was 92).
    49: LineLength: Line length should not exceed 80 chars (was 97).
    Dogma v0.1.5 analysing Plug v1.2.0-dev (output abbreviated)

    View full-size slide

  18. (╯°□°)╯︵ ┻━┻
    But what is
    the problem?

    View full-size slide

  19. Elixir’s recent rise from
    totally unknown to
    still definitely unknown but
    mentioned in hushed tones
    Clark Kampfe in “Elixir is not Ruby”
    https://zeroclarkthirty.com/2015-11-01-elixir-is-not-ruby.html

    View full-size slide

  20. What‘s the
    newcomer experience?

    View full-size slide

  21. Let‘s create
    a mentoring tool.

    View full-size slide

  22. 11 def runApiCall(list, mode \\ nil) do
    12 options = %{}
    13 list |> IO.inspect
    14 API.call(list, mode)
    15 end

    View full-size slide

  23. 11 def runApiCall(list, mode \\ nil) do
    12 options = %{}
    13 list |> IO.inspect
    14 API.call(list, mode)
    15 end
    breaks convention of underscored names
    outputs to STDOUT, is slow

    View full-size slide

  24. 11 def runApiCall(list, mode \\ nil) do
    12 options = %{}
    13 list |> IO.inspect
    14 API.call(list, mode)
    15 end
    breaks convention of underscored names
    outputs to STDOUT, is slow

    View full-size slide

  25. First, we need to
    categorize issues.

    View full-size slide

  26. readability
    software design

    View full-size slide

  27. readability
    software design
    refactoring opportunities

    View full-size slide

  28. readability
    software design
    refactoring opportunities
    consistency checks

    View full-size slide

  29. readability
    software design
    refactoring opportunities
    consistency checks
    warnings

    View full-size slide

  30. 1 defmodule ReadabilityExample do
    2 @githubBaseURL "https://github.com/"
    3 @github_sample_url "https://github.com/rrrene/
    credo/blob/master/lib/credo/check/consistency/
    line_endings/unix.ex"
    4 end

    View full-size slide

  31. 1 defmodule ReadabilityExample do
    2 @githubBaseURL "https://github.com/"
    3 @github_sample_url "https://github.com/rrrene/
    credo/blob/master/lib/credo/check/consistency/
    line_endings/unix.ex"
    4 end
    breaks convention of underscored names
    exceeds maximum characters per line

    View full-size slide

  32. Next, issues need
    to be prioritized.

    View full-size slide

  33. issues ordered by priority
    20
    12
    11
    6
    5
    1
    -1
    -2
    -5
    -10
    -11
    -100

    View full-size slide

  34. issues ordered by priority
    20
    12
    11
    6
    5
    1
    -1
    -2
    -5
    -10
    -11
    -100
    Readability: max line length
    Warning: IO.inspect
    Readability: camelCase function name

    View full-size slide

  35. issues ordered by priority
    20
    12
    11
    6
    5
    1
    -1
    -2
    -5
    -10
    -11
    -100
    (regular)
    Readability: max line length
    Readability: camelCase function name
    Warning: IO.inspect

    View full-size slide

  36. issues ordered by priority
    20
    12
    11
    6
    5
    1
    -1
    -2
    -5
    -10
    -11
    -100
    Readability: max line length
    Readability: camelCase function name
    Warning: IO.inspect
    (strict)

    View full-size slide

  37. readability
    software design
    refactoring opportunities
    consistency checks
    warnings

    View full-size slide

  38. {1, "string", true}
    # two ways how to write tuples
    # both great, if applied consistently
    { 1, "string", true }

    View full-size slide

  39. {1, "string", true}
    # two ways how to write tuples
    # both great, if applied consistently
    { 1, "string", true }
    without spaces inside the tuple

    View full-size slide

  40. {1, "string", true}
    # two ways how to write tuples
    # both great, if applied consistently
    { 1, "string", true }
    with spaces inside the tuple
    without spaces inside the tuple

    View full-size slide

  41. defmodule BadHTTPHeaderError do
    defexception [:message]
    end
    defmodule UserRequestError do
    defexception [:message]
    end

    View full-size slide

  42. defmodule BadHTTPHeaderError do
    defexception [:message]
    end
    defmodule UserRequestError do
    defexception [:message]
    end
    consistent suffix "Error"

    View full-size slide

  43. defmodule BadHTTPHeaderException do
    defexception [:message]
    end
    defmodule UserRequestException do
    defexception [:message]
    end
    consistent suffix „Exception"

    View full-size slide

  44. defmodule InvalidHTTPHeader do
    defexception [:message]
    end
    defmodule InvalidUserRequest do
    defexception [:message]
    end
    consistent prefix „Invalid"

    View full-size slide

  45. fails consistency check
    defmodule InvalidHeader do
    defexception [:message]
    end
    defmodule UserRequestFailed do
    defexception [:message]
    end
    no consistent prefix or suffix

    View full-size slide

  46. $ # add credo to mix.exs
    $ mix deps.get
    $ mix credo

    View full-size slide

  47. $ mix credo lib/plug/static.ex:90:13

    View full-size slide

  48. Where do we
    go from here?

    View full-size slide

  49. Explanations

    View full-size slide

  50. Explanations
    Style Guide

    View full-size slide

  51. Explanations
    Style Guide
    Editor Support

    View full-size slide

  52. Explanations
    Style Guide
    Editor Support
    Custom Configuration

    View full-size slide

  53. Explanations
    Style Guide
    Editor Support
    Custom Configuration
    @lint attributes

    View full-size slide

  54. Explanations
    Style Guide
    Editor Support
    Custom Configuration
    @lint attributes
    Custom Checks are coming!

    View full-size slide

  55. Explanations
    Style Guide
    Editor Support
    Custom Configuration
    @lint attributes
    Custom Checks are coming!
    Creating a Toolbox, not a Linter!

    View full-size slide

  56. final thoughts

    View full-size slide

  57. Questions & Alchemists

    View full-size slide

  58. # APPENDIX
    Credo – A static code analysis tool with a focus on code consistency and teaching.
    https://hex.pm/packages/credo
    Dogma – A code style linter for Elixir, powered by shame.
    https://hex.pm/packages/dogma
    Clark Kampfe in “Elixir is not Ruby”
    https://zeroclarkthirty.com/2015-11-01-elixir-is-not-ruby.html
    Inch CI – Lint your docs
    http://inch-ci.org
    ElixirStatus – community announcements
    http://elixirstatus.com
    HexFaktor – monitor your deps
    http://beta.hexfaktor.org

    View full-size slide