Julio Biason
6 years ago
10 changed files with 335 additions and 9 deletions
@ -1,8 +1,13 @@ |
|||||||
+++ |
+++ |
||||||
title = "My Books" |
title = "My Books" |
||||||
template = "section-contentless.html" |
template = "section-contentless.html" |
||||||
|
transparent = true |
||||||
+++ |
+++ |
||||||
|
|
||||||
## Portuguese/Português |
## Portuguese/Português |
||||||
|
|
||||||
* [Uma Lição de Vim](uma-licao-de-vim) |
* [Uma Lição de Vim](uma-licao-de-vim) |
||||||
|
|
||||||
|
## English/Inglês |
||||||
|
|
||||||
|
* [Things I Learnt The Hard Way](things-i-learnt) |
||||||
|
@ -0,0 +1,14 @@ |
|||||||
|
+++ |
||||||
|
transparent = true |
||||||
|
title = "Things I Learnt The Hard Way (In 30 Years of Software Development)" |
||||||
|
template = "section-contentless.html" |
||||||
|
+++ |
||||||
|
|
||||||
|
* [Intro](intro) |
||||||
|
* [Disclaimer](disclaimer) |
||||||
|
|
||||||
|
* Programming: |
||||||
|
* [Spec First, Then Code](spec-first) |
||||||
|
* [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) |
@ -0,0 +1,42 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Disclaimer" |
||||||
|
date = 2019-06-19 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "books", "things i learnt", "disclaimer"] |
||||||
|
+++ |
||||||
|
|
||||||
|
There is one magical thing you need to know when reading this book: It's all |
||||||
|
personal opinion |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
A lot of stuff I'm going to discuss throughout this book will come directly |
||||||
|
from my personal experience in several projects -- system applications, web |
||||||
|
backend, embedded, mobile, stream processing -- in several different languages |
||||||
|
-- C, C++, Python, Java. And, because it comes from personal experience, |
||||||
|
everything reflects my own personal opinion on several subjects. |
||||||
|
|
||||||
|
Obviously, you don't need to agree with every single point. |
||||||
|
|
||||||
|
Also, sometimes I may mention some examples that people who know me -- either |
||||||
|
worked with me, heard me complain about some project, inherit one of my |
||||||
|
projects, _I_ inherit one of the _their_ projects -- may recognized and think |
||||||
|
I'm attacking the author. |
||||||
|
|
||||||
|
I am not. |
||||||
|
|
||||||
|
We do mistakes. Sometimes we don't know the topic with are attacking, |
||||||
|
sometimes we don't have full specs, sometimes we don't have the time to write |
||||||
|
things properly in a crunchtime. And that's why some things don't look as |
||||||
|
pretty as they should. Heck, if you think I'm attacking the original author of |
||||||
|
some example, look back the stuff I wrote and you'll see things a lot worse. |
||||||
|
|
||||||
|
But I need the example. I want to show people how things can be better. I want |
||||||
|
to show people how my opinion built over some subject. And, again, I'm in no |
||||||
|
way attacking the original author of the code. I may even call the code |
||||||
|
"stupid", but I'm not calling the author _stupid_. |
||||||
|
|
||||||
|
With that in mind... |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/intro", prev_chapter_title = "Intro", next_chapter_link="/books/things-i-learnt/spec-first", next_chapter_title="Spec First, The Code") }} |
@ -0,0 +1,54 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Gherkin Is Your Friend to Understand Expectations" |
||||||
|
date = 2019-06-19 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "book", "things i learnt", "gherkin", "expectations"] |
||||||
|
+++ |
||||||
|
|
||||||
|
Gherkin is file format for writing behaviour tests. But it can also give you |
||||||
|
some insights on what you should do. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
Alright, let's talk a bit about Gherkin: |
||||||
|
|
||||||
|
[Gherkin](https://en.wikipedia.org/wiki/Cucumber_(software)#Gherkin_language) |
||||||
|
is a file format created for [Cucumber](https://en.wikipedia.org/wiki/Cucumber_(software)), |
||||||
|
which describes scenarios, what's in them, what actions the user/system will |
||||||
|
do and what's expected after those actions, in a very high level, so people |
||||||
|
without programming experience can describe what's expected from the system. |
||||||
|
|
||||||
|
Although Gherkin was born with Cucumber, it is now supported by a bunch of |
||||||
|
programming languages, through external libraries. |
||||||
|
|
||||||
|
A typical Gherkin file may look something like this: |
||||||
|
|
||||||
|
* **Given that** _initial system environment_ |
||||||
|
* **When** _action performed by the user or some external system_ |
||||||
|
* **Then** _expected system environment_ |
||||||
|
|
||||||
|
Or, in a more concrete example: |
||||||
|
|
||||||
|
* **Given that** The system is retrieving all tweets favourited by the user |
||||||
|
* **When** It finds a tweet with an attachment |
||||||
|
* **Then** The attachment should be saved along the tweet text |
||||||
|
|
||||||
|
Pretty simple, right? |
||||||
|
|
||||||
|
Now, why I'm mentioning this? |
||||||
|
|
||||||
|
Sometimes, specs are not the most clear source of information about what it is |
||||||
|
expected from the system. If you're confused about what you should write, |
||||||
|
asking the person responsible for the request to write something like Gherkin |
||||||
|
may give you some better insights about it. |
||||||
|
|
||||||
|
Obviously, it won't be complete. People tend to forget the error situations -- |
||||||
|
people entering just numbers on names, letter in age fields, tweets with no |
||||||
|
text and just attachments -- but at least with a Gherkin description of the |
||||||
|
system, you can get a better picture of the whole. |
||||||
|
|
||||||
|
Also, you may not like to write specs. That's alright, you can replace them |
||||||
|
with Gherkin anyway. |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/steps-as-comments", prev_chapter_title="Write Steps as Comments", next_chapter_link="/books/things-i-learnt/integration-tests", next_chapter_title="Unit Tests Are Good, Integration Tests Are Gooder") }} |
@ -0,0 +1,69 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Unit Tests Are Good, Integration Tests Are Gooder" |
||||||
|
date = 2019-06-19 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "book", "things i learnt", "unit tests", "integration tests"] |
||||||
|
+++ |
||||||
|
|
||||||
|
The view of the whole is greater than the sum of its parts. And that includes |
||||||
|
tests for the whole compared to tests of single things. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
First, I just don't want to into a discussion about what's the "unit in a unit |
||||||
|
test"[^1], so let's take the point that a unit test is a test that tests a |
||||||
|
class/function, not the whole system, which would require data flowing through |
||||||
|
several classes/functions. |
||||||
|
|
||||||
|
There are several libraries/frameworks that actually split this in a way that |
||||||
|
you can't test the whole. |
||||||
|
[Spring](https://spring.io/)+[Mockito](https://site.mockito.org/) is one of |
||||||
|
those combinations -- and one that I worked with. Due the bean container of |
||||||
|
Java, the extensive use of Beans by Spring and the way Mockito interacts with |
||||||
|
the container, it's pretty easy to write tests that involve only one class: |
||||||
|
You can ask Mockito to mock every dependency injection in one class and mock |
||||||
|
every injected class, simply using annotations. |
||||||
|
|
||||||
|
And this is cool and all. But the fact that we are making sure each class does |
||||||
|
what it does, it doesn't give a proper view of the whole; you can't see if |
||||||
|
that collection of perfectly tested classes actually solve the problem the |
||||||
|
system is responsible for solving. |
||||||
|
|
||||||
|
Once, in C++, I wrote an alarm system |
||||||
|
[daemon](https://en.wikipedia.org/wiki/Daemon_(computing)) for switches. There |
||||||
|
were three different levels of things the alarm system should do: It could |
||||||
|
only log the message of the incoming error, it could log the error and send a |
||||||
|
SNMP message, or it could log the error, send a SNMP message and turn a LED in |
||||||
|
the front panel on. Because each piece had a well defined functionality, we |
||||||
|
broke the system in three different parts: One for the log, one for the SNMP |
||||||
|
and one for the LED. All tested, all pretty. But I still had a nagging |
||||||
|
feeling that something was missing. That's when I wrote a test that would |
||||||
|
bring the daemon up, send some alarms and see the results. |
||||||
|
|
||||||
|
And, although each module was well tested, we still got one things we were |
||||||
|
doing it wrong. If we never wrote an integration test, we would never catch |
||||||
|
that. |
||||||
|
|
||||||
|
Not only that, but because we wrote a test that interacted with the daemon, we |
||||||
|
could get a better picture of its functionality and the test actually _made |
||||||
|
sense_ -- as in, if you read the unit tests, they seemed disconnected from |
||||||
|
what the daemon was expected to do, but the integration tests actually read |
||||||
|
like "Here, let me show that we actually did what you asked". And yes, this |
||||||
|
was akin to [Gherkin](/books/things-i-learnt/gherkin) tests, although I didn't |
||||||
|
know Gherkin at the time. |
||||||
|
|
||||||
|
Personally, I think over time integration tests are more important that unit |
||||||
|
tests. The reason is that I still have the feeling that unit tests check if |
||||||
|
the classes/functions have _adherence_ to the underlying _design_ -- Does your |
||||||
|
view can actually work without the controller? Is the controller using |
||||||
|
something from the model or using things that should be in the view? -- but |
||||||
|
adherence to the design gets better over time -- developers start using the |
||||||
|
layout from previous examples, so they capture the design by osmosis, while |
||||||
|
the big picture starts to get more and more complex, with lots of moving |
||||||
|
parts. |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/gherkin", prev_chapter_title="Gherkin Is Your Friend to Understand Expectations") }} |
||||||
|
|
||||||
|
[^1]: There is no "unit" in "unit tests". "Unit test" means the test _is_ a |
||||||
|
unit, indivisible and dependent only on itself. |
@ -0,0 +1,52 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Intro" |
||||||
|
date = 2019-06-18 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "books", "things i learnt", "intro"] |
||||||
|
+++ |
||||||
|
|
||||||
|
"Things I Learnt The Hard Way (In 30 Years of Software Development)" started |
||||||
|
as a simple sequence of toots (the same as "tweets", but outside Twitter) when |
||||||
|
I was thinking about a new presentation I could do. |
||||||
|
|
||||||
|
But why "a new presentation"? |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
I go around my state with a group called "Tchelinux": We usually go to |
||||||
|
universities and talk to people starting uni, explaining things about |
||||||
|
free/libre software and sometimes telling people about things they wouldn't |
||||||
|
normally see in the uni curriculum. |
||||||
|
|
||||||
|
One thing that annoys me is that there are very few presentations about "when |
||||||
|
things go wrong". All the presentations are either prototypes or tell the good |
||||||
|
stuff, and hide all the wrong things that could happen[^1]. Obviously, after |
||||||
|
working 30 years in the field of software development, I saw my fair share of |
||||||
|
things going wrong -- sometimes in unimaginable piles of crap -- and I thought |
||||||
|
"maybe that's something people would like to hear". |
||||||
|
|
||||||
|
And that's when the toot sequence started. Just before I noticed, I spent the |
||||||
|
whole day just posting this kind of stuff (fortunately, my pile of "incoming" |
||||||
|
was a bit empty at the time) and it had 30 points, plus addendums and a few |
||||||
|
explanation points. That's when I decided to group all them in a single post. |
||||||
|
|
||||||
|
All I thought when I grouped everything in a post was "this will make things |
||||||
|
easier for the people following the thread on Mastodon". But then the post |
||||||
|
appeared on Reddit. And Twitter. And HackerNews. And YCombinator. And none of |
||||||
|
those where mine. |
||||||
|
|
||||||
|
But here is the thing: Each point was limited by the toot size, which is 500 |
||||||
|
characters. Sometimes that's not enough to expand the point, explain it |
||||||
|
properly and add some examples. |
||||||
|
|
||||||
|
And that's how the idea to write this "book" came to life. |
||||||
|
|
||||||
|
One thing you must keep in mind here: *These are my options*. I understand |
||||||
|
that not everything is so black and white as put here, and some people's |
||||||
|
experiences may not match things here. Also, you get a bit cynical about |
||||||
|
technology after 30 years. So... thread carefully, 'cause here be dragons. |
||||||
|
|
||||||
|
[^1]: Yup, I'm guilty of that too. |
||||||
|
|
||||||
|
{{ chapters(next_chapter_link="/books/things-i-learnt/disclaimer", next_chapter_title="Disclaimer") }} |
@ -0,0 +1,40 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Spec First, Then Code" |
||||||
|
date = 2019-06-18 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "books", "things i learnt", "specs", "code"] |
||||||
|
+++ |
||||||
|
|
||||||
|
"Without requirements or design, programming is the art of adding bugs to an |
||||||
|
empty text file." -- Louis Srygley |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
If you don't know what you're trying to solve, you don't know what to code. |
||||||
|
|
||||||
|
A lot of times we have this feeling of "let me jump straight to the code". But |
||||||
|
without understanding what problem you're trying to solve, you'd end up |
||||||
|
writing a bunch of things that doesn't solve anything -- or, at least, |
||||||
|
anything that _should_ be solved. |
||||||
|
|
||||||
|
So here is the point: Try to get a small spec on whatever you want to solve. |
||||||
|
But be aware that even that spec may have to be thrown out, as the |
||||||
|
understanding of the problem tend to grow as long as the project continue. |
||||||
|
|
||||||
|
Yes, it's paradoxical: You need a spec to know what to code to avoid coding |
||||||
|
the wrong solution, but the spec may be wrong, so you _end up_ solving the |
||||||
|
wrong solution anyway. So what's the point? The point is, the spec reflects |
||||||
|
the understanding of a problem _at a certain point_: All you (and your team) |
||||||
|
know is _there_. |
||||||
|
|
||||||
|
The times I stood longer looking at my own code wondering what to do next were |
||||||
|
when we didn't have the next step defined: It was missing some point of the |
||||||
|
solution or we didn't have the communication structures defined or something |
||||||
|
of sorts. Usually, when that happened, I stumbled upon Twitter or Mastodon |
||||||
|
instead of trying to solve the problem. So when you see yourself doing this |
||||||
|
kind of stuff -- "I don't know what to do next, and I'm not sure if I'm done |
||||||
|
with the current problem" -- then maybe it's time to stop and talk to other |
||||||
|
people in the project to figure that out. |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/disclaimer", prev_chapter_title="Disclaimer", next_chapter_link="/books/things-i-learnt/steps-as-comments", next_chapter_title="Write Steps as Comments") }} |
@ -0,0 +1,58 @@ |
|||||||
|
+++ |
||||||
|
title = "Things I Learnt The Hard Way - Write Steps as Comments" |
||||||
|
date = 2019-06-18 |
||||||
|
|
||||||
|
[taxonomies] |
||||||
|
tags = ["en-au", "books", "things i learnt", "steps", "comments", "code"] |
||||||
|
+++ |
||||||
|
|
||||||
|
Don't know how to solve your problem? Write the steps as comments in your |
||||||
|
code. |
||||||
|
|
||||||
|
<!-- more --> |
||||||
|
|
||||||
|
There you are, looking at the blank file wondering how you're going to solve |
||||||
|
that problem. Here is a tip: |
||||||
|
|
||||||
|
Take the spec you (or someone else) wrote. Break each point into a series of |
||||||
|
steps to reach the expected content. You can even write on your natural |
||||||
|
language, if you don't speak English. |
||||||
|
|
||||||
|
Then fill the spaces between the comments with code. |
||||||
|
|
||||||
|
For example, if you have a spec of "connect to server X and retrieve |
||||||
|
everything there. You should save the content in the database. Remember that |
||||||
|
server X has an API that you can pass an ID (the last ID seen) and you can use |
||||||
|
it to not retrieve the same content again." Pretty simple, right? |
||||||
|
|
||||||
|
Now, writing this in comments, pointing the steps you need to make: |
||||||
|
|
||||||
|
``` |
||||||
|
// connect to server X |
||||||
|
// retrieve posts |
||||||
|
// send posts to the database |
||||||
|
``` |
||||||
|
|
||||||
|
Ah, you forgot the part about the ID. No problem, you just have to add it in |
||||||
|
the proper places -- for example, it doesn't make sense to connect to the |
||||||
|
server before you have the last seen ID: |
||||||
|
|
||||||
|
``` |
||||||
|
// open configuration file |
||||||
|
// get value of the last seen ID; if it doesn't exist, it's empty. |
||||||
|
// connect to server X |
||||||
|
// retrieve posts starting at the last seen ID |
||||||
|
// send posts to the database |
||||||
|
// save the last seen ID in the configuration file |
||||||
|
``` |
||||||
|
|
||||||
|
Now it is "easy"[^1]: You just add the code after each comment. |
||||||
|
|
||||||
|
A better option is to change the comments into functions and, instead of |
||||||
|
writing the code between the comments, you write the functionality in the |
||||||
|
function themselves and keep a clean view of what your application does in the |
||||||
|
main code. |
||||||
|
|
||||||
|
[^1]: Yes, that was sarcastic. |
||||||
|
|
||||||
|
{{ chapters(prev_chapter_link="/books/things-i-learnt/spec-first", prev_chapter_title="Specs First, Then Code", next_chapter_link="/books/things-i-learnt/gherkin", next_chapter_title="Gherkin Is Your Friend to Understand Expectations") }} |
Loading…
Reference in new issue