Julio Biason
6 years ago
9 changed files with 207 additions and 2 deletions
@ -0,0 +1,28 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Documentation Is a Love Letter To Your Future Self" |
||||||
|
date = 2019-06-21 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "books", "things i learnt", "documentation"] |
||||||
|
+++ |
||||||
|
|
||||||
|
We all know writing the damn docs for functions and classes and modules is a |
||||||
|
pain in the backside. But realizing what you were thinking when you wrote the |
||||||
|
function will save your butt in the future. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
When I say that it will save your butt, I don't mean the documentation will |
||||||
|
tell you something like "Here are the lotto numbers in 2027"[^1] or "If John |
||||||
|
complains about your future code review, here is some shit he did in the |
||||||
|
past". |
||||||
|
|
||||||
|
I mean, it will explain how the _flow_ of your code is expected to do. Imaging |
||||||
|
this: pick your code and replace every function call to its documentation. Can |
||||||
|
you understand what it is expected by reading that? If you can, |
||||||
|
congratulations, you won't have a problem in the future; if you can't... well, |
||||||
|
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") }} |
@ -0,0 +1,26 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Future Thinking is Future Trashing" |
||||||
|
date = 2019-06-21 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "books", "things i learnt", "design", "solution"] |
||||||
|
+++ |
||||||
|
|
||||||
|
When developers try to solve a problem, they sometimes try to find a way that |
||||||
|
will solve all the problems, including the ones that may appear in the future. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
Trying to solve the problems that will appear in the future comes with a hefty |
||||||
|
tax: future problems future will never come -- and, believe me, they _never_ |
||||||
|
come -- and you'll end up either having to maintain a huge behemoth of code |
||||||
|
that will never be fully used or you'll end up rewriting the whole thing |
||||||
|
'cause there is a shitton of unused stuff. |
||||||
|
|
||||||
|
Solve the problem you have right now. Then solve the next one. And the next |
||||||
|
one. At one point, you'll realize there is a pattern emerging from those |
||||||
|
solutions and _then_ you'll find your "solve everything". This pattern is the |
||||||
|
_abstraction_ you're looking for and _then_ you'll be able to solve it in a |
||||||
|
simple way. |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/languages-tests", prev_chapter_title="Good Languages Come With Tests", next_chapter_link="/books/things-i-learnt/document-id", next_chapter_title="Documentation Is a Love Letter To Your Future Self") }} |
@ -0,0 +1,25 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Good Languages Come With Tests" |
||||||
|
date = 2019-06-20 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "books", "things i learnt", "programming languages", "tests"] |
||||||
|
+++ |
||||||
|
|
||||||
|
You can be sure that if a language brings a testing framework -- even minimal |
||||||
|
-- in its standard library, the ecosystem around it will have better tests |
||||||
|
than a language that doesn't carry a testing framework, no matter how good the |
||||||
|
external testing frameworks for the language are. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
The reason is kinda obvious on this one: When the language itself brings a |
||||||
|
testing framework, it reduces the friction for people to start writing tests, |
||||||
|
and that includes the authors of the language itself and the community. |
||||||
|
|
||||||
|
Sure, better frameworks may come along, and languages that don't have a |
||||||
|
testing framework in their standard library may have options with better |
||||||
|
support and easier access but, again, when they are there from the start, the |
||||||
|
start is better and the final result is better. |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/throw-away", prev_chapter_title="Be Ready To Throw Your Code Away", next_chapter_link="/books/things-i-learnt/future-trashing", next_chapter_title="Future Thinking is Future Trashing") }} |
@ -0,0 +1,45 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Tests Make Better APIs" |
||||||
|
date = 2019-06-19 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "book", "things i learnt", "unit tests", "layers", "apis"] |
||||||
|
+++ |
||||||
|
|
||||||
|
Testing things in isolation may give a better view of your APIs. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
When I spoke about [integration |
||||||
|
tests](/books/things-i-learnt/integration-tests) you may end up with the |
||||||
|
impression that I don't like unit tests[^1]. |
||||||
|
|
||||||
|
Actually, I think they provide some good intrinsic values. |
||||||
|
|
||||||
|
For example, as mentioned before, they can provide a better look at the |
||||||
|
adherence to the design. |
||||||
|
|
||||||
|
But, at the same time, they give a better view of your internal -- and even |
||||||
|
external -- APIs. |
||||||
|
|
||||||
|
For example, you're writing the tests for the view layer -- 'cause, you know, |
||||||
|
we write everything in layers; layers on top of layers -- and you're noticing |
||||||
|
that you have to keep a lot of data (state) around to be able to make the |
||||||
|
calls to the controller. That's a sign that you may have to take a better look |
||||||
|
at the controller API. |
||||||
|
|
||||||
|
Not only that, but take, for example, the fact that you're working on a |
||||||
|
library -- which will be called by someone else -- and you're writing tests |
||||||
|
for the most external layer, the layer that will be exposed by the library. |
||||||
|
And, again, you're noticing that you have to keep a lot of context around, |
||||||
|
lots of variables, variables coming from different places and similar calls |
||||||
|
using parameters in different ways. Your tests will look like a mess, don't |
||||||
|
they? That's because the API _is_ a mess. |
||||||
|
|
||||||
|
Unit testing your layers makes you the _user_ of that layer API, and then you |
||||||
|
can see how much one would suffer -- or, hopefully, enjoy -- using that. |
||||||
|
|
||||||
|
[^1]: Again, let's ignore for a second that there are no "unit" in "unit |
||||||
|
tests"... |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/integration-tests", prev_chapter_title="Unit Tests Are Good, Integration Tests Are Gooder", next_chapter_link="/books/things-i-learnt/tests-in-the-command-line", next_chapter_title="Make Tests That You Know How To Run on the Command line") }} |
@ -0,0 +1,37 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Make Tests That You Know How To Run on the Command line" |
||||||
|
date = 2019-06-19 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "book", "things i learnt", "tests", "command line"] |
||||||
|
+++ |
||||||
|
|
||||||
|
You know that "Play" with a little something on your IDE that runs only the |
||||||
|
tests? Do you know what it does? |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
A long time ago I read the story about a professor that taught his students to |
||||||
|
code. He preferred to teach using an IDE, 'cause then "students have to just |
||||||
|
press a button to run the tests". |
||||||
|
|
||||||
|
I get the idea, but I hate the execution. |
||||||
|
|
||||||
|
When we get into professional field, we start using things like [continuous |
||||||
|
integration](https://en.wikipedia.org/wiki/Continuous_integration) which, |
||||||
|
basically, is "run tests every time something changes" (it's a bit more than |
||||||
|
that, but that's the basic idea). |
||||||
|
|
||||||
|
Now, let me ask you this: Do you think the students of the professor above |
||||||
|
would know how to add the command to run the tests in a continuous |
||||||
|
integration system? |
||||||
|
|
||||||
|
I know I'm being too picky (one could even call me "pricky" about this) but |
||||||
|
the fact is that whatever we do today, at some point can be automated: our |
||||||
|
tests can be run in an automated form, our deployment can be run in an |
||||||
|
automated form, our validation can be run in an automated form and so on. If |
||||||
|
you have no idea how those things "happen", you'll need the help of someone |
||||||
|
else to actually build this kind of stuff, instead of having the knowledge |
||||||
|
(well, half knowledge, the other half is the CI tool) with you all the time. |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/tests-apis", prev_chapter_title="Tests Make Better APIs", next_chapter_link="/books/things-i-learnt/throw-away", next_chapter_title="Be Ready To Throw Your Code Away") }} |
@ -0,0 +1,38 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Be Ready To Throw Your Code Away" |
||||||
|
date = 2019-06-19 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "book", "things i learnt", "code"] |
||||||
|
+++ |
||||||
|
|
||||||
|
A lot of people, when they start with TDD, get annoyed when you say that you |
||||||
|
may have to rewrite a lot of stuff, including whatever your already wrote. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
TDD was _designed_ to throw code away: The more you learn about your problem, |
||||||
|
the more you understand that, whatever you wrote, won't solve the problem in |
||||||
|
the long run. |
||||||
|
|
||||||
|
You shouldn't worry about this. Your code is not a wall: if you have to throw |
||||||
|
it always, it is not wasted material. Surely it means your time writing code |
||||||
|
was lost, but you got a better understanding about the problem now. |
||||||
|
|
||||||
|
Not only that, but as you progress through your project, solving problems and |
||||||
|
getting "acquainted" with the problem, you'll also notice that the |
||||||
|
[spec](/books/things-i-learnt/spec-first) will also change. This means that the problem you solved |
||||||
|
wasn't exactly the problem you _needed_ to solve; your code is trying to solve |
||||||
|
something that isn't exactly the problem. |
||||||
|
|
||||||
|
Also, this is really common -- the spec changing, not throwing the code away, |
||||||
|
that is. One thing that you can be sure is that it won't change _everywhere_. |
||||||
|
Some of the things you solved will stay the same, some others will be |
||||||
|
completely removed and some others added. And you will see that you'll |
||||||
|
refactor your code a lot, and throw a lot of code away. And not just code that |
||||||
|
solves the problem, but also the tests for that code. |
||||||
|
|
||||||
|
... unless you focus mostly on [integration |
||||||
|
tests](/books/things-i-learnt/integration-tests). |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/tests-in-the-command-line", prev_chapter_title="Make Tests That You Know How To Run on the Command line", next_chapter_link="/books/things-i-learnt/language-tests", next_chapter_title="Good Languages Come With Tests") }} |
Loading…
Reference in new issue