I want to quickly take notes in the same file throughout the day using VS Code. How do I do that?

My approach has been to use my VS Code extension Run Me, which I use to bind a keyboard shortcut to one of the commands I created. In my particular case, on any VS Code window I can press CTRLNumpad 2 and it will open a file under the following path: buffer/YYYY/MM/DD.md, where YYYY/MM/DD is replaced with the year/month/day. In this file I record all my notes within the day.

I use the following snippet, which I can trigger using dt, then pressing TAB. This replaces the dt string with a string of the form YYYY-MM-DD HH:MM:SS, which is the current year-month-day hour:minute:second.

{
    "Datetime": {
        "scope": "",
        "prefix": "dt",
        "body": [
            "$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND"
        ],
        "description": "Date time"
    }
}

I also use the Script Commands extension to do something slightly more complicated, which is to create strings of the form 2020-03-02 21:19:05 [nid://952], where nid://952 represents a unique note id (nid). The number that is generated is unique and is tracked by storing the last generated number in a text file that is read/written on each call to this command. A cheaper approach could have been to simply use the timestamp as unique note id. One downside of the timestamp as note id approach is that you don't have an idea of how many notes you've recorded so far, other than searching your notes and then counting the number of unique instances.

How do you estimate the size of a project roughly?

When I am asked to provide a rough estimate of the required effort on a project with a lot of requirements or user stories, I first want to make sure that my estimate is in the right order of magnitude. That means that I want to estimate a project that takes 1-10 weeks to be in that range, but not estimate less than a week or more than 10 weeks. Similarly, a project that takes one or more years should not estimated as a job of a few weeks.

My orders of magnitude are as follows:

  • 1 day
  • 1 week (5 days)
  • 1 month (20 days)
  • 1 quarter (60 days)
  • 1 half-year (120/125 days)
  • 1 year (250 days)

As such, when estimating a task, I will say that the task will either take 1 day, 1 week or 1 month. In general, any task that is estimated at 1 month long (or above) needs to be broken down into sub-tasks as it indicates that the task is hiding a lot of complexity.

With this kind of approach, one can estimate that a developer can do approximately 250 small tasks (1 day), 50 medium tasks (5 days) or 13 large tasks (20 days) per year.

Start by creating an estimate of the overall project without thinking about any of the underlying tasks. This is done to have a quick idea of the scale of the project.

Then list and estimate the tasks that will need to be accomplished to complete the project. You might be forgetting a few, but it is fine at that moment. Think mostly of the most important tasks and also the riskiest.

If the sum of the efforts you estimated is in the same order of your original project estimate, then you are done. If not, then you need to investigate and explain what led you to either over or under estimate. Did you forget to estimate some tasks? Did you ignore some tasks when you did your initial estimate? What were the assumptions you made that were right/wrong? Once you are satisfied with your explanation, you are done with estimating.

01 Mar 2020

Read more books

History / Edit / PDF / EPUB / BIB / 1 min read (~169 words)
Questions

How can I read more books?

Make it a priority to read books. Replace some of the existing habits you have with reading books instead.

If you like to spend time reading reddit or hackernews or watching videos on youtube, replace that with reading a book. Of course, it's easier said than done. The best way I've been able to transition from those activities to reading books was to progress slowly. Don't replace reading hackernews one day by reading a book instead. Instead, simply spend 5, 10, 15 minutes reading a book, and then the remainder of the time on reading hackernews. Spend the same amount of time every day reading a book for a week. When a week has passed, increase that amount of time slightly (e.g., go from 5 minutes per day to 10 minutes per day).

As you increase the amount of time you read, you will find it easier and easier to spend time reading instead of doing other activities you might consider harmful or less valuable.

I use VS Code and I'd like to insert templates into my documents. How do I do this?

In VS Code, the concept of templates is called snippets. It is fairly easy to create a snippet, so I won't go into the details. Here's an example of a snippet I use to insert the date and time quickly into my documents.

{
    "Datetime": {
        "scope": "",
        "prefix": "dt",
        "body": [
            "$CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND"
        ],
        "description": "Date time"
    }
}

With this snippet, I only have to type dt and then press TAB and dt gets replaced by the current date and time.

I use snippets to create the template of my questions and problems articles. My current approach is to open a non-existent file by calling code /path/to/new/file and VS Code opens the editor with this file. I can then write the content of this file, which will not automatically save until I manually save. Once I'm happy with the content of my article, I manually save, which means that in the future, any edit I make and then have the editor lose focus will be automatically saved and commit to git (my current workflow).

One of the things I don't particularly like with the current implementation of the snippets system is that the body needs to be a list of strings, where each item represents a new line. It is possible to create a single entry and use \n and \ to format the string, but that is not a clean approach. Those are limitations of jsonc. If it was possible to link to a file, then it would be "easy" to create a clean template.

29 Feb 2020

Slow python imports

History / Edit / PDF / EPUB / BIB / 4 min read (~644 words)
Problems Python

Some imports in my python code are slow. How can I figure out which ones are the source of slowness?

Python offers a really useful functionality you can use that will list how long each import took. By passing the -X importtime argument to your python command when you execute your script it will print out both the cumulative time (including nested imports) and self time (excluding nested imports) of each import.

python -X importtime your-script.py

Running python -X importtime my-script.py on an empty script returns the following (on Windows 7, Python 3.7.5)

import time: self [us] | cumulative | imported package
import time:        52 |         52 | zipimport
import time:       367 |        367 | _frozen_importlib_external
import time:        55 |         55 |     _codecs
import time:       530 |        585 |   codecs
import time:       520 |        520 |   encodings.aliases
import time:      1107 |       2210 | encodings
import time:       328 |        328 | encodings.utf_8
import time:        39 |         39 | _signal
import time:       357 |        357 | encodings.latin_1
import time:        34 |         34 |     _abc
import time:       312 |        345 |   abc
import time:       474 |        819 | io
import time:       113 |        113 |       _stat
import time:       264 |        377 |     stat
import time:       269 |        269 |       genericpath
import time:       794 |       1062 |     ntpath
import time:       871 |        871 |     _collections_abc
import time:       915 |       3223 |   os
import time:       490 |        490 |   _sitebuiltins
import time:        57 |         57 |     _locale
import time:       934 |        991 |   _bootlocale
import time:       421 |        421 |   encodings.cp1252
import time:       472 |        472 |   types
import time:       394 |        394 |       warnings
import time:       440 |        834 |     importlib
import time:       263 |        263 |       importlib.machinery
import time:       554 |        816 |     importlib.abc
import time:        64 |         64 |           _operator
import time:       792 |        856 |         operator
import time:       343 |        343 |         keyword
import time:        43 |         43 |           _heapq
import time:       405 |        447 |         heapq
import time:        85 |         85 |         itertools
import time:       328 |        328 |         reprlib
import time:        69 |         69 |         _collections
import time:      1460 |       3585 |       collections
import time:        44 |         44 |         _functools
import time:       596 |        640 |       functools
import time:       784 |       5008 |     contextlib
import time:       651 |       7308 |   importlib.util
import time:      1095 |       1095 |   pywin32_bootstrap
import time:       231 |        231 |   sitecustomize
import time:     10744 |      24972 | site

For a script with a simple import argparse, I get the following output:

import time: self [us] | cumulative | imported package
import time:        70 |         70 | zipimport
import time:       341 |        341 | _frozen_importlib_external
import time:        54 |         54 |     _codecs
import time:       457 |        511 |   codecs
import time:       456 |        456 |   encodings.aliases
import time:      1030 |       1997 | encodings
import time:       215 |        215 | encodings.utf_8
import time:        38 |         38 | _signal
import time:       268 |        268 | encodings.latin_1
import time:        33 |         33 |     _abc
import time:       398 |        431 |   abc
import time:       311 |        741 | io
import time:        87 |         87 |       _stat
import time:       271 |        357 |     stat
import time:       196 |        196 |       genericpath
import time:       416 |        612 |     ntpath
import time:       714 |        714 |     _collections_abc
import time:       610 |       2292 |   os
import time:       229 |        229 |   _sitebuiltins
import time:        48 |         48 |     _locale
import time:       246 |        293 |   _bootlocale
import time:       217 |        217 |   encodings.cp1252
import time:       488 |        488 |   types
import time:       279 |        279 |       warnings
import time:       461 |        740 |     importlib
import time:       269 |        269 |       importlib.machinery
import time:       557 |        825 |     importlib.abc
import time:        63 |         63 |           _operator
import time:       808 |        871 |         operator
import time:       336 |        336 |         keyword
import time:        41 |         41 |           _heapq
import time:       336 |        376 |         heapq
import time:        69 |         69 |         itertools
import time:       341 |        341 |         reprlib
import time:        70 |         70 |         _collections
import time:      1136 |       3197 |       collections
import time:        69 |         69 |         _functools
import time:       642 |        710 |       functools
import time:       801 |       4708 |     contextlib
import time:       688 |       6959 |   importlib.util
import time:       934 |        934 |   pywin32_bootstrap
import time:       224 |        224 |   sitecustomize
import time:      9323 |      20954 | site
import time:       698 |        698 |     enum
import time:        55 |         55 |       _sre
import time:       417 |        417 |         sre_constants
import time:       372 |        789 |       sre_parse
import time:       443 |       1286 |     sre_compile
import time:       323 |        323 |     copyreg
import time:       716 |       3021 |   re
import time:       725 |        725 |     locale
import time:       948 |       1673 |   gettext
import time:       986 |       5678 | argparse

The package are listed in order that they are resolved. In argparse case, os and sys were already loaded, so it first loads re, then gettext. Once both are loaded, argparse has finished loading.

The way the cumulative column is computed is to take all the prior self that are a level higher than the package you're looking at. For example (if we take the io package):

import time:        33 |         33 |     _abc
import time:       398 |        431 |   abc
import time:       311 |        741 | io

311 + 398 + 33 = 742

We can see here that the numbers are not necessarily equal to one another, this might be due to precision used to do the computation while the rendering of numbers is rounded.

Note that the load time of a package may be different depending on which script you load because dependendencies of the package may have already been loaded in some cases, while in others it may have to load them.

Looking at text might be your thing, but if you're more visual, there's a tool called tuna which will consume this output and create an icicle plot you can look at to find which imports are the slowest/longest.