shortform blog entries
Two python functions:
1
2
3
4
5
6
def print_status_and_execute(f):
print("running function " + f.__qualname__)
return f
def add(x, y):
return x+y
You might want to wrap them like:
1
status_printing_add = print_status_and_execute(add)
Which is kind of ok, except that now you have to change all your code wherever you used to use add
to use the new status_printing_add
function.
Instead, you can just decorate the function definition of add
like so:
1
2
3
4
5
6
7
8
9
def print_status_and_execute(f):
def fn(*args, **kwargs):
print("running function " + f.__qualname__)
return f(*args, **kwargs)
return fn
@print_status_and_execute
def add(x, y):
return x+y
And now every instance of add behaves as if it is automatically transformed:
add(a, b) -> print_status_and_execute(add)(a, b)
You can even make decorators themselves depend on arguments, though it requires an extra level of abstraction:
1
2
3
4
5
6
7
8
9
10
11
12
13
def print_n_times(n):
def decorator(f):
def fn(*args, **kwargs):
for i in range(n):
print(*args)
print(**kwargs)
return f(*args, **kwargs)
return fn
return decorator
@print_n_times(5)
def say_hello(name):
print("hello " + name)
Or do fancier things, like create and maintain extra data structures available to their context across function calls:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def memoize(fn):
prev_res = {}
def mem(num):
if num in prev_res.keys():
return prev_res[num]
else:
val = fn(num)
prev_res[num] = val
return val
return mem
@memoize
def fibb(n):
if n == 0:
return 1
elif n == 1:
return 1
else:
return fibb(n-1) + fibb(n-2)
These notes are a stream-of-consciousness response to reading through The Twelve-Factor App at the suggestion of a good friend of mine.
Introduction and Background
Nothing particularly special here. At this high of a level of abstraction, everything sounds like a good and reasonable idea!
Section 1: Codebase
Not too much controversial in here (I hope!). I like the emphasis on strict delineation of codebases between apps, and factoring out shared code into separate libraries under dependency management.
Section 2: Dependencies
This one requires some rigor and automated test tools for enforcement!
Their ending note about extending the philosophy to system tools makes plenty of sense, though it does start to make me wonder how they would handle system tools that might need to be rebuilt for different micro architectures… seems troublesome to end up with nested system compatibility issues…
Section 3: Config
This one is an interesting distinction. Of course you don’t want to save credentials and the like into your code repo, but storing all config as environment variables feels a little like you’re just pushing the problem down the road… you still need tools to set up and manage those env vars for any sufficiently complicated setup, and especially if a single user might need to switch between various configs (when, say, deploying to dev vs test vs qa) it feels like it would be very easy to accidentally end up in a world where your config is now stored in a management program or downloaded from a source location.
Section 4: Backing Services
This is a reasonable set of definitions and goals, but leaves a little bit of documentation and organization discussion to be desired. For example, if you’re using a SQL database as a resource, you may also need to track specific version requirements for that database implementation–especially if you’re relying on specific and/or unusual functionality–but even in the general case, you may want to specify version requirements to align with your testing environment, even if only to make sure to be able to replicate behavior where bugs may be concerned.
These sorts of situations would require some extra state to be stored somewhere beyond just the resource handle.
Section 5: Build, release, run
Again reasonable, with some additional potential trickery around dealing with exploding database sizes in cases where the release may include large binaries / etc.
Section 6: Processes
Very reminiscent of my time with Haskell. I dig it, but there are probably consequences of this approach that I’m not immediately appreciating.
Section 7: Port Binding
This is one I’ll tag for deeper discussion. There’s definitely some stuff I don’t fully grok about sentences like “does not rely on runtime injection of a webserver into the execution environment to create a web-facing service”.
For example, what would doing so even mean or entail? Why might you be tempted to do so?
Section 8: Concurrency
A few questions in here also. What does “daemonizing” mean? What are PID files? Is there some formalism for “process types” that I should be aware of, or is it just a question of nomenclature, fully under the control of the devs?
Section 9: Disposability
This again seems like a “mathematically pure” thought, but one that’s devilish to police via testing in practice. In particular, the linked wikipedia page on “reentrant” was surprisingly subtle.
Section 10: Dev/prod parity
Nice, here’s some discussion of the issues I was thinking about from the “Backing Services” section. Overall this seems like an obviously good idea. I wonder what situations would make it maximally difficult.
Section 11: Logs
Huh. This is definitely an idea in the same vein as the previous ten sections, but it surprised me on first read nonetheless. Just logging everything straight to stdout and leaving log routing and collection to the execution environment definitely makes sense given the rest of this framework. I’ll have to chew on this one a little more to see what I really think of it, but so far no objections, even if it is a change in how I’ve been thinking.
Section 12: Admin processes
This doesn’t actually seem like it’s saying much of anything at all. Basically the message is “standardize everything you can, and use tools to make sure of it”.
Is there something more to this that I’m missing?
I know some people headed to London soon, so for them and anyone else, here are my London recommendations. Do note that these all date from my trips before the onset of covid-19, so you should check the actual availability / openings of things for your specific visit.
Cocktail Bars
-
Dandelyan is absolutely one of the best bars in the world, and certainly the most pioneering of the cocktail bars I’ve presonally visited. These are the sort of people who don’t just use a banana syrup in their drinks, they spend weeks making their own banana syrup, from a plethora of different banana species and individual fruit at different levels of ripeness, each ingredient prepared individually to highlight certain flavor elements in the final syrup. The correct way to visit Dandelyan is to show up as close to their opening time as possible—early in the day!—and grab seats at the bar. Then talk the bartender’s ear off. Ask them about the background behind the drinks. Ask them about the ingredients. How they refined the recipes. What surprised them the most. Order whatever you want, but don’t feel pressured to finish everything, or even anything! The best visits here will give you a chance to sample flavors you simply won’t find anywhere else, and it’s perfectly fine to leave half-finished drinks when you’re done. Delight your taste buds. Save your liver.
-
Mr Fogg’s are top-notch cocktail bars with a lean towards flair and adventure. If Dandelyan is a science lab, then the Mr Fogg’s bars are Disneyland. Tons of fun, really good drinks, and plenty of atmosphere, theme, and delight. You simply can’t leave without a smile. Mr Fogg’s are best visited a little later in the evening. Your goal shouldn’t be to grab time with the bartender while it’s still uncrowded; instead, get there only a little bit on the early side, so that you can watch it fill up, kick back, and enjoy the celebration that’s sure to surround you.
Restaurants
-
Hoppers is one of my favorite restaurants in the entire world. It has a focus on Sri Lankan and South Indian food, so expect bold flavors! But everything, everything, is delicious. Special shout-out to the bone marrow.
-
Dishoom is a series of Indian restaurants in London. They’re much bigger than Hoppers, and tend to have somewhat less bold and specific flavors, but are still delicious, and just extremely solid for a meal.
Other
-
Timber Yard Seven Dials is my favorite coffee shop in all of London. I love the crowds. I love the coffee. I love the location. And I love the snacks. I’ve set up shop there for days at a time, speed-running an online course, just as easily as I’ve used it as an excuse to step in from the cold and enjoy a quick, warm drink.
-
Borough Market is the best damn food market I’ve ever encountered, only Torvehallerne in Copenhagen comes close. Come for the duck wraps. Come back for the charcuterie. Come back again for the cheeses. Come back yet again for the baked goods. Come back one more time for whatever else you feel like. It’s all great. Then hit up the hot chocolate from across the street. It’s all fantastic.
-
High tea is worth doing at least once. On every week. Of every trip. Honestly, it’s a little kitsch, but it’s delicious, it’s fun, you’ve got a billion excellenet choices to pick from, and it’s so London. Note that some of the more expensive options have a refill policy that can actually be quite a good value for your money if you’re hungry enough. For example, I have definitely not ever taken advantage of the Langham’s infinite refills on sandwiches to consume in excess of 23 delicious little tea sandwiches in a single sitting.
Non-Food Thoughts
-
Have at least one set of nice clothes. There are plenty of places in London which, unlike California, actually have dress codes. This means at least pants, a button-down shirt, and a blazer for men. Flip flops and sneakers need not apply.
-
It’ll probably rain. You can deal with it. You won’t melt. And honestly, while you should pack a reasonable coat, you probably don’t need to bring an umbrella. If it’s raining that hard, you can always buy a cheap one when you’re there, or borrow one from your hotel.
-
Shows are a lot of fun! You should try one!
-
Festivals / exhibitions / etc are worth watching out for. Something or other is always passing through London, and you can easily lose a day—or more!—in any of the excellent museums.
-
London has a bunch of great bookshops! Even though I do almost all of my reading on something with a screen these days, I love browsing around and picking up something with pages every once in a while.
-
Yelp has been really quite reasonable for me in London. Also Uber.
-
There’s really not much need to plan day trips in advance if you don’t mind taking the train (and you shouldn’t! it’s great!). Just show up at the station, buy a ticket, and grab the next one.
-
If you’re visiting London for a while, dealing with laundry can be surprisingly tricky. Hotels often charge very high rates, so you may be best served with a local wash-and-fold service.
-
The parks and walking paths are great. There are few things I enjoy more than meeting up with friends in London and catching up over a walk. In any direction. From anywhere. To anywhere. It’s great! Bonus points if you end up passing through one of the many parks, which are always lovely.
-
Shopping is… a thing? I guess? Fortnum & Mason has great tea, and we always bring back a bunch with us whenever we go. Beyond that, London is certainly a major metropolis, with more than enough wealth and fashions to support just about any sort of shopping experience you’re looking for.
-
There are tourist attractions. They usually have lines. At least, I’ve usually seen lines whenever I’ve walked by them. I dunno, it’s not really my thing. I’d much rather wander through Soho with a cup of coffee, or crash a table tennis club somewhere.
-
Speaking of which, activity clubs are myriad in London, and well worth looking up for your trip. Whatever your hobby, you’re very likely to be able to find some club or gathering for it in the city during your visit, and that’s a great way to make friends, have a great time, and get the inside scoop on whatever you want from some locals.
I talk a lot about comparative advantage, and finding ways to trade on it. But one of the things I’ve never directly defended is the idea that strong comparative advantages can exist, and that you can improve your chances of developing such comparative advantages by studying more or less anything at all.
So, here’s a quantitative estimate.
Imagine forming a multi-dimensional vector representing your level of productivity on various tasks. Now, asking whether you are likely to have serious comparative advantages compared to someone else is akin to asking whether your productivity-vector points in a different direction to theirs. What are the odds of that happening, even in the worst case scenario, where your study is left to chance?
To get an idea of the numbers, we’ll pick some different dimensionalities, generate a bunch of random unit vectors of each dimensionality, and just look at the angle between the vectors of the same dimensionality. To make things even more concrete, we’ll pick a cutoff (in this case, ±2°) and ask “What is the chance of two randomly generated unit vectors of a given dimensionality being within ±2° of 90°?” This will tell us not only the chance of having a significant angle between the two vectors, but the chance of the two vectors being nearly maximally un-aligned. Or, in other words, the chance of really significant comparative advantages existing.
So there it is. Study things—almost anything at all, and the more the better—and you’ll be practically guaranteed to develop significant comparative advantages that you can use for mutually beneficial trade.
Unnecessary friction slows your life down. It burns up energy that could be better spent achieving your goals, and it distracts you from important things in order to deal with its own minutiae.
So be careful when crafting resolutions. The death of a resolution is to be complicated or difficult to achieve.
Instead of resolving to get a gym membership and go for an hour every day, resolve to develop two or three healthy habits—maybe one that you do daily, and two more on a weekly cadence—that can fit into your life with low friction, and that which you’ll be able to maintain.
Don’t make difficult resolutions. Instead, resolve to find the easiest steps that will bring you meaningfully closer to your goals.