diff --git a/config.toml b/config.toml index 330760b..dcb5bf0 100644 --- a/config.toml +++ b/config.toml @@ -34,11 +34,3 @@ after_dark_menu = [ {url = "$BASE_URL/books", name = "Books"}, ] after_dark_title = "JulioBiason.Net 4.0" - -hyde_links = [ - {name = "Category: Book Reviews", url = "/reviews/books"}, - {name = "Category: Code", url = "/code"}, - {name = "Category: Reviews", url = "/reviews"}, - {name = "Tags", url = "/tags"}, -] -hyde_reverse = true diff --git a/content/books/_index.md b/content/books/_index.md index d7f8a96..4dd7768 100644 --- a/content/books/_index.md +++ b/content/books/_index.md @@ -1,8 +1,13 @@ +++ title = "My Books" template = "section-contentless.html" +transparent = true +++ ## Portuguese/Português * [Uma Lição de Vim](uma-licao-de-vim) + +## English/Inglês + +* [Things I Learnt The Hard Way](things-i-learnt) diff --git a/content/books/things-i-learnt/_index.md b/content/books/things-i-learnt/_index.md new file mode 100644 index 0000000..2b90585 --- /dev/null +++ b/content/books/things-i-learnt/_index.md @@ -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) diff --git a/content/books/things-i-learnt/disclaimer/index.md b/content/books/things-i-learnt/disclaimer/index.md new file mode 100644 index 0000000..4281987 --- /dev/null +++ b/content/books/things-i-learnt/disclaimer/index.md @@ -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 + + + +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") }} diff --git a/content/books/things-i-learnt/gherkin/index.md b/content/books/things-i-learnt/gherkin/index.md new file mode 100644 index 0000000..4e8ae9b --- /dev/null +++ b/content/books/things-i-learnt/gherkin/index.md @@ -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. + + + +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") }} diff --git a/content/books/things-i-learnt/integration-tests/index.md b/content/books/things-i-learnt/integration-tests/index.md new file mode 100644 index 0000000..1df6682 --- /dev/null +++ b/content/books/things-i-learnt/integration-tests/index.md @@ -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. + + + +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. diff --git a/content/books/things-i-learnt/intro/index.md b/content/books/things-i-learnt/intro/index.md new file mode 100644 index 0000000..138f1fd --- /dev/null +++ b/content/books/things-i-learnt/intro/index.md @@ -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"? + + + +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") }} diff --git a/content/books/things-i-learnt/spec-first/index.md b/content/books/things-i-learnt/spec-first/index.md new file mode 100644 index 0000000..046626c --- /dev/null +++ b/content/books/things-i-learnt/spec-first/index.md @@ -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 + + + +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") }} diff --git a/content/books/things-i-learnt/steps-as-comments/index.md b/content/books/things-i-learnt/steps-as-comments/index.md new file mode 100644 index 0000000..637a12e --- /dev/null +++ b/content/books/things-i-learnt/steps-as-comments/index.md @@ -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. + + + +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") }} diff --git a/themes/nighttime b/themes/nighttime index e1f25d3..658e800 160000 --- a/themes/nighttime +++ b/themes/nighttime @@ -1 +1 @@ -Subproject commit e1f25d33deadd983fd47e24a2fe6546824bd894b +Subproject commit 658e800a1a1cecd1ab382e17dbab3bd6bba4e2ec