diff --git a/content/books/things-i-learnt/_index.md b/content/books/things-i-learnt/_index.md index 672b295..12e3399 100644 --- a/content/books/things-i-learnt/_index.md +++ b/content/books/things-i-learnt/_index.md @@ -32,6 +32,11 @@ template = "section-contentless.html" * [Good Languages Come With Integrated Documentation](languages-docs) * Source Control * [Always Use A Version Control System](always-vcs) + * [One Commit Per Change](one-change-commit) + * Project Organization + * [Organize Your Code by Data/Type, Not Functionality](project-organization) + * [Create Libraries](libraries) + * [The Config File Is Friend](config-file) * Writing code * [Be Ready To Throw Your Code Away](throw-away) * [Future Thinking Is Future Trashing](future-trashing) @@ -47,6 +52,7 @@ template = "section-contentless.html" * [Always Use Timezones With Your Dates](use-timezones) * [Always Use UTF-8 For Your Strings](use-utf8) * [Logs Are For Events, Not User Interface](log-events) + * [Learn To Monitor](monitoring) * Community/Teams * [A Language Is Much More Than A Language](languages-are-more) * [Understand And Stay Away From Cargo Cult](cargo-cult) diff --git a/content/books/things-i-learnt/always-vcs/index.md b/content/books/things-i-learnt/always-vcs/index.md index 8ec89cd..56c4fcf 100644 --- a/content/books/things-i-learnt/always-vcs/index.md +++ b/content/books/things-i-learnt/always-vcs/index.md @@ -30,4 +30,4 @@ change. And, in the long, since you'll end up with working in team and will be required to use a VCS, you'll be used to using one. -{{ chapters(prev_chapter_link="/books/things-i-learnt/languages-docs", prev_chapter_title="Good Languages Come With Integrated Documentation", next_chapter_link="/books/things-i-learnt/throw-away", next_chapter_title="Be Ready To Throw Your Code Away") }} +{{ chapters(prev_chapter_link="/books/things-i-learnt/languages-docs", prev_chapter_title="Good Languages Come With Integrated Documentation", next_chapter_link="/books/things-i-learnt/one-change-commit", next_chapter_title="One Commit Per Change") }} diff --git a/content/books/things-i-learnt/config-file/index.md b/content/books/things-i-learnt/config-file/index.md new file mode 100644 index 0000000..3723326 --- /dev/null +++ b/content/books/things-i-learnt/config-file/index.md @@ -0,0 +1,37 @@ ++++ +title = "Things I Learnt The Hard Way - The Config File Is Friend" +date = 2019-07-15 + +[taxonomies] +tags = ["en-au", "books", "things i learnt", "configuration", "config file"] ++++ + +Do not ignore the power of configuration files. + + + +Imagine you wrote a function that you have to pass a value for it to start +processing (say, a twitter user account id). But then you have to do that with +two values and you just call the function again with the other value. + +It makes more sense to use a config file and just run the application twice +with two different config files 'cause, this way, you have a single, small, +testable application instead of two, or a very complex application that does a +lot of stuff. + +We can even jump into the idea of [creating +libraries](/books/things-i-learnt/libraries) and say that, instead of +splitting your e-commerce application into smaller parts and making a big one +by grouping these smaller parts, you could simply have one e-commerce +application and, for each of your clients, you would have a different +configuration file, pointing to different assets. This way, even the assets +may reside in the same repository in the same branch, 'cause all that +identifies which assets should be used are defined in the configuration file. + +"But which one should I use?" you may ask. Well, "it depends". It may make +sense to have one single application with different configuration files if +most of its can be used all the time. If the intersection of used things is +very small, it may make more sense to split into different libraries and just +"pick and chose" what to use. + +{{ chapters(prev_chapter_link="/books/things-i-learnt/libraries", prev_chapter_title="Create Libraries", next_chapter_link="/books/things-i-learnt/throw-away", next_chapter_title="Be Ready To Throw Your Code Away") }} 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 ef5fc6f..ed09b2d 100644 --- a/content/books/things-i-learnt/languages-are-more/index.md +++ b/content/books/things-i-learnt/languages-are-more/index.md @@ -54,4 +54,4 @@ And picking a language for something _above_ the syntax is even worse. tool." So, basically, the community ignored whatever the community was using. -{{ chapters(prev_chapter_link="/books/things-i-learnt/log-events", prev_chapter_title="Logs Are For Events, Not User Interface", next_chapter_link="/books/things-i-learnt/outside-project", next_chapter_title="Don't Mess With Things Outside Your Project") }} +{{ chapters(prev_chapter_link="/books/things-i-learnt/monitoring", prev_chapter_title="Learn To Monitor", 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/libraries/index.md b/content/books/things-i-learnt/libraries/index.md new file mode 100644 index 0000000..2c4cd2a --- /dev/null +++ b/content/books/things-i-learnt/libraries/index.md @@ -0,0 +1,48 @@ ++++ +title = "Things I Learnt The Hard Way - Create Libraries" +date = 2019-07-15 + +[taxonomies] +tags = ["en-au", "books", "things i learnt", "libraries", "project organization"] ++++ + +One thing you must learn is how to break your project into smaller libraries, +to avoid doing rounds to deal with "the same, but a bit different". + + + +I've seen a lot of projects that use things like branches for different +things. Say, you have an e-commerce page. But you also have different clients, +and they all have different colours and logo. Some people would take this +scenario and, using the VCS properties, use the main branch for the main code +and a branch for each client, merge from main branch from time to time -- and, +thus, the branches are never merged back. + +This is suboptimal, 'cause that's not how VCS are supposed to be used. + +But you can, for example, break the main code into a library/framework and +have one project for each client, with their assets and you just reference the +library/framework in each. + +Simple and clean. + +But stop there for a second. Although this makes the code cleaner, avoids +duplication and uses a VCS in the way it was supposed to be used, you can't +start this way. + +Remember that [future thinking is future +trashing](/books/things-i-learnt/future-trashing). What you can do is actually +break your project by functionality, [making modules related to their +data](/books/things-i-learnt/project-organization) and then, when you get a +reasonable number of clients, you'll notice what can be reused in each, what +modules make sense for one client and not for another. And then you'll have a +good way to deal with those. + +One project that may appear when creating libraries is "How do I create my own +library repository?" 'Cause all modern languages today have support for +importing external libraries and, even if your libraries will never be out of +your control, they are external to the project. So you may need to learn how +to deal with this before creating the libraries. And, unfortunately, each +language and build tool has its own way to manage this. + +{{ chapters(prev_chapter_link="/books/things-i-learnt/project-organization", prev_chapter_title="Organize Your Code by Data/Type, Not Functionality", next_chapter_link="/books/things-i-learnt/config-file", next_chapter_title="The Config File Is Friend") }} diff --git a/content/books/things-i-learnt/log-events/index.md b/content/books/things-i-learnt/log-events/index.md index 2c75c63..edeb658 100644 --- a/content/books/things-i-learnt/log-events/index.md +++ b/content/books/things-i-learnt/log-events/index.md @@ -43,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/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") }} +{{ 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/monitoring", next_chapter_title=Learn To Monitor"") }} diff --git a/content/books/things-i-learnt/monitoring/index.md b/content/books/things-i-learnt/monitoring/index.md new file mode 100644 index 0000000..854e6a5 --- /dev/null +++ b/content/books/things-i-learnt/monitoring/index.md @@ -0,0 +1,29 @@ ++++ +title = "Things I Learnt The Hard Way - Logs Are For Events, Not User Interface" +date = 2019-07-15 + +[taxonomies] +tags = ["en-au", "books", "things i learnt", "monitoring"] ++++ + +On a previous life, to understand how a system behaved, I added a ton of +metrics: how fast things were going in, how fast things were going out, how +many things were in the middle, how many the job processed... Not doing it so +makes me feel... naked. + + + +Monitoring your project performance give you a really good view of how a +system is behaving. Is the speed going down? Is the system taking longer to +process an input? Are no inputs being processed? + +If you have this kind of information, you can check what is going on in the +system and understand why. Is it normal? Did a change around the system (the +other system that produces the input, the system that consumes in the output) +affected the results? + +If you're not measuring, you'll have no idea. + +Also, "If you can not measure it, you can not improve it", as Lord Kevin said. + +{{ 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/languages-are-more", next_chapter_title="A Language Is Much More Than A Language") }} diff --git a/content/books/things-i-learnt/one-change-commit/index.md b/content/books/things-i-learnt/one-change-commit/index.md new file mode 100644 index 0000000..9dc5129 --- /dev/null +++ b/content/books/things-i-learnt/one-change-commit/index.md @@ -0,0 +1,39 @@ ++++ +title = "Things I Learnt The Hard Way - One Commit Per Change" +date = 2019-07-09 + +[taxonomies] +tags = ["en-au", "books", "things i learnt", "source control", "commits"] ++++ + +When working with source control tools, keep one change per commit. Avoid +bundling more than one change in a single commit just to "save time". + + + +I've seen my fair share of commits with messages like "Fix issues #1, #2 +and #3". This is not something you should do. One commit for fixing issue #1, +another for #2 and yet another for #3. + +Just note that I said "one commit per change", not "one commit per file". +Sometimes, to make a single change, you may need to change more than one file +-- it may point that you have a coupling problem, but that's a different +issue. You could, for example, make one commit which adds a new field in model +without adding a change in the controller to load this field; after all, the +controller won't (or, at least, shouldn't) break due the added field, and the +model won't break (or, at least, shouldn't) break because the controller is +not touching the field[^1]. + +When making a commit, think this: "In case something goes wrong, can I undo +this commit without breaking other stuff?" Commit history is stacked, so +obviously you'd have to undo the commits on top of that one. And that's +alright. + +**BONUS TIP**! If you're using `git`, you can use `git add -p` in case you +"overchange". It will allow you to pick parts of a file, instead of adding all +the changes in the file before committing. + +[^1]: Ok, it _may_ have some issues if the field can't be null, but you get + what I meant, right? + +{{ chapters(prev_chapter_link="/books/things-i-learnt/always-vcs", prev_chapter_title="Always Use A Version Control System", next_chapter_link="/books/things-i-learnt/project-organization", next_chapter_title="Organize Your Code by Data/Type, Not Functionality") }} diff --git a/content/books/things-i-learnt/project-organization/index.md b/content/books/things-i-learnt/project-organization/index.md new file mode 100644 index 0000000..f587680 --- /dev/null +++ b/content/books/things-i-learnt/project-organization/index.md @@ -0,0 +1,84 @@ ++++ +title = "Things I Learnt The Hard Way - Organize Your Code by Data/Type, Not Functionality" +date = 2019-07-15 + +[taxonomies] +tags = ["en-au", "books", "things i learnt", "project", "project organization"] ++++ + +A lot of projects assume that you'll put things with the same functionality in +the same place, no matter what data they deal with. This makes things harder +to break apart later. + + + +Most projects keep organized by the functionality each component do. For +example, all the models are in the same place, all the functions that convert +one model into an internal structure/DTO are kept together, and so on. +Something like this: + +``` +. ++-- IncomingModels +| +-- DataTypeInterface +| +-- DataType1 +| +-- DataType2 +| +-- DataType3 ++-- Filters +| +-- FilterInterface +| +-- FilterValidDataType2 ++-- Processors +| +-- ProcessorInterface +| +-- ConvertDataType1ToDto1 +| +-- ConvertDataType2ToDto2 ++-- OutgoingModels + +-- DtoInterface + +-- Dto1 + +-- Dto2 +``` + +This is fine and works. But when you organize by data, it'll make a lot easier +to split your project in smaller projects -- 'cause, at some point, you may +want to do almost the same thing as you're doing right now, but with small +differences. + +``` +. ++-- Base +| +-- IncomingModels +| | +-- DataTypeInterface +| +-- Filters +| | +-- FilterInterface +| +-- Processors +| | +-- ProcessorInterface +| +-- OutgoingModels +| +-- DtoInterface ++-- Data1 +| +-- IncomingModels +| | +-- DataType1 +| +-- Processors +| | +-- ConvertDataType1ToDto1 +| +-- OutgoingModels +| +-- Dto1 +... +``` + +Now you can make a module that deals _only_ with Data1, another that works +only with Data2 and so on. And then you can break them into isolated modules. + +And then when you have another project that also have Data1 but also deals +with Data3, you can reuse most of the stuff in the Data1 module. + +And I do understand that this creates an explosion of directories/packages, +which may seem a bit unnecessary. + +Believe me, I also thought the idea of keeping things by functionality made +more sense. But in one project, I got a requirement to do almost the same +thing as I was doing before, but with a small change, which would require one +less step/transformation (in our example, you can think as the new requirement +as doing exactly what the Data1, Data2 and Data3 did, with their +transformations and such, but without the Data3 part). By breaking by their +types, I managed to create small modules for each one and the new project +would simply reference Data1 and Data2, but not Data3. + +{{ chapters(prev_chapter_link="/books/things-i-learnt/one-change-commit", prev_chapter_title="One Commit Per Change", next_chapter_link="/books/things-i-learnt/libraries", next_chapter_title="Create Libraries") }} diff --git a/content/books/things-i-learnt/throw-away/index.md b/content/books/things-i-learnt/throw-away/index.md index bde6e6a..7f4ace5 100644 --- a/content/books/things-i-learnt/throw-away/index.md +++ b/content/books/things-i-learnt/throw-away/index.md @@ -39,4 +39,4 @@ 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). -{{ chapters(prev_chapter_link="/books/things-i-learnt/always-vcs", prev_chapter_title="Always Use A Version Control System", next_chapter_link="/books/things-i-learnt/future-trashing", next_chapter_title="Future Thinking Is Future Trashing") }} +{{ chapters(prev_chapter_link="/books/things-i-learnt/config-file", prev_chapter_title="The Config File Is Friend", next_chapter_link="/books/things-i-learnt/future-trashing", next_chapter_title="Future Thinking Is Future Trashing") }}