Browse Source

Merge branch 'release/20190621.1'

master 20190621.1
Julio Biason 5 years ago
parent
commit
ced9172335
  1. 2
      content/books/things-i-learnt/_index.md
  2. 37
      content/books/things-i-learnt/document-is-contract/index.md
  3. 2
      content/books/things-i-learnt/document-it/index.md
  4. 2
      content/books/things-i-learnt/integration-tests/index.md
  5. 59
      content/books/things-i-learnt/tests-dead-code/index.md

2
content/books/things-i-learnt/_index.md

@ -12,9 +12,11 @@ template = "section-contentless.html"
* [Write Steps as Comments](steps-as-comments)
* [Gherkin Is Your Friend to Understand Expectations](gherkin)
* [Unit Tests Are Good, Integration Tests Are Gooder](integration-tests)
* [Testing Every Function Creates Dead Code](tests-dead-code)
* [Tests Make Better APIs](tests-apis)
* [Make Tests That You Know How To Run on the Command line](tests-in-the-command-line)
* [Be Ready To Throw Your Code Away](throw-away)
* [Good Languages Come With Tests](languages-tests)
* [Future Thinking Is Future Trashing](future-trashing)
* [Documentation Is a Love Letter To Your Future Self](document-it)
* [The Function Documentation Is Its Contract](document-is-contract)

37
content/books/things-i-learnt/document-is-contract/index.md

@ -0,0 +1,37 @@
+++
title = "Things I Learnt The Hard Way - The Function Documentation Is Its Contract"
date = 2019-06-21
[taxonomies]
tags = ["en-au", "books", "things i learnt", "documentation", "contracts"]
+++
When you start the code by [writing the
documentation](/books/things-i-learnt/steps-as-comments), you're actually
making a contract (probably with your future self): I'm saying this function
does _this_ and _this_ is what it does.
<!-- more -->
Remember that the documentation must be a clear explanation of what your code
_is_ doing; remember that good messages will make [reading the code only by
the function documentation](/books/things-i-learnt/document-id) should be
clear.
A function called `mult`, documented as "Get the value and multiply by 2" but,
when you look at the code, it does multiply by 2, but sends the result through
the network or even just asks a remote service to multiply the incoming result
by 2, is clearly breaking its contract. It's not just multiplying by 2, it's
doing more than just that, or it's asking someone else to manipulate the
value.
Now, what happens when this kind of thing happens?
The easy solution is to change the documentation. But do you know if people
who called the function expecting it to be "multiply value by 2" will be happy
for it to call an external service? There is a clear breach of "contract" --
whatever you initially said your function would do -- so the correct solution
would be to add a new function with a proper contract -- and probably a better
name.
{{ chapters(prev_chapter_link="/books/things-i-learnt/document-it", prev_chapter_title="Documentation Is a Love Letter To Your Future Self") }}

2
content/books/things-i-learnt/document-it/index.md

@ -25,4 +25,4 @@ I have some bad news for you...
[^1]: Please, don't make me revise this in 2027... :(
{{ chapters(prev_chapter_link="/books/things-i-learnt/future-trashing", prev_chapter_title="Future Thinking is Future Trashing") }}
{{ chapters(prev_chapter_link="/books/things-i-learnt/future-trashing", prev_chapter_title="Future Thinking is Future Trashing", next_chapter_link="/books/things-i-learnt/document-is-contract", next_chapter_title="The Function Documentation Is Its Contract") }}

2
content/books/things-i-learnt/integration-tests/index.md

@ -66,4 +66,4 @@ parts.
[^1]: There is no "unit" in "unit tests". "Unit test" means the test _is_ a
unit, indivisible and dependent only on itself.
{{ chapters(prev_chapter_link="/books/things-i-learnt/gherkin", prev_chapter_title="Gherkin Is Your Friend to Understand Expectations", next_chapter_title="Tests Make Better APIs", next_chapter_link="/books/things-i-learnt/tests-apis") }}
{{ chapters(prev_chapter_link="/books/things-i-learnt/gherkin", prev_chapter_title="Gherkin Is Your Friend to Understand Expectations", next_chapter_title="Testing Every Function Creates Dead Code", next_chapter_link="/books/things-i-learnt/tests-dead-code") }}

59
content/books/things-i-learnt/tests-dead-code/index.md

@ -0,0 +1,59 @@
+++
title = "Things I Learnt The Hard Way - Testing Every Function Creates Dead Code"
date = 2019-06-21
[taxonomies]
tags = ["en-au", "books", "things i learnt", "unit tests", "dead code"]
+++
If you write a test for every single function on your system, and your system
keeps changing, how will you know when a function is not necessary anymore?
<!-- more -->
Writing a test for every single function on your system may come from the
"100% Coverage Syndrome", which afflicts some managers, thinking that the only
way to be completely sure your system is "bug free" is to write tests for
every single piece of code, till you reach the magical "100% coverage" in all
the tests.
I do believe you can reach 100% coverage, as long as you're willing to
_delete_ your code.
Cue the universal grasps here.
But how do you know which pieces of code can be deleted?
When I mentioned [integration
tests](/books/things-i-learnt/integration-tests), I mentioned how much more
sense it made to me reading them instead of the "unit" tests, because they
were describing exactly how the system would operate in normal conditions. If
you write tests the go through the system, doing normal operations, and you
can get tests for all the normal cases -- and some "abnormal", like when
things go wrong -- then you know that, if you run those tests and they mark
some lines as "not tested", it's because you don't need them.
"But Julio, you're forgetting the error control!" I do agree, specially when
you're talking with project owners or some other expert, that people will
forget to tell you what to do in case of things going wrong -- say, someone
entering a name in the age field -- but _you_ can see those and _you_ know
that you need error control so _you_ can add the error control and describe
the situation where that error control would trigger.
If, on the other hand, you write a test for every function, when you do a
short/simple check, you'll find that the function is still being used in the
system -- by the tests, not actually, "value to the user" code. Sure, you can
use your IDE to go back and forth between code and test and see if it points a
use beyond the test, but it won't do it for yourself.
There is one other weird thing about trying to write integration tests for
error controls: Sometimes, you can't reach the control. It's true! I did wrote
control checks for every function once but, when running in the integration
tests, there was no way to produce an input at the input layer of the system
that would reach the error control in that function -- mostly 'cause the
other functions, which would run before the one I was trying to test, would
catch the error before it. If that's a design problem or not -- it probably
was -- it's a different discussion, but the fact is that that function didn't
need error control.
{{ chapters(prev_chapter_link="/books/things-i-learnt/integration-tests", prev_chapter_title="Unit Tests Are Good, Integration Tests Are Gooder", next_chapter_title="Tests Make Better APIs", next_chapter_link="/books/things-i-learnt/tests-apis") }}
Loading…
Cancel
Save