@ -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") }}
@ -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") }}
{{ 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") }}
@ -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") }}
@ -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") }}
@ -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") }}
@ -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") }}
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") }}
@ -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") }}
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") }}
{{ 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") }}
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") }}
@ -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") }}