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

Contract Programming in Ruby

Contract Programming in Ruby

Human Talks Grenoble

Yves Brissaud

December 12, 2017
Tweet

More Decks by Yves Brissaud

Other Decks in Programming

Transcript

  1. Programmation par contrat
    en ruby
    Yves Brissaud
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  2. Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  3. UT, TDD, BDD, *tests
    /
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  4. Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  5. La programmation par contrat
    -- wikipedia
    est un paradigme de programmation dans lequel le déroulement
    des traitements est régi par de règles.


    C'est une méthode de programmation semi-formelle dont le but
    principal est de réduire le nombre de bugs dans es programmes.


    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  6. Eiffel, 1985
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  7. ...
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  8. - précondition
    - postcondition
    - invariant
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  9. Précondition
    Responsabilité sur l'appelant
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  10. Postcondition
    Responsabilité sur l'appelé
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  11. Invariant
    Toujours vrai
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  12. Examples
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  13. sqrt
    def sqrt(x)
    Math.sqrt(x)
    end
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  14. def sqrt(x)
    Math.sqrt(x)
    end
    > sqrt(2)
    1.414213563730951
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  15. def sqrt(x)
    Math.sqrt(x)
    end
    > sqrt(-2)
    ?
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  16. def sqrt(x)
    Math.sqrt(x)
    end
    > sqrt(-2)
    Math::DomainError: Numerical argument is out of domain
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  17. Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  18. def sqrt(x)
    unless x >= 0
    puts "x should be positive"
    nil
    end
    Math.sqrt(x)
    end
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  19. def sqrt(x)
    unless x >= 0
    puts "x should be positive"
    nil
    end
    Math.sqrt(x)
    end
    > sqrt(-2)
    x should be positive
    nil
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  20. def sqrt(x)
    unless x >= 0
    puts "x should be positive"
    nil
    end
    Math.sqrt(x)
    end
    > sqrt(nil)
    ?
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  21. def sqrt(x)
    unless x >= 0
    puts "x should be positive"
    0
    end
    Math.sqrt(x)
    end
    > sqrt(nil)
    NoMethodError: undefined method `>=' for nil:NilClass
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  22. - Qui gère la bonne valeur en entrée ?
    - Qui gère la bonne valeur en sortie ?
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  23. - entrée gérée par l'appelé
    - sortie gérée par l'appelant
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  24. Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  25. Contract Pos => Pos
    def sqrt(x)
    Math.sqrt(x)
    end
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  26. dé nition claire de l'entrée
    Pos => Numérique >= 0
    dé nition claire de la sortie
    Pos => Numérique >= 0
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  27. Contract Pos => Pos
    def sqrt(x)
    Math.sqrt(x)
    end
    > sqrt(-2)
    ?
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  28. Contract Pos => Pos
    def sqrt(x)
    Math.sqrt(x)
    end
    > sqrt(-2)
    ParamContractError: Contract violation for argument 1 of 1:
    Expected: Pos,
    Actual: -2
    Value guarded in: Object::sqrt
    With Contract: Pos => Pos
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  29. Contract Pos => Pos
    def sqrt(x)
    Math.sqrt(x)
    end
    > sqrt(nil)
    ?
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  30. Contract Pos => Pos
    def sqrt(x)
    Math.sqrt(x)
    end
    > sqrt(-2)
    ParamContractError: Contract violation for argument 1 of 1:
    Expected: Pos,
    Actual: nil
    Value guarded in: Object::sqrt
    With Contract: Pos => Pos
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  31. - entrée gérée par l'appelé 'appelan
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  32. Contract Pos => Pos
    def sqrt(x)
    "haha"
    end
    > sqrt(2)
    ?
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  33. Contract Pos => Pos
    def sqrt(x)
    "haha"
    end
    > sqrt(2)
    ReturnContractError: Contract violation for return value:
    Expected: Pos,
    Actual: "haha"
    Value guarded in: Object::sqrt
    With Contract: Pos => Pos
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  34. - sortie gérée par l'appelant 'appel
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  35. Et si on veut sqrt(nil) == 0 ?
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  36. Classique
    Contract Maybe[Pos] => Pos
    def sqrt(x)
    return 0 if x.nil?
    Math.sqrt(x)
    end
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  37. Classique
    Contract Maybe[Pos] => Pos
    def sqrt(x)
    return 0 if x.nil?
    Math.sqrt(x)
    end
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  38. Method overloading
    Contract Pos => Pos
    def sqrt(x)
    Math.sqrt(x)
    end
    Contract nil => 0
    def sqrt(_)
    0
    end
    > sqrt(2)
    1.414213563730951
    > sqrt(nil)
    0
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  39. Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  40. Aucun, n'importe quoi
    Contract None => Any
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  41. Hash, Array
    Contract ArrayOf[String] => Any
    Contract HashOf[Symbol => Date] => ArrayOf[{ :date => Num }]
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  42. Keyword arguments
    Contract String, KeywordArgs[
    port: Optional[Num],
    user: String,
    password: And[String, -> (p) p.length >= 8]
    ] => Connection
    def connect(host, port: 5000, user:, password:)
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  43. Functions
    Contract Func[RangeOf[Date] => Enum[:workweek, :weekend]] => Any
    def set_callback(range_to_day_type)
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  44. Duck typing
    Contract RespondTo[:parent_user] => User
    def get_parent(obj)
    obj.parent_user
    end
    Contract Any => NoParentError
    def get_parent(obj)
    NoParentError.new obj
    end
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  45. https://egonschiele.github.io/contracts.ruby
    https://github.com/egonSchiele/contracts.ruby
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  46. code auto documenté (à jour)
    responsabilités claires
    moins de surprise à l'exécution
    method overloading
    coût à l'exécution (désactivable)
    idiomatique
    Human Talks Grenoble décembre 2017 | https://www.squarescale.com | @_crev_

    View Slide

  47. Thanks
    https://www.squarescale.com
    Human Talks Grenoble décembre 2017 | @_crev_ | docker run --rm -it squarescale/ybrissaud

    View Slide