From 2a9472a1619a33301f44f56e710154ea49e262ab Mon Sep 17 00:00:00 2001 From: Julio Biason Date: Fri, 5 Jul 2019 11:34:49 -0300 Subject: [PATCH] More proof reading --- content/books/things-i-learnt/_index.md | 2 +- .../boolean-parameters/index.md | 6 ++-- .../books/things-i-learnt/cargo-cult/index.md | 2 +- .../books/things-i-learnt/crash-it/index.md | 12 +++++++ .../books/things-i-learnt/data-types/index.md | 15 +++++---- .../things-i-learnt/document-and/index.md | 7 ++-- .../document-is-contract/index.md | 24 +++++++------- .../things-i-learnt/document-it/index.md | 10 ++++++ .../things-i-learnt/future-trashing/index.md | 9 ++++-- .../books/things-i-learnt/handle-it/index.md | 6 ++-- .../interface-changes/index.md | 4 +-- .../languages-are-more/index.md | 21 ++++++++++-- .../books/things-i-learnt/log-events/index.md | 22 +++++++------ .../things-i-learnt/outside-project/index.md | 12 +++++-- .../things-i-learnt/resist-easy/index.md | 8 ++--- .../things-i-learnt/start-stupid/index.md | 5 +-- .../books/things-i-learnt/tests-apis/index.md | 17 ++++++---- .../books/things-i-learnt/throw-away/index.md | 32 +++++++++++-------- .../things-i-learnt/use-structures/index.md | 16 +++++----- .../things-i-learnt/use-timezones/index.md | 15 +++++---- .../books/things-i-learnt/use-utf8/index.md | 28 ++++++++-------- 21 files changed, 167 insertions(+), 106 deletions(-) diff --git a/content/books/things-i-learnt/_index.md b/content/books/things-i-learnt/_index.md index 3190069..a0557ca 100644 --- a/content/books/things-i-learnt/_index.md +++ b/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) diff --git a/content/books/things-i-learnt/boolean-parameters/index.md b/content/books/things-i-learnt/boolean-parameters/index.md index fea0c77..22517e3 100644 --- a/content/books/things-i-learnt/boolean-parameters/index.md +++ b/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. @@ -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") }} diff --git a/content/books/things-i-learnt/cargo-cult/index.md b/content/books/things-i-learnt/cargo-cult/index.md index 38b0056..85530a1 100644 --- a/content/books/things-i-learnt/cargo-cult/index.md +++ b/content/books/things-i-learnt/cargo-cult/index.md @@ -14,7 +14,7 @@ same results as a real airplane. -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 diff --git a/content/books/things-i-learnt/crash-it/index.md b/content/books/things-i-learnt/crash-it/index.md index 3611777..055096b 100644 --- a/content/books/things-i-learnt/crash-it/index.md +++ b/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") }} diff --git a/content/books/things-i-learnt/data-types/index.md b/content/books/things-i-learnt/data-types/index.md index 178d4f8..22d86e6 100644 --- a/content/books/things-i-learnt/data-types/index.md +++ b/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") }} diff --git a/content/books/things-i-learnt/document-and/index.md b/content/books/things-i-learnt/document-and/index.md index 16b3458..8257644 100644 --- a/content/books/things-i-learnt/document-and/index.md +++ b/content/books/things-i-learnt/document-and/index.md @@ -13,9 +13,9 @@ documentation. 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") }} diff --git a/content/books/things-i-learnt/document-is-contract/index.md b/content/books/things-i-learnt/document-is-contract/index.md index 018f5f0..c408cda 100644 --- a/content/books/things-i-learnt/document-is-contract/index.md +++ b/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. 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? diff --git a/content/books/things-i-learnt/document-it/index.md b/content/books/things-i-learnt/document-it/index.md index 4e5a972..12bdffa 100644 --- a/content/books/things-i-learnt/document-it/index.md +++ b/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") }} diff --git a/content/books/things-i-learnt/future-trashing/index.md b/content/books/things-i-learnt/future-trashing/index.md index bd1f902..7487080 100644 --- a/content/books/things-i-learnt/future-trashing/index.md +++ b/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. 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") }} diff --git a/content/books/things-i-learnt/handle-it/index.md b/content/books/things-i-learnt/handle-it/index.md index 31ca634..d971a75 100644 --- a/content/books/things-i-learnt/handle-it/index.md +++ b/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 diff --git a/content/books/things-i-learnt/interface-changes/index.md b/content/books/things-i-learnt/interface-changes/index.md index 400c047..de6ee26 100644 --- a/content/books/things-i-learnt/interface-changes/index.md +++ b/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. @@ -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 diff --git a/content/books/things-i-learnt/languages-are-more/index.md b/content/books/things-i-learnt/languages-are-more/index.md index 827bc93..ef5fc6f 100644 --- a/content/books/things-i-learnt/languages-are-more/index.md +++ b/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") }} diff --git a/content/books/things-i-learnt/log-events/index.md b/content/books/things-i-learnt/log-events/index.md index 311fc95..2c75c63 100644 --- a/content/books/things-i-learnt/log-events/index.md +++ b/content/books/things-i-learnt/log-events/index.md @@ -12,20 +12,22 @@ necessarily an human readable format. -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") }} diff --git a/content/books/things-i-learnt/outside-project/index.md b/content/books/things-i-learnt/outside-project/index.md index fced03d..a061991 100644 --- a/content/books/things-i-learnt/outside-project/index.md +++ b/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. @@ -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") }} diff --git a/content/books/things-i-learnt/resist-easy/index.md b/content/books/things-i-learnt/resist-easy/index.md index dc9212d..2b4e853 100644 --- a/content/books/things-i-learnt/resist-easy/index.md +++ b/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? -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") }} diff --git a/content/books/things-i-learnt/start-stupid/index.md b/content/books/things-i-learnt/start-stupid/index.md index ade4987..d313143 100644 --- a/content/books/things-i-learnt/start-stupid/index.md +++ b/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") }} diff --git a/content/books/things-i-learnt/tests-apis/index.md b/content/books/things-i-learnt/tests-apis/index.md index 425b2ed..530b17f 100644 --- a/content/books/things-i-learnt/tests-apis/index.md +++ b/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. -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") }} diff --git a/content/books/things-i-learnt/throw-away/index.md b/content/books/things-i-learnt/throw-away/index.md index 62ebab8..a5cc2e4 100644 --- a/content/books/things-i-learnt/throw-away/index.md +++ b/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). diff --git a/content/books/things-i-learnt/use-structures/index.md b/content/books/things-i-learnt/use-structures/index.md index c0ed963..2b1f7e6 100644 --- a/content/books/things-i-learnt/use-structures/index.md +++ b/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. @@ -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 diff --git a/content/books/things-i-learnt/use-timezones/index.md b/content/books/things-i-learnt/use-timezones/index.md index fb390fd..6873b8f 100644 --- a/content/books/things-i-learnt/use-timezones/index.md +++ b/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. (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") }} diff --git a/content/books/things-i-learnt/use-utf8/index.md b/content/books/things-i-learnt/use-utf8/index.md index 840162c..2534afe 100644 --- a/content/books/things-i-learnt/use-utf8/index.md +++ b/content/books/things-i-learnt/use-utf8/index.md @@ -12,11 +12,11 @@ with no "weird" or "funny" characters. -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") }}