- Season 1
- 0002 - How and why to avoid nil
- 0003 - Building rspec from scratch
- 0005 - Extracting domain objects
- 0006 - Conflicting principles
- 0007 - Growing a test suite
- 0008 - Processes and jobs
- 0009 - Exceptions and control flow
- Fast tests with and without Rails
- 0016 - A refactoring story
- 0017 - Wrapping third party APIs
Season 1
0002 - How and why to avoid nil
nil
s are most of the time, time bombs, which don't cause problems right away
(when they are born/spawned/gotten/assigned for the first time/etc.), but cause
problems later, when some other piece of code tries to use them, and blows up
because that code did not expect a nil
.
The most offending thing is, since the code blew up after the nil
was
created, it's not obvious from the crash stacktrace where did that nil
come
from.
He discusses several ways of "handling" nils
; I particularly liked the first
one: arrange things so your code blows up, not when handling a nil
, but then
first obtaining it. That way, at least the backtrace will tell you where did
that come from.
To be honest, I did not understood the other ways of managing nil
s. I might
re-visit this because of that.
0003 - Building rspec from scratch
How to write DSLs in Ruby, using rspec as an example/guide/goal. It's nice, and understandable.
0005 - Extracting domain objects
This seems to me basically the same idea I got from Grails (the web framework): you don't have to cram your business logic in the models; most of time, you can put it in another "kind" of module, which is neither model nor view nor controller: the service.
The domain objects, for him, fulfill the same function that service modules perform in another languages/frameworks.
Actually, I think that he's kinda trapped in domain objects, because all you have in ruby are class-like things (classes and modules) which are not actually modular because you can't import just a single method/function from a module, it's always all or nothing.
0006 - Conflicting principles
A better way of writing list_of_things.collect {|thing| thing.something}
[1, 2, 3].collect(&:succ) #=> [2, 3, 4]
Also, he mentions services! service classes.
What the what is "tell don't ask". Oh, Martin Fowler explains. Tell the object what should be done, instead of ask ing it for data and manipulating it and doing the thing yourself. Should have been "tell don't take" or "for fucks sake delegate". But I disgress.
This principle, and Demeter's Law, seem to me to be just trying to control needleses coupling in functions: tell your object to do something, instead of asking for its internals (and violating Demeter's Law) and doing it yourself, because, fundamentally, if you do that yourself you now no longer depend just on that object, but also on the object's internal structure, which might change. These two principles try to keep you out of that mess. That's ... not bad.
What IS bad is that the two guys who presented that concept for the first time (here) are also kinda trying to get you to use privates and access qualifiers and stupid shit like that. I guess we can forgive them because it was sort of still the 90's when they wrote that and collective experience using software you did not write hadn't shown yet what a stupid idea is to use access qualifiers for attributes/methods in class definitions.
0007 - Growing a test suite
Oooh, rspec has a matcher to check that a (countable) value changed from something to something else
expect {thing_that_changes_count}.to change {counter}.by some_amount
0008 - Processes and jobs
Job control
All this time and I haven't gone through how to use jobs in the shell. fg
brings the last suspended job back.
jobs
gives you a list of jobs, along with their IDs.
You can say fg ${job_id}
if you want a specific one.
But also, you can allow one of those suspended jobs to keep running, without
getting into the foreground, using bg ${job_id}
output as files
In a shell, command <(another_command)
takes the output of another_command
and makes it look as if it was a file, at least from command
's point of view.
So you can do stuff like:
vim <(head .bashrc)
or something like that.
0009 - Exceptions and control flow
Nothing noteworthy.
Fast tests with and without Rails
He writes tests for a service. The service (and its tests) are not part of the
rails application, they live in lib/
(and rspec/lib
).
The tests are really fast, because:
- He does not load neither Rails nor bundle.
- He uses
stub
s instead of ActiveRecord instances.
0016 - A refactoring story
Did he just show a bunch of "git log"s after doing a refactor? I lost my time here.
Actually, I just decided to watch this because it's kind of a prerreq for the "wrapping third party APIs"
0017 - Wrapping third party APIs
About testing response handling from remote APIs
It's interesting to look at how he tests requests to third party APIs: by stubbing the responses he would obtain from the real endpoint.
Which is pretty much the same you get from using the VCR/cassettes facility; the VCR library:
- Figures out what the stubbed response would look like, by performing an actual request to the third party API, once. And uses that response for the test.
- Auto-generates the stubbed response in further requests.
If you test a response by stubbing it manually, you will have to adjust it should the response structure change, in the future.
Or, if you are using VCRs, you adjust your test by re-recording the cassette. And that's it.
About test speed
The difference in speed between rspec tests that require rails, versus tests that don't, is abysmal. So much, that it makes me reconsider using factories, and replacing them with stubs/mocks, just for the speed gain.
I think he also mentions in the video how much slower is rspec when you run it via bundle, and admits to not having a clue about why it is that slow. That makes two of us, buddy
Although, I'd like to try parallel-rspec first.