Browse Source

Merge branch 'hotfix/20190705.1'

master 20190705.1
Julio Biason 5 years ago
parent
commit
36126c9672
  1. 2
      content/books/things-i-learnt/_index.md
  2. 6
      content/books/things-i-learnt/boolean-parameters/index.md
  3. 2
      content/books/things-i-learnt/cargo-cult/index.md
  4. 12
      content/books/things-i-learnt/crash-it/index.md
  5. 15
      content/books/things-i-learnt/data-types/index.md
  6. 7
      content/books/things-i-learnt/document-and/index.md
  7. 24
      content/books/things-i-learnt/document-is-contract/index.md
  8. 10
      content/books/things-i-learnt/document-it/index.md
  9. 9
      content/books/things-i-learnt/future-trashing/index.md
  10. 6
      content/books/things-i-learnt/handle-it/index.md
  11. 4
      content/books/things-i-learnt/interface-changes/index.md
  12. 21
      content/books/things-i-learnt/languages-are-more/index.md
  13. 22
      content/books/things-i-learnt/log-events/index.md
  14. 12
      content/books/things-i-learnt/outside-project/index.md
  15. 8
      content/books/things-i-learnt/resist-easy/index.md
  16. 5
      content/books/things-i-learnt/start-stupid/index.md
  17. 17
      content/books/things-i-learnt/tests-apis/index.md
  18. 32
      content/books/things-i-learnt/throw-away/index.md
  19. 16
      content/books/things-i-learnt/use-structures/index.md
  20. 15
      content/books/things-i-learnt/use-timezones/index.md
  21. 28
      content/books/things-i-learnt/use-utf8/index.md

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

@ -39,9 +39,9 @@ template = "section-contentless.html"
* [If Your Data Has a Schema, Use a Structure](use-structures) * [If Your Data Has a Schema, Use a Structure](use-structures)
* [Don't Mess With Things Outside Your Project](outside-project) * [Don't Mess With Things Outside Your Project](outside-project)
* [Resist The Temptation Of Easy](resist-easy) * [Resist The Temptation Of Easy](resist-easy)
* [Start Stupid](start-stupid)
* [Always Use Timezones With Your Dates](use-timezones) * [Always Use Timezones With Your Dates](use-timezones)
* [Always Use UTF-8 For Your Strings](use-utf8) * [Always Use UTF-8 For Your Strings](use-utf8)
* [Start Stupid](start-stupid)
* [Logs Are For Events, Not User Interface](log-events) * [Logs Are For Events, Not User Interface](log-events)
* Community/Teams * Community/Teams
* [A Language Is Much More Than A Language](languages-are-more) * [A Language Is Much More Than A Language](languages-are-more)

6
content/books/things-i-learnt/boolean-parameters/index.md

@ -6,8 +6,8 @@ date = 2019-06-23
tags = ["en-au", "books", "things i learnt", "booleans", "functions", "parameters"] tags = ["en-au", "books", "things i learnt", "booleans", "functions", "parameters"]
+++ +++
When you're designing a function, you may be tempted to add a flag. Don't do When you're designing a function, you may be tempted to add a flag (a
this. parameter in a function that it is a boolean). Don't do this.
<!-- more --> <!-- more -->
@ -27,6 +27,6 @@ another `getUserMessagesFull` or something around those lines, but each
function just call the original `getUserMessage` with true or false -- but the function just call the original `getUserMessage` with true or false -- but the
interface to the outside of your class/module will still be clear. interface to the outside of your class/module will still be clear.
But _don't_ add flags/Boolean parameters to your functions. But _don't_ add flags/Boolean parameters to your API.
{{ 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/interface-changes", next_chapter_title="Beware of Interface Changes") }} {{ 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/interface-changes", next_chapter_title="Beware of Interface Changes") }}

2
content/books/things-i-learnt/cargo-cult/index.md

@ -14,7 +14,7 @@ same results as a real airplane.
<!-- more --> <!-- more -->
In I.T., a "cargo cult" is the expectation that if you use the same tools as In IT, a "cargo cult" is the expectation that if you use the same tools as
some big players, you'd end up getting the same results. some big players, you'd end up getting the same results.
One example: Netflix runs a large fleet of microservices daily; they use One example: Netflix runs a large fleet of microservices daily; they use

12
content/books/things-i-learnt/crash-it/index.md

@ -36,4 +36,16 @@ of error handling -- as long as you don't have any idea on how to handle it.
Then, when they crash, you can think of a way to deal with it, instead of Then, when they crash, you can think of a way to deal with it, instead of
silently capturing it and doing nothing. silently capturing it and doing nothing.
Also, keep in mind to not go forth and capture _every_ exception/error in a
single take -- like the example above, which will capture every exception, or
like `except Exception` in Python. This last example actually happened to me
when another developer added this "broad except"[^1] in a network code and, at
some point, the code would get into the capture all the time. We checked every
cable, every connection, every interface, till I noticed there was a syntax
error in the code. In Python, syntax errors raise exceptions and, because we
had a "capture all exceptions", we lost some pretty good time looking for the
problem in the wrong place.
[^1]: As called by Pylint.
{{ chapters(prev_chapter_link="/books/things-i-learnt/interface-changes", prev_chapter_title="Beware of Interface Changes", next_chapter_link="/books/things-i-learnt/handle-it", next_chapter_title="If You Know How To Handle It, Handle It") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/interface-changes", prev_chapter_title="Beware of Interface Changes", next_chapter_link="/books/things-i-learnt/handle-it", next_chapter_title="If You Know How To Handle It, Handle It") }}

15
content/books/things-i-learnt/data-types/index.md

@ -22,19 +22,20 @@ typing. The same still applies.
One classic example of misusing types is adding booleans. Booleans are either One classic example of misusing types is adding booleans. Booleans are either
`true` or `false`, but because most languages follow C, which doesn't have a `true` or `false`, but because most languages follow C, which doesn't have a
boolean type and uses compiler pre-processors to define `TRUE` as an integer boolean type and uses compiler pre-processors to define `TRUE` as an integer
with the value `1` and `FALSE` with another integer with the value `0`. And with the value `1` and `FALSE` with another integer with the value `0`. Newer
so, the build on top of what older developers knew, other languages use the languages were build on top of what older developers knew, and so, a bunch of
same concepts. And so, you have a list of booleans and want to know how many those languages also assumed using an integer under booleans was a good idea.
true values are in the list, you can simply add them all. And even today, with modern languages, people rely on those old methods.
Let me point that again: You're adding booleans and expecting a number. Let me repeat that: You're adding booleans and expecting a number -- only
because in the old times there wasn't boolean types.
No, you're counting the number of elements in the list 'cause that would see No, you're counting the number of elements in the list 'cause that would see
the whole list. You're not even filtering the false values over and counting the whole list. You're not even filtering the false values over and counting
the resulting list size. You're jumping the underlying type to get a bit of the resulting list size. You're jumping the underlying type to get a bit of
performance out. performance out.
Fortunately, new languages are based on ML, which wouldn't allow this kind of Fortunately, some new languages are using booleans as a complete different
stuff. type and wouldn't allow this kind of stuff.
{{ chapters(prev_chapter_link="/books/things-i-learnt/handle-it", prev_chapter_title="If You Know How To Handle It, Handle It", next_chapter_link="/books/things-i-learnt/use-structures", next_chapter_title="If Your Data Has a Schema, Use a Structure") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/handle-it", prev_chapter_title="If You Know How To Handle It, Handle It", next_chapter_link="/books/things-i-learnt/use-structures", next_chapter_title="If Your Data Has a Schema, Use a Structure") }}

7
content/books/things-i-learnt/document-and/index.md

@ -13,9 +13,9 @@ documentation.
<!-- more --> <!-- more -->
This is kind like "sometimes rule", but most of the time, when you feel you This is kind like "sometimes rule", but most of the time, when you feel you
need to add and "and" to the function documentation (it's need to add an "and" to the function documentation (its
[contract](/books/things-i-learnt/document-is-contract)), then you're telling [contract](/books/things-i-learnt/document-is-contract)), then you're telling
that that function is doing two (or more things). that that function is doing two (or more) things.
One of guiding principles of good code is the [Single responsibility One of guiding principles of good code is the [Single responsibility
principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), in principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), in
@ -27,6 +27,7 @@ Ok, but what now? Well, you have two functions, with two distinct contracts.
Ok, but you _had_ those two being called, what happens now? Well, where you Ok, but you _had_ those two being called, what happens now? Well, where you
called one, you now will need to call two. If your preferred language have called one, you now will need to call two. If your preferred language have
support for function composition, you can use that to group both functions support for function composition, you can use that to group both functions
again. again. This is the kind of stuff that you'll get when you [learn to use
functional programming](/books/things-i-learnt/functional-programming).
{{ chapters(prev_chapter_link="/books/things-i-learnt/document-is-contract", prev_chapter_title="The Function Documentation Is Its Contract", next_chapter_link="/books/things-i-learnt/languages-docs", next_chapter_title="Good Languages Come With Integrated Documentation") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/document-is-contract", prev_chapter_title="The Function Documentation Is Its Contract", next_chapter_link="/books/things-i-learnt/languages-docs", next_chapter_title="Good Languages Come With Integrated Documentation") }}

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

@ -6,24 +6,24 @@ date = 2019-06-21
tags = ["en-au", "books", "things i learnt", "documentation", "contracts"] tags = ["en-au", "books", "things i learnt", "documentation", "contracts"]
+++ +++
When you start the code by [writing the When you start the code by [writing the general flow as
documentation](/books/things-i-learnt/steps-as-comments), you're actually steps](/books/things-i-learnt/steps-as-comments) and making each step a
making a contract (probably with your future self): I'm saying this function function, you're actually making a contract (probably with your future self):
does _this_ and _this_ is what it does. I'm saying this function does _this_ and _this_ is what it does.
<!-- more --> <!-- more -->
Remember that the documentation must be a clear explanation of what your code 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 _is_ doing and _why_ it exists; remember that good messages will make [reading
the function documentation](/books/things-i-learnt/document-id) should be the code only by the function documentation](/books/things-i-learnt/document-id)
clear. should be clear.
A function called `mult`, documented as "Get the value and multiply by 2" but, 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 when you look at the code, it does multiply by 2, but also sends the result
the network or even just asks a remote service to multiply the incoming result through the network or even just asks a remote service to multiply the
by 2, is clearly breaking its contract. It's not just multiplying by 2, it's incoming result by 2, is clearly breaking its contract. It's not just
doing more than just that, or it's asking someone else to manipulate the multiplying by 2, it's doing more than just that, or it's asking someone else
value. to manipulate the value.
Now, what happens when this kind of thing happens? Now, what happens when this kind of thing happens?

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

@ -23,6 +23,16 @@ 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, congratulations, you won't have a problem in the future; if you can't... well,
I have some bad news for you... I have some bad news for you...
One point that may come here is "Code is its own documentation" or
"self-documenting code". I do understand, and yes, simpler functions may make
the documentation redundant (for example, if you notice that you need a
function that multiplies two numbers -- and only do that -- giving it a
description of "Multiples two numbers" may look redundant), but you have to
ask yourself _why_ you needed such simple function. _Why_ it exists? _Where_
it sits in the general data flow?
That's the things you need to document.
[^1]: Please, don't make me revise this in 2027... :( [^1]: Please, don't make me revise this in 2027... :(
{{ 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-is-contract", next_chapter_title="The Function Documentation Is Its Contract") }} {{ 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-is-contract", next_chapter_title="The Function Documentation Is Its Contract") }}

9
content/books/things-i-learnt/future-trashing/index.md

@ -12,9 +12,9 @@ will solve all the problems, including the ones that may appear in the future.
<!-- more --> <!-- more -->
Trying to solve the problems that will appear in the future comes with a hefty 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_ tax: future problems future will never come -- and, believe me, they will
come -- and you'll end up either having to maintain a huge behemoth of code _never_ come -- and you'll end up either having to maintain a huge behemoth of
that will never be fully used or you'll end up rewriting the whole thing code that will never be fully used or you'll end up rewriting the whole thing
'cause there is a shitton of unused stuff. 'cause there is a shitton of unused stuff.
Solve the problem you have right now. Then solve the next one. And the next Solve the problem you have right now. Then solve the next one. And the next
@ -23,4 +23,7 @@ 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 _abstraction_ you're looking for and _then_ you'll be able to solve it in a
simple way. simple way.
As Steve Jobs once said "You can't connect the dots looking forward, only
backwards".
{{ 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/boolean-parameters", next_chapter_title="Don't Use Booleans As Parameters") }} {{ 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/boolean-parameters", next_chapter_title="Don't Use Booleans As Parameters") }}

6
content/books/things-i-learnt/handle-it/index.md

@ -23,9 +23,9 @@ handle, no exceptions -- and tying with the previous point, if you don't know
how to handle them, you should not capture them in the first place. how to handle them, you should not capture them in the first place.
But, no matter what language you're using, if you know an error/exception can But, no matter what language you're using, if you know an error/exception can
occur, _deal with it_. If you have to save the save the content of the user occur, _deal with it_. If you have to save the content of the user somewhere
somewhere else, log it to be reprocessed later or even just show an error else, log it to be reprocessed later or even just show an error message, do
message, do it. it.
Although I seriously meant it, it doesn't mean you have to remember every Although I seriously meant it, it doesn't mean you have to remember every
single exception/error code and what it means when calling a function. You can single exception/error code and what it means when calling a function. You can

4
content/books/things-i-learnt/interface-changes/index.md

@ -7,7 +7,7 @@ tags = ["en-au", "books", "things i learnt", "interfaces", "apis"]
+++ +++
Interfaces and APIs is what you give away to others. If you keep changing them, Interfaces and APIs is what you give away to others. If you keep changing them,
you'll make everyone's life a sad life. you'll make everyone's life sad.
<!-- more --> <!-- more -->
@ -25,7 +25,7 @@ you can see these kind of changes happening and you can see the kind of
changes you're doing on how they reflect externally. changes you're doing on how they reflect externally.
You can create the new functions and mark the current one as deprecated, You can create the new functions and mark the current one as deprecated,
either by documentation or by some code feature. Then, after a few released, either by documentation or by some code feature. Then, after a few releases,
you can finally kill the original function. you can finally kill the original function.
(A dickish move you can do is to create the new functions, mark the current (A dickish move you can do is to create the new functions, mark the current

21
content/books/things-i-learnt/languages-are-more/index.md

@ -16,17 +16,17 @@ Programming languages, in essence, are simply a bunch of keywords that make
things "go". But besides those keywords, they also bring their community, the things "go". But besides those keywords, they also bring their community, the
way the leaders deal with the community, the tools created by the leaders or way the leaders deal with the community, the tools created by the leaders or
community to deal with the minutiae of creating a system, the way those tools community to deal with the minutiae of creating a system, the way those tools
interact with each other. interact with each other, and a lot more.
While a language may have a simple syntax, it may be that the ones controlling While a language may have a simple syntax, it may be that the ones controlling
the language actually don't give two shits -- if you pardon my French -- to the language actually don't give two shits -- if you pardon my French -- to
the community. They focus on solving _their_ problems, not the community the community. They focus on solving _their_ problems, not the community
problems. problems[^1].
Or maybe the community has duplicate tools -- which is not a problem -- but Or maybe the community has duplicate tools -- which is not a problem -- but
that developers of each tool don't talk to each other. Or worse: They simply that developers of each tool don't talk to each other. Or worse: They simply
refuse to look what other tools are doing, which could be used to improve refuse to look what other tools are doing, which could be used to improve
their own. their own[^2].
And maybe that third language is not as simple as others, but the leadership And maybe that third language is not as simple as others, but the leadership
is always discussing things with the community, being transparent on their is always discussing things with the community, being transparent on their
@ -39,4 +39,19 @@ surface of what the whole of a language encapsulates and if you ignore the
other elements in it, you may find yourself with a cute language in a other elements in it, you may find yourself with a cute language in a
community that is always fighting and never going forward. community that is always fighting and never going forward.
And picking a language for something _above_ the syntax is even worse.
[^1]: Yes, this is common, even in larger communities. And yes, I've seen the
leadership ignoring requests from the community and, sometimes, just
ignoring all the hard work the community did to supply the missing bits
because they didn't like it.
[^2]: Again, I've seen this before: There was a language that didn't come with
a build tool bundled. The community created a tool, which was widely
adopted. Later, a new build tool appeared and, in one of the notes, the
author of the new tool mentioned a feature. The community came and asked
"The previous build tool did something like that, what's the difference
between that and your tool?" And the answer was "I never used the first
tool." So, basically, the community ignored whatever the community was
using.
{{ chapters(prev_chapter_link="/books/things-i-learnt/log-events", prev_chapter_title="Logs Are For Events, Not User Interface", next_chapter_link="/books/things-i-learnt/outside-project", next_chapter_title="Don't Mess With Things Outside Your Project") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/log-events", prev_chapter_title="Logs Are For Events, Not User Interface", next_chapter_link="/books/things-i-learnt/outside-project", next_chapter_title="Don't Mess With Things Outside Your Project") }}

22
content/books/things-i-learnt/log-events/index.md

@ -12,20 +12,22 @@ necessarily an human readable format.
<!-- more --> <!-- more -->
For a long time, I used logs to show to the user what was happening. Nothing For a long time, I used logs to show to the user what was happening. To me, it
could be the idea of displaying errors, general information and, if the user was logical to use something where I could mark errors as errors, general
requested, the internals of whatever is going on in one simple way. I mean, information as information and, if the user requested more information, print
yeah, let me add the errors, the info messages and the debug messages and let more information on what was going on. So I just added logging, defined normal
the user decide what they want to see. messages as `info`, errors as `errors`, information that may help me find
errors as `debug` and use _only_ the logging system for all output of the
application.
But that's not what logs are targeted for -- and now I'm having to rethink But that's not what logs are targeted for -- and now I'm having to rethink
most of the stuff I already wrote. most of the stuff I already wrote.
Use the standard output to inform the user what's going on, in a human Use the standard output to inform the user what's going on, in a human
readable format; use the standard err to inform the user when things go wrong; readable format; use the standard error output to inform the user when things
but use the logs to capture something that you'll have to process later, so go wrong; but use the logs to capture something that you'll have to process
you should probably use a format that it is easier to parse, even if it is not later, so you should probably use a format that it is easier to parse, even if
so friendly. it is not so friendly.
As an example, let's say you're connecting to a server. You could use the As an example, let's say you're connecting to a server. You could use the
standard output to say "Connecting to server", to give the user a feedback standard output to say "Connecting to server", to give the user a feedback
@ -41,4 +43,4 @@ could have the values to try to figure out why it failed -- surely, logging
why it failed also helps, but you know what I mean. This is an example of why it failed also helps, but you know what I mean. This is an example of
something that makes complete sense in logs, but not in user interfaces. something that makes complete sense in logs, but not in user interfaces.
{{ chapters(prev_chapter_link="/books/things-i-learnt/start-stupid", prev_chapter_title="Start Stupid", next_chapter_link="/books/things-i-learnt/languages-are-more", next_chapter_title="A Language Is Much More Than A Language") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/use-utf8", prev_chapter_title="Always Use UTF-8 For Your Strings", next_chapter_link="/books/things-i-learnt/languages-are-more", next_chapter_title="A Language Is Much More Than A Language") }}

12
content/books/things-i-learnt/outside-project/index.md

@ -6,8 +6,8 @@ date = 2019-06-25
tags = ["en-au", "books", "things i learnt", "frameworks"] tags = ["en-au", "books", "things i learnt", "frameworks"]
+++ +++
Simple rule: Is the code yours or from your team? Good, go break it. Does it Simple rule: Is the code yours or from your team? Good, you can make any
come from outside? DON'T. TOUCH. IT. changes you want. Does it come from outside? DON'T. TOUCH. IT.
<!-- more --> <!-- more -->
@ -32,4 +32,12 @@ thing using extensions or actually coding around the problem, even duplicating
the framework functions, would probably take longer and make you write more the framework functions, would probably take longer and make you write more
code, but in the long run, it's worth the time. code, but in the long run, it's worth the time.
Sometimes the change you need is impossible 'cause the framework you're using
doesn't have any support for extensions. This is the time you'll need to build
a new layer _on top_ of the framework. Again, this may seem painful and
changing the framework directly is a lot easier, but you'll have to keep
updating your patch for newer versions, which may not be that easy. Building
on top of the framework will at least give you some assurance 'cause the
exposed API must be way more stable than the internal code.
{{ chapters(prev_chapter_link="/books/things-i-learnt/use-structures", prev_chapter_title="If Your Data Has a Schema, Use a Structure", next_chapter_link="/books/things-i-learnt/resist-easy", next_chapter_title="Resist The Temptation Of Easy") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/use-structures", prev_chapter_title="If Your Data Has a Schema, Use a Structure", next_chapter_link="/books/things-i-learnt/resist-easy", next_chapter_title="Resist The Temptation Of Easy") }}

8
content/books/things-i-learnt/resist-easy/index.md

@ -11,14 +11,14 @@ easily build your project, but do you understand what's going on?
<!-- more --> <!-- more -->
I'm not denying the fact that IDEs make things easier. The fact is, you should I'm not denying the fact that IDEs make things easier. I'm trying to say that
not rely heavily on their features. you should not rely heavily on their features.
I mentioned before that you should at least know how to [run tests on the I mentioned before that you should at least know how to [run tests on the
command line](/books/things-i-learnt/tests-in-the-command-line) and the same command line](/books/things-i-learnt/tests-in-the-command-line) and the same
applies to everything in IDEs: how to build, how to run, how to run tests and, applies to everything in IDEs: how to build, how to run, how to run tests and,
let's be honest here, how to find proper names for your variables and let's be honest here, how to find proper names for your variables and
functions. 'Cause, sure, it's nice that the IDE can complete all the names of functions. 'Cause it's nice that the IDE can complete all the names of
the functions, but if the autocomplete feature was off, would you know which the functions, but if the autocomplete feature was off, would you know which
function you need? In other words, have you thought at least 10 seconds about function you need? In other words, have you thought at least 10 seconds about
a good name for your function so you _won't_ need to use autocomplete to a good name for your function so you _won't_ need to use autocomplete to
@ -28,4 +28,4 @@ These days, IDEs can autocomplete almost everything, from function names to
even how to name your variables. But using the autocomplete is not always a even how to name your variables. But using the autocomplete is not always a
good solution. Finding better names is. good solution. Finding better names is.
{{ chapters(prev_chapter_link="/books/things-i-learnt/outside-project", prev_chapter_title="Don't Mess With Things Outside Your Project", next_chapter_link="/books/things-i-learnt/use-timezones", next_chapter_title="Always Use Timezones With Your Dates") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/outside-project", prev_chapter_title="Don't Mess With Things Outside Your Project", next_chapter_link="/books/things-i-learnt/start-stupid", next_chapter_title="Start Stupid") }}

5
content/books/things-i-learnt/start-stupid/index.md

@ -21,7 +21,8 @@ a project done for you?
But starting it in the stupid way, in which you have to think your project But starting it in the stupid way, in which you have to think your project
layout, how to build stuff, how to run tests, how to do _everything_ may give layout, how to build stuff, how to run tests, how to do _everything_ may give
you some insights on how things work, how the pieces mesh together and how to you some insights on how things work, how the pieces mesh together and how to
cogs turn around. cogs turn around. Even better: It make give you some insights on what
_doesn't_ work.
Honestly, you don't have to do this with all projects. You can still use your Honestly, you don't have to do this with all projects. You can still use your
favourite IDE and do things in the easy way. But you can also have that side favourite IDE and do things in the easy way. But you can also have that side
@ -30,4 +31,4 @@ what your IDE is doing.
And when you grasp that, you'll be able to use _any_ IDE. And when you grasp that, you'll be able to use _any_ IDE.
{{ chapters(prev_chapter_link="/books/things-i-learnt/use-utf8", prev_chapter_title="Always Use UTF-8 For Your Strings", next_chapter_link="/books/things-i-learnt/log-events", next_chapter_title="Logs Are For Events, Not User Interface") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/resist-easy", prev_chapter_title="Resist The Temptation Of Easy", next_chapter_link="/books/things-i-learnt/use-timezones", next_chapter_title="Always Use Timezones With Your Dates") }}

17
content/books/things-i-learnt/tests-apis/index.md

@ -10,9 +10,8 @@ Testing things in isolation may give a better view of your APIs.
<!-- more --> <!-- more -->
When I spoke about [integration After reading the [integration tests](/books/things-i-learnt/integration-tests)
tests](/books/things-i-learnt/integration-tests) you may end up with the chapter, you may end up with the impression that I don't like unit tests[^1].
impression that I don't like unit tests[^1].
Actually, I think they provide some good intrinsic values. Actually, I think they provide some good intrinsic values.
@ -23,14 +22,16 @@ But, at the same time, they give a better view of your internal -- and even
external -- APIs. external -- APIs.
For example, you're writing the tests for the view layer -- 'cause, you know, 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 we write everything in layers; layers on top of layers[^2] -- and you're noticing
that you have to keep a lot of data (state) around to be able to make the 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 calls to the controller. Or that you have similar calls, but the parameters
at the controller API. are sometimes switched (say, one function gets a token and a user ID, and
another function gets a user ID and a token -- why?) 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 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 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. for the most external layer, the layer that will be exposed by that library.
And, again, you're noticing that you have to keep a lot of context around, 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 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 using parameters in different ways. Your tests will look like a mess, don't
@ -41,5 +42,7 @@ 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 [^1]: Again, let's ignore for a second that there are no "unit" in "unit
tests"... tests"...
[^2]: And layers all the way down, [like
turtles](https://en.wikipedia.org/wiki/Turtles_all_the_way_down).
{{ 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") }} {{ 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") }}

32
content/books/things-i-learnt/throw-away/index.md

@ -13,24 +13,28 @@ may have to rewrite a lot of stuff, including whatever your already wrote.
TDD was _designed_ to throw code away: The more you learn about your problem, 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 more you understand that, whatever you wrote, won't solve the problem in
the long run. the long run. Also, as you slowly solve new problems, you may notice some
pattern in the code emerging (you're doing the same thing over and over, with
only minor changes). That's a good time to go over and rewrite everything to
take advantage of this pattern.
You shouldn't worry about this. Your code is not a wall: if you have to throw You shouldn't worry about this. Your code is not a wall (or any physical
it always, it is not wasted material. Surely it means your time writing code object): if you have to throw it away, you didn't wasted materials. Surely it
was lost, but you got a better understanding about the problem now. means your time writing code was lost, but you got a better understanding
about the problem now, or you may start to think in a more concise way to
solve the problem.
Not only that, but as you progress through your project, solving problems and Not only that, but as you progress through your project, solving problems and
getting "acquainted" with the problem, you'll also notice that the 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 [spec](/books/things-i-learnt/spec-first) will also change. This means that
wasn't exactly the problem you _needed_ to solve; your code is trying to solve the problem your code solve wasn't exactly the problem you _needed_ to solve;
something that isn't exactly the problem. 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, Also, specs changing is really common. One thing that you can be sure is that
that is. One thing that you can be sure is that it won't change _everywhere_. it won't change _everywhere_. Some of the things you solved will stay the
Some of the things you solved will stay the same, some others will be same, some others will be completely removed and some others added. And you
completely removed and some others added. And you will see that you'll will see that you'll refactor your code a lot, and throw a lot of code away.
refactor your code a lot, and throw a lot of code away. And not just code that And not just code that solves the problem, but also the tests for that code.
solves the problem, but also the tests for that code.
... unless you focus mostly on [integration ... unless you focus mostly on [integration
tests](/books/things-i-learnt/integration-tests). tests](/books/things-i-learnt/integration-tests).

16
content/books/things-i-learnt/use-structures/index.md

@ -7,7 +7,7 @@ tags = ["en-au", "books", "things i learnt", "data classes", "structs"]
+++ +++
You may be tempted to use a list (or tuple, if your language allows) to keep You may be tempted to use a list (or tuple, if your language allows) to keep
your data if it's simple -- like, say, only 2 fields. Don't. your data if it has, say, only 2 fields. Don't.
<!-- more --> <!-- more -->
@ -33,13 +33,13 @@ some_string, an_integer, a_float = a_tuple
See? It's simple! You don't need to create a whole structure if you're just See? It's simple! You don't need to create a whole structure if you're just
passing a string, an integer and a float around. passing a string, an integer and a float around.
Except, you do. Except, you do need a structure 'cause your data has a _schema_.
Tuples and destructuring should be used only when you need to pass data from Tuples and destructuring should be used only when you need to pass data from
one function to another -- and barely that. When you have this tuple being one function to another -- and barely that. When you have this tuple being
passed around, being destructured and created again -- say, you are adding one passed around, being destructured and created again -- say, you are adding one
value of the tuple to another value and producing a new tuple in the same value of the tuple to another value and producing a new tuple in the same
format -- then you have a structured data. format -- then you have a structured -- and _schemaed_ data.
And when you have a structured data, you must use a data class or a struct (or And when you have a structured data, you must use a data class or a struct (or
even even
@ -47,7 +47,7 @@ even
if you're using Python). if you're using Python).
Although it may look way more simpler to keep destructuring and building the Although it may look way more simpler to keep destructuring and building the
tuple over and over, in the long run you'll end up with a mess 'cause a simple tuple over and over, in the long run you'll end up with a mess: a simple
change -- like adding a new field -- will require checking every destructuring change -- like adding a new field -- will require checking every destructuring
and every creation of the tuple to make sure if will stay in the same shape and every creation of the tuple to make sure if will stay in the same shape
every time. every time.
@ -55,15 +55,15 @@ every time.
So: You data has a schema? Use a Data Class or Class or Struct. Only if it is So: You data has a schema? Use a Data Class or Class or Struct. Only if it is
schemaless, then you can use a tuple. schemaless, then you can use a tuple.
I've seen this used at least once. Sure, at the very start of the project, it I've seen this used at least once. At the very start of the project, it
may seem easier to just store the data as a tuple and destructure it and build may seem easier to just store the data as a tuple and destructure it and build
it again when needed. There was even a whole module designed to receiving it again when needed. There was even a whole module designed to receiving
tuples, destructure them and rebuild new ones (for example, a function that tuples, destructure them and rebuild new ones (for example, a function that
would receive two tuples and compute the sum of the "value" field of each, would receive two tuples and compute the sum of the "value" field of each,
building a new tuple as a result). But because of this design, to add just a building a new tuple as a result). But because of this design, to add just a
new field, I had to change 14 files and do 168 changes around -- 'cause, sure, new field, I had to change 14 files and do 168 changes around -- 'cause there
there was a function to add two tuples, but there were points where you need was a function to add two tuples, but there were points where you need just
just one field, and there wasn't a function for it. one field, and there wasn't a function for it.
It would be easier to use if there were functions to extract each field, and It would be easier to use if there were functions to extract each field, and
add two tuples, and what else was needed for managing the tuples, but then you add two tuples, and what else was needed for managing the tuples, but then you

15
content/books/things-i-learnt/use-timezones/index.md

@ -7,13 +7,13 @@ tags = ["en-au", "books", "things i learnt", "dates", "timezones"]
+++ +++
No matter if the date you're receiving is in your local timezone and you'll No matter if the date you're receiving is in your local timezone and you'll
display it in your timezone. Sooner or later, the fact that you ignored there display it in your timezone, sooner or later, the fact that you ignored there
was a timezone behind that date will hurt you. was a timezone behind that date will hurt you.
<!-- more --> <!-- more -->
(Note: Most of this post when I say "date" you can think of "date and time", (Note: Most of this post when I say "date" you can think of "date and time",
although the date should also be timezone aware.) although the date should also be "timezone aware".)
At some point of my professional life, ignoring timezones was easy: You just At some point of my professional life, ignoring timezones was easy: You just
pick the date, throw in the database, then read it back and everybody was pick the date, throw in the database, then read it back and everybody was
@ -32,9 +32,10 @@ timezone as soon as possible and carry it around in all operations.
Modules/classes that don't support timezones for dates/times should, as soon Modules/classes that don't support timezones for dates/times should, as soon
as possible, removed from the system. as possible, removed from the system.
Developers a bit more seasoned -- and by "seasoned" I meant "Had to deal with Any developers a bit more seasoned -- and by "seasoned" I meant "Had to deal
times before" -- will probably claim "Hey, this is _obvious_!" And I'd have to with times before" -- will probably claim "Hey, this is _obvious_!" And I'd
agree. But it's annoying how many times I got bitten by some stupid bug 'cause have to agree. But it's annoying how many times I got bitten by some stupid
we decided that "well, everything is in the same timezone, so it's all good". bug 'cause we decided that "well, everything is in the same timezone, so it's
all good".
{{ chapters(prev_chapter_link="/books/things-i-learnt/resist-easy", prev_chapter_title="Resist The Temptation Of Easy", next_chapter_link="/books/things-i-learnt/use-utf8", next_chapter_title="Always Use UTF-8 For Your Strings") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/start-stupid", prev_chapter_title="Start Stupid", next_chapter_link="/books/things-i-learnt/use-utf8", next_chapter_title="Always Use UTF-8 For Your Strings") }}

28
content/books/things-i-learnt/use-utf8/index.md

@ -12,11 +12,11 @@ with no "weird" or "funny" characters.
<!-- more --> <!-- more -->
I was born in a time when the only encoding we had was ASCII. You could encode I became a developer in a time when the only encoding we had was ASCII. You
all strings in sequences of bytes, 'cause all characters you could use where could encode all strings in sequences of bytes, 'cause all characters you
encoded from 1 to 255 (well, from 32 [space] to 93 [close brackets] and you could use where encoded from 1 to 255 (well, from 32 [space] to 93 [close
still have a few latin-accented characters in some higher positions, although brackets] and you still have a few latin-accented characters in some higher
not all accents where there). positions, although not all accents where there).
Today, accepting characters beyond that is not the exception, but the norm. To Today, accepting characters beyond that is not the exception, but the norm. To
cope with all that, we have things like cope with all that, we have things like
@ -26,18 +26,18 @@ memory space (UTF-16 is also a good option here, but that would depend on your
language). language).
So, as much as you to make your system simple, you will have to keep the So, as much as you to make your system simple, you will have to keep the
internal representation of your strings in UTF-8/UTF-16. Surely, you may not internal representation of your strings in UTF-8/UTF-16. You may not receive
receive the data as UTF-8/UTF-16, but you'll have to encode it and keep the data as UTF-8/UTF-16, but you'll have to encode it and keep transmitting
transmitting it around as UTF-8/UTF-16 till you have to display it, at which it around as UTF-8/UTF-16 till you have to display it, at which point you'll
point you'll convert from UTF-8/UTF-16 to whatever your display supports convert from UTF-8/UTF-16 to whatever your display supports (maybe it even
(maybe it even supports displaying in UTF-8/UTF-16, so you're good already). supports displaying in UTF-8/UTF-16, so you're good already).
At this point, I believe most languages do support UTF-8, which is great. You Today, I believe most languages do support UTF-8, which is great. You
may still have problems with inputs coming from other systems that are not may still have problems with inputs coming from other systems that are not
UTF-8 (old Windows versions, for example), but that's fairly easy to convert UTF-8 (old Windows versions, for example), but that's fairly easy to convert
-- the hard part is figuring out the input _encoding_, though. Also, most -- the hard part is figuring out the input _encoding_, though. Also, most
developers tend to ignore this and only accept ASCII characters, or ignore developers tend to ignore this and assume the input is in ASCII, or ignore the
UTF-8/whatever-encoding and get a bunch of weird characters on their printing, input encoding and get a bunch of weird characters on their printing,
'cause they completely ignored the conversion on the output point. That's why 'cause they completely ignored the conversion on the output point. That's why
I'm repeating the mantra of UTF-8: To remind you to always capture your input, I'm repeating the mantra of UTF-8: To remind you to always capture your input,
encode it in UTF-8 and _then_ convert in the output. encode it in UTF-8 and _then_ convert in the output.
@ -52,4 +52,4 @@ single character. Walking through the whole string would require traversing
the string character by character, instead of simply jumping straight to the the string character by character, instead of simply jumping straight to the
proper position. But that's a price worth paying, in the long run. proper position. But that's a price worth paying, in the long run.
{{ chapters(prev_chapter_link="/books/things-i-learnt/use-timezones", prev_chapter_title="Always Use Timezones With Your Dates", next_chapter_link="/books/things-i-learnt/start-stupid", next_chapter_title="Start Stupid") }} {{ chapters(prev_chapter_link="/books/things-i-learnt/use-timezones", prev_chapter_title="Always Use Timezones With Your Dates", next_chapter_link="/books/things-i-learnt/log-events", next_chapter_title="Logs Are For Events, Not User Interface") }}

Loading…
Cancel
Save