From e7b98495a0912b9cd5198b291f218318503e002d Mon Sep 17 00:00:00 2001 From: Julio Biason Date: Fri, 21 Jun 2019 12:50:06 -0300 Subject: [PATCH 1/2] New Chapter: Documentation is a contract --- content/books/things-i-learnt/_index.md | 1 + .../document-is-contract/index.md | 37 +++++++++++++++++++ .../things-i-learnt/document-it/index.md | 2 +- 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 content/books/things-i-learnt/document-is-contract/index.md diff --git a/content/books/things-i-learnt/_index.md b/content/books/things-i-learnt/_index.md index 8372f7f..6f2249e 100644 --- a/content/books/things-i-learnt/_index.md +++ b/content/books/things-i-learnt/_index.md @@ -18,3 +18,4 @@ template = "section-contentless.html" * [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) diff --git a/content/books/things-i-learnt/document-is-contract/index.md b/content/books/things-i-learnt/document-is-contract/index.md new file mode 100644 index 0000000..9c02812 --- /dev/null +++ b/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. + + + +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") }} diff --git a/content/books/things-i-learnt/document-it/index.md b/content/books/things-i-learnt/document-it/index.md index 7203d5f..fe34aa0 100644 --- a/content/books/things-i-learnt/document-it/index.md +++ b/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") }} From 4f92c083cf5b72f29c89b3d38850852343e94cdd Mon Sep 17 00:00:00 2001 From: Julio Biason Date: Fri, 21 Jun 2019 13:11:55 -0300 Subject: [PATCH 2/2] New chapter: All functions tests = dead code --- content/books/things-i-learnt/_index.md | 1 + .../integration-tests/index.md | 2 +- .../things-i-learnt/tests-dead-code/index.md | 59 +++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 content/books/things-i-learnt/tests-dead-code/index.md diff --git a/content/books/things-i-learnt/_index.md b/content/books/things-i-learnt/_index.md index 6f2249e..0568ff0 100644 --- a/content/books/things-i-learnt/_index.md +++ b/content/books/things-i-learnt/_index.md @@ -12,6 +12,7 @@ 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) diff --git a/content/books/things-i-learnt/integration-tests/index.md b/content/books/things-i-learnt/integration-tests/index.md index 77c5b50..b62f80c 100644 --- a/content/books/things-i-learnt/integration-tests/index.md +++ b/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") }} diff --git a/content/books/things-i-learnt/tests-dead-code/index.md b/content/books/things-i-learnt/tests-dead-code/index.md new file mode 100644 index 0000000..5239952 --- /dev/null +++ b/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? + + + +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") }}