# .kitchen.yml---driver:name:dockeruse_sudo:false# this depends if you need to do `sudo` to run `docker` command or notdisable_upstart:falseimage:ubuntu-upstart:14.04run_command:/sbin/initplatforms:-name:ubuntu-14.04
If you have any questions, suggestions or just want to chat about how contracts.ruby is awesome, you can ping me on twitter @tdd_fellow. If you have any issues using contracts.ruby or contracts-rspec you can create issues on corresponding github project. Pull requests are welcome!
Disclaimer: This is my personal vision, based on my knowledge and experience. If you want to challenge it, ask questions, provide feedback and discuss, feel free to ping me on twitter: @tdd_fellow, I would love to hear from you.
Code examples are in ruby/pseudo-code.
Object Oriented Programming
Most notable features of OOP:
Encapsulation - keep data together with behavior that needs that data, effectively hiding this data from everything else.
Inheritance - usually a subclassing, inheriting all behavior and data, in some language even all private details.
Polymorphism - ability to substitute instances of one class with instances of others.
How important these features are for OO design?
Imagine, that given 100 points you want to distribute them between these 3 features, and each number will represent an importance of corresponding feature.
This would be my answer (and my personal opinion):
Encapsulation
Polymorphism
Inheritance
80
40
-20
And 100 = 80 + 40 + (-20) :)
Why inheritance is so bad?
Because it increases coupling (usually): subclass (usually) depends on some data and/or behavior of its superclass. Even worse: (usually) it is not public data/behavior. I.e.: it violates principle of encapsulation badly. (Usually).
There are actually cases, when you do want your classes to be in inheritance hierarchy, it is the case, when your domain has the same hierarchy naturally in real world. And type inheritance doesn’t really mean behavior inheritance.
So how to avoid violation of encapsulation using inheritance?
Be careful, use only public interfaces of your superclass.
Replace inheritance with composition and delegation, because when you use only public interfaces of superclass, then you don’t really need inheritance.
Coupling
Why coupling is bad?
Imagine you need to change behavior of class X.
You will have to change any other piece of code base, that directly depends on this behavior of class X.
More coupling you have, more changes will have to take place, and probably, in totally unrelated parts of codebase.
As a result it:
Exponentially increases time required for change
Invites bugs (lots of)
Dependency
Dependency, is basically what coupling is, - is not really your friend, so you need to watch out for them.
How to deal with dependencies?
Dependency inversion principle - Instead of referring foreign system/package/class/module/whatever, refer an abstract interface.
Dependency injection - Technique, that allows to provision all dependencies to parts of your system and basically fulfill all required interfaces.
What is the problem with this code? - It is a dependency Answer -> RatingService. What if you wanted to A/B test different rating models? You will definitely have troubles with that approach, especially if it is not the only place, that reference RatingService.
Now you can easily have multiple rating services and A/B test them, or do whatever you want, it is really flexible.
It is still coupling
But coupling to abstract interface, instead of real implementation, which means, you can exchange different implementations without changing users of this interface. Which basically improves polymorphism features of your code. It is very loose coupling.
Test Driven Development
How is it related to OO design?
It provides very short feedback on your OO design:
If you have troubles writing test - your design is wrong and you need to step back
If you don’t like how your test look like - your design is wrong and you need to step back
If you have troubles making test green - your design is wrong and you need to step back
It is really almost like pairing partner if used right! Of course pairing still provides even better feedback loop - real-time continuous feedback loop!
Unit tests vs integration tests
Integration tests are scam!:
Very slow => bad feedback loop
Exponential count of paths to test
Unit tests just don’t work. Are they?
Everything works in isolation != the whole system works as expected.
Testing in isolation = providing fake objects and/or mocks for all your dependencies
Mocks and fake objects can make your unit test green, but in fact the code is broken, because one of the dependencies has changed its behavior or even public interface in unexpected fashion.
Answer: Cut your system at value boundaries!
Instead of method call boundaries. And we arrive at Actor Model.
Any user of this class will have to stub out its #rating_for in unit tests.
It invites additional behavior to be added (since it is as simple as adding additional public method), which will kill single responsibility feature of this class.
Allows unit testing easily without mocks and fake objects: by peeking inside its inbox in unit tests instead, and checking that it received right message.
It is really hard to pack more responsibility to this, since it has no methods, it has just one body, that is responsible for processing exactly one message.
You of course can encode something strange in message, and organize your own method dispatch mechanism through actors inbox, but that is just silly (usually).
Easy to unit test:
123456789101112131415
# creating actor, but not starting itrating_actor=RatingCalculator.new# dependency injection of rating actoranswer_actor=Answer.new(answer_id,rating_actor)answer_actor.startrender_actor=Render.new(answer_actor)render_actor.runexpect(rating_actor.inbox).toinclude([comments,upvotes,downvotes,outbox])# fake response from rating actoroutbox.send(3.5)expect(render_actor).torender_rating(3.5)
In unit tests you start only one actor - actor under test, and all other actors just get instantiated correctly and passed in as a dependencies where needed. Since they are not started, they will not consume any messages from their inbox, which means that you can consume these inboxes from your unit test, and check that the messages that arrived at inboxes are expected.
When the code is done
It works!
It is readable (future me will not curse me for writing this code)
It has no duplication
And it is as short as possible (while maintaining all of the above)
Code comments
Basically a code smell (I’m not talking about documentation comments)
Example:
123
# when user is activeifactivity_service.has_events(user.id,min_date:2.weeks.ago)&&!user.fraud?
Which is bad from more than one point of view, it literally should have been:
12345
ifuser.active?# orifactivity_service.user_is_active?(user)# .. more variations can be here ..# .. but all of them will be better ..
If code needs comment:
it is not readable
it fails to communicate its intent
You should be able to read the code and understand it. In that order: read -> understand.
You shouldn’t interpret it in your head. You shouldn’t have Ruby (or your favorite language here) instance running in your head.
To sum it up
Inheritance is good only in very rare cases
Coupling and dependencies are not your friends, take them under control with dependency inversion & injection
TDD as a shortest feedback cycle for your OO design
Write code in such way, that you would thank yourself for that in the future
Recommended reading: “Pragmatic Programmer: From Journeyman to Master” by Andrew Hunt and David Thomas. It is insanely good, concise book with lots of awesome references to other resources.
Thanks!
If you have any questions or suggestions, you can always reach me out on twitter @tdd_fellow.
A short introduction to a powerful Design by Contract technique and its implementation in ruby contracts.ruby.
Design by Contract allows one to do defensive programming in very elegant fashion, allows to set contracts on methods (expectations on input - arguments; and on output - return result) and invariants on classes. This allows to reason about code much much better.
Classical defensive programming
Lets start from simple code example:
123
defadd(a,b)a+bend
If you want to be really confident in implementation and usage of this method, you would probably use something like that:
12345678910
defadd(a,b)raise"a should be Fixnum or Float"unlessa.is_a?(Fixnum)||a.is_a?(Float)raise"b should be Fixnum or Float"unlessb.is_a?(Fixnum)||b.is_a?(Float)result=a+braise"result should be Fixnum or Float"unlessresult.is_a?(Fixnum)||result.is_a?(Float)resultend
Which definitely provides guarantees for input and output values.
But this code is extremely ugly, unmaintainable and unreadable. You can always extract assert-like helper methods, but it will not improve readability too much, you want to have just this simple a + b in the body of this method.
gem "contracts"
1234
ContractNum,Num=>Numdefadd(a,b)a+bend
This code does the same thing, but readability at a totally different level. Developers who know haskell may find this notation quite familiar.
Design by contract
When applying design by contract technique to development of any system or service, it allows you to answer the following questions:
What does it expect? - Restrictions on input data for the system.
What does it guarantee? - Restrictions on output data (return value) of the system.
What does it maintain? - Restrictions on the inner state of the system (if your system is stateful, of course).
Benefits
Benefits of being able to answer this questions and enforce them on a runtime level are:
Clients of your system can be confident using its public APIs. They can be sure, that if they provide something wrong, then they will get a convenient error immediately. And they can be sure, that system returns the right value as a result.
System or service itself can be confident in its own operations. Implementation of system, that is covered with contracts, can assume that all the data flowing through the system is right and expected, and don’t waste time (and lines of code, and sanity of the developer/maintainer) on different checks, conversions and so on (ie on defensive programming), it can just do what it needs to do, in confident, concise and convenient way, right up to the point.
assert on steroids. And it is not only about types
Up until now it may seem like some kind of runtime type-checking system. But it is not, it is way more powerful.
You can check for exact value:
1
Contract200,nil,:get=>"ok"
You can check for types:
1
ContractUser,Time=>Or[TrueClass,FalseClass]
You can check for anything that is available to you at runtime:
12345678910
ContractActiveUser=>Ratingdefrating_for(active_user)# .. calculate rating for active user ..endclassActiveUserdefself.valid?(user)user.last_activity>2.weeks.agoendend
As you expect when contract check on active_user argument happens, it will just call ActiveUser.valid?(active_user) and in case of falsy result will raise contract violation error.
This kind of errors tell you, what exactly you did wrong and where exactly you did it wrong. It is totally different from usual NoMethodError :something for nil:NilClass, because usually these kind of no-method errors can occur in totally different part of codebase comparing to where these errors actually were introduced. Contract violation will be issued exactly at the place where you passed invalid data into or out from your system. So that when you see a contract violation error, there is a high chance that you already know how to fix it.
Pattern matching, sorta..
You can say even method overloading. Very simple example:
12345678
# factorial in classic waydeffactorial(n)ifn==11elsen*factorial(n-1)endend
12345678910
# factorial using pattern matchingContract1=>1deffactorial(_)1endContractNum=>Numdeffactorial(number)number*factorial(number-1)end
When I saw this example, my first reaction was: “Wow!”. I was very excited about this feature.
Something useful with pattern matching
Last example was not particularly useful for our everyday development, but here you go.
Imagine you have a concurrent evented system, that needs to make asynchronous requests to some external http service(s). You may eventually end up with handler functions like these:
# And using pattern matching:Contract200,JsonString=>JsonStringdefhandle_response(status,response)transform_response(JSON.parse(response))endContractFixnum,String=>JsonStringdefhandle_response(status,response)wrap_in_error(status,response)end
Limitless benefits
All your input data is consistent
All data flows inside of your system are consistent
State of your system is consistent
Output of your system is consistent (or it is a contract violation error)
Blows up loudly on any logical error in your system
Last point is extremely important, because sometimes logical errors in classical programs will not lead to any failure at all, they will just do the wrong thing. For example, transfer money to wrong bank account. In such mission critical systems it is really important to fail fast to not allow error to propagate throughout your system.
Caveats: Performance
Benchmark
Slowdown
a+b
900% slowdown
production system with network IO
5-10% slowdown
NO_CONTRACTS=1
0% slowdown
First benchmark is simple comparision of a + b with and without contract. Since a + b itself is very fast, then the slowdown is huge. But if you try to benchmark any real world system, that actually does something useful (communicates to other services through network for example), then slowdown is very very small.
And you have ability to disable contracts in production with NO_CONTRACTS=1 environment variable. But beware, you lose extremely important benefit of blowing up on logical error immediately before letting error propagate. This benefit itself outweights these 5-10%, at least for me.
If you have any questions or suggestions, you can always reach me out on twitter @tdd_fellow. If you have any issues with using contracts.ruby, you can always create an issue on github and Pull Requests are welcome.
I generally like this approach, it is nice to have such feature in your language tools available right there and with already existing integrations to popular editors.
Except one thing:
Parentheses
Go needs fewer parentheses than C and Java: control structures (if, for, switch) do not have parentheses in their syntax. Also, the operator precedence hierarchy is shorter and clearer, so
x<<8 + y<<16
So we kill parentheses and replace them with whitespace. I am not entirely sure it is better. How will this work then?
1
x<<8+y<<16
And what about this?
1
x<<8+y<<16
Probably nobody will write it like that, but one space miss, and lots of minutes lost in debugging.
Semicolons
Oh, lexer inserting semicolons where it pleases? What can go wrong. Reminds me about javascript and its problems when you omit semicolons.
And this example looked strange to me:
One consequence of the semicolon insertion rules is that you cannot put the opening brace of a control structure (if, for, switch, or select) on the next line. If you do, a semicolon will be inserted before the brace, which could cause unwanted effects. Write them like this
if i < f() {
g()
}
not like this
if i < f() // wrong!
{ // wrong!
g()
}
First I thought that it will accept this input, put a semicolon after if, compile successfully and always execute statement inside of block, especially because it said “could cause unwanted effects”. But turned out this code results in compilation error - so no problem here, but probably this should have been clarified in the article.
Control Structure
Mandatory block - looks good to me.
But the last example worries me:
This is an example of a common situation where code must guard against a sequence of error conditions. The code reads well if the successful flow of control runs down the page, eliminating error cases as they arise. Since error cases tend to end in return statements, the resulting code needs no else statements.
That code is definitely not narrative, I will put some comments with kind of operation that is done:
12345678910
f,err:=os.Open(name)// get inputiferr!=nil{// check errors, guardreturnerr}d,err:=f.Stat()// get additional inputiferr!=nil{// check for errors, again, guardf.Close()// cleanupsreturnerr}codeUsing(f,d)// do something
This way it is hard to understand and reason about.
Why not just:
123456
f=os.Open(name)// get inputd=f.Stat()// get inputresult=codeUsing(f,d)// do somethingifresult.IsErorr(){// handle errorsf.Close()// cleanup}
Of course f, d and result are just Result/Either monads, they can be either in normal or faulty state. Whenever you try to do anything on Result in faulty state, it will just return itself. But Result in normal state will proxy call to its contents and wrap it in another Result monad (normal or faulty - depends on if call was successful or not). Probably I am too critical about that, because here I used some patterns that are not part of the language itself, but yeah, I can’t look at code that mixes guards and actions.
Probably, somebody out there in go-lang world can tell me, is it common to use patterns like Maybe, Result, NullObject and so on in go-lang? Or everybody just go with simple code without any magic behind the scenes, and just do it like in the article’s example? Feel free to ping me at twitter @tdd_fellow.
For
Lets move on..
For strings, the range does more work for you, breaking out individual Unicode code points by parsing the UTF-8. Erroneous encodings consume one byte and produce the replacement rune U+FFFD. (The name (with associated builtin type) rune is Go terminology for a single Unicode code point. See the language specification for details.)
I really like that a term for this “unicode minimal entity” was invented. And after some while the name actually makes a lot of sense. And it sounds good.
Switch
That surprised me. Feels like assembler:
Although they are not nearly as common in Go as some other C-like languages, break statements can be used to terminate a switch early. Sometimes, though, it’s necessary to break out of a surrounding loop, not the switch, and in Go that can be accomplished by putting a label on the loop and “breaking” to that label. This example shows both uses.
Loop:
for n := 0; n < len(src); n += size {
switch {
case src[n] < sizeOne:
if validateOnly {
break
}
size = 1
update(src[n])
case src[n] < sizeTwo:
if n+1 >= len(src) {
err = errShortInput
break Loop
}
if validateOnly {
break
}
size = 2
update(src[n] + src[n+1]<<shift)
}
}
Not exactly the original assembler label, one only use it to mark (aka tag) the loop itself and use it to break out of it. Interesting concept, but something clicks in my head when I look at this.
Type switch
Good one, “Switching on Type”, (usually) a code smell, builtin into language. But still it has its own uses when used carefully.
Multiple return values
Why not tuples? If you just introduce tuples and destructuring, then you don’t need multiple return values, only one return value - tuple itself.
Defer
This is a nice one. Allows to simplify previous example with files even more:
1234
f=os.Open(name)// get inputdeferf.Close()// deferred cleanup right after acquiring of `f`d=f.Stat()// get inputresult=codeUsing(f,d)// do something
Particularly interesting example with trace/untrace follows in the article.
rspec-json_expectations library provides powerful include_json matcher for your RSpec suites. It allows to match string with JSON or already parsed ruby Hash against other ruby Hash, which is very convenient and creates very readable spec code. Lets jump to some examples.
It can handle some plain json:
1234567
it"has basic info about user"doexpect(response).toinclude_json(id:25,email:"john.smith@example.com",name:"John")end
And nested json:
123456789
it"has gamification info for user"doexpect(response).toinclude_json(code:"7wxMw32",gamification:{rating:93,score:355})end
You can even do some regex matching:
123456
it"has basic info about user"doexpect(response).toinclude_json(code:/^[a-z0-9]{10}$/,url:%r{api/v5/users/[a-z0-9]{10}.json})end
Most can agree, that this method of specifying JSON responses in ruby is very readable, but what about failure messages? How helpful they are?
For example with failure in nested JSON things can become tricky, but this gem solves them quite nice:
1234
json atom at path "gamification/score" is not equal to expected value:
expected: 355
got: 397
If you match with nested Arrays you will get numbers in your JSON path within failure message, for example:
123456
json atom at path "results/2/badges/0" is not equal to expected value:
expected: "first flight"
got: "day & night"
json atom at path "results/3" is missing