Browse Source

Merge tag '20190705.1' into preview

20190705.1
master
Julio Biason 5 years ago
parent
commit
e71167c916
  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)
* [Don't Mess With Things Outside Your Project](outside-project)
* [Resist The Temptation Of Easy](resist-easy)
* [Start Stupid](start-stupid)
* [Always Use Timezones With Your Dates](use-timezones)
* [Always Use UTF-8 For Your Strings](use-utf8)
* [Start Stupid](start-stupid)
* [Logs Are For Events, Not User Interface](log-events)
* Community/Teams
* [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"]
+++
When you're designing a function, you may be tempted to add a flag. Don't do
this.
When you're designing a function, you may be tempted to add a flag (a
parameter in a function that it is a boolean). Don't do this.
<!-- 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
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") }}

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

@ -14,7 +14,7 @@ same results as a real airplane.
<!-- 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.
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
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") }}

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
`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
with the value `1` and `FALSE` with another integer with the value `0`. And
so, the build on top of what older developers knew, other languages use the
same concepts. And so, you have a list of booleans and want to know how many
true values are in the list, you can simply add them all.
with the value `1` and `FALSE` with another integer with the value `0`. Newer
languages were build on top of what older developers knew, and so, a bunch of
those languages also assumed using an integer under booleans was a good idea.
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
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
performance out.
Fortunately, new languages are based on ML, which wouldn't allow this kind of
stuff.
Fortunately, some new languages are using booleans as a complete different
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") }}

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

@ -13,9 +13,9 @@ documentation.
<!-- more -->
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
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
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
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
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") }}

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

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,
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... :(
{{ 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 -->
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
tax: future problems future will never come -- and, believe me, they will
_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
@ -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
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") }}

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.
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
somewhere else, log it to be reprocessed later or even just show an error
message, do it.
occur, _deal with it_. If you have to save the content of the user somewhere
else, log it to be reprocessed later or even just show an error message, do
it.
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

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,
you'll make everyone's life a sad life.
you'll make everyone's life sad.
<!-- 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.
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.
(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
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
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
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
problems.
problems[^1].
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
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
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
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") }}

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

@ -12,20 +12,22 @@ necessarily an human readable format.
<!-- more -->
For a long time, I used logs to show to the user what was happening. Nothing
could be the idea of displaying errors, general information and, if the user
requested, the internals of whatever is going on in one simple way. I mean,
yeah, let me add the errors, the info messages and the debug messages and let
the user decide what they want to see.
For a long time, I used logs to show to the user what was happening. To me, it
was logical to use something where I could mark errors as errors, general
information as information and, if the user requested more information, print
more information on what was going on. So I just added logging, defined normal
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
most of the stuff I already wrote.
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;
but use the logs to capture something that you'll have to process later, so
you should probably use a format that it is easier to parse, even if it is not
so friendly.
readable format; use the standard error output to inform the user when things
go wrong; but use the logs to capture something that you'll have to process
later, so you should probably use a format that it is easier to parse, even if
it is not so friendly.
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
@ -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
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"]
+++
Simple rule: Is the code yours or from your team? Good, go break it. Does it
come from outside? DON'T. TOUCH. IT.
Simple rule: Is the code yours or from your team? Good, you can make any
changes you want. Does it come from outside? DON'T. TOUCH. IT.
<!-- 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
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") }}

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 -->
I'm not denying the fact that IDEs make things easier. The fact is, you should
not rely heavily on their features.
I'm not denying the fact that IDEs make things easier. I'm trying to say that
you should not rely heavily on their features.
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
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
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
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
@ -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
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
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
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
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.
{{ 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 -->
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].
After reading the [integration tests](/books/things-i-learnt/integration-tests)
chapter, you may end up with the impression that I don't like unit tests[^1].
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.
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
calls to the controller. That's a sign that you may have to take a better look
at the controller API.
calls to the controller. Or that you have similar calls, but the parameters
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
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,
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
@ -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
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") }}

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,
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
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.
You shouldn't worry about this. Your code is not a wall (or any physical
object): if you have to throw it away, you didn't wasted materials. Surely it
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
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.
[spec](/books/things-i-learnt/spec-first) will also change. This means that
the problem your code solve wasn't exactly the problem you _needed_ to solve;
your code is trying to solve something that isn't exactly the problem.
Also, specs changing is really common. 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).

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
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 -->
@ -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
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
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
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
even
@ -47,7 +47,7 @@ even
if you're using Python).
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
and every creation of the tuple to make sure if will stay in the same shape
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
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
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
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
new field, I had to change 14 files and do 168 changes around -- 'cause, sure,
there was a function to add two tuples, but there were points where you need
just one field, and there wasn't a function for it.
new field, I had to change 14 files and do 168 changes around -- 'cause there
was a function to add two tuples, but there were points where you need just
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
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
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.
<!-- more -->
(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
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
as possible, removed from the system.
Developers a bit more seasoned -- and by "seasoned" I meant "Had to deal with
times before" -- will probably claim "Hey, this is _obvious_!" And I'd have to
agree. But it's annoying how many times I got bitten by some stupid bug 'cause
we decided that "well, everything is in the same timezone, so it's all good".
Any developers a bit more seasoned -- and by "seasoned" I meant "Had to deal
with times before" -- will probably claim "Hey, this is _obvious_!" And I'd
have to agree. But it's annoying how many times I got bitten by some stupid
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 -->
I was born in a time when the only encoding we had was ASCII. You could encode
all strings in sequences of bytes, 'cause all characters you could use where
encoded from 1 to 255 (well, from 32 [space] to 93 [close brackets] and you
still have a few latin-accented characters in some higher positions, although
not all accents where there).
I became a developer in a time when the only encoding we had was ASCII. You
could encode all strings in sequences of bytes, 'cause all characters you
could use where encoded from 1 to 255 (well, from 32 [space] to 93 [close
brackets] and you still have a few latin-accented characters in some higher
positions, although not all accents where there).
Today, accepting characters beyond that is not the exception, but the norm. To
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).
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
receive the data as UTF-8/UTF-16, but you'll have to encode it and keep
transmitting it around as UTF-8/UTF-16 till you have to display it, at which
point you'll convert from UTF-8/UTF-16 to whatever your display supports
(maybe it even supports displaying in UTF-8/UTF-16, so you're good already).
internal representation of your strings in UTF-8/UTF-16. You may not receive
the data as UTF-8/UTF-16, but you'll have to encode it and keep transmitting
it around as UTF-8/UTF-16 till you have to display it, at which point you'll
convert from UTF-8/UTF-16 to whatever your display supports (maybe it even
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
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
developers tend to ignore this and only accept ASCII characters, or ignore
UTF-8/whatever-encoding and get a bunch of weird characters on their printing,
developers tend to ignore this and assume the input is in ASCII, or ignore the
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
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.
@ -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
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