Reflections after two years of living here
- Probably the only truly walkable community in Florida of its size.
- At high risk for climate change, and yet:
- Businesses leave their doors open to leak AC out onto the road
- cruise ships go out constantly, sitting at port burning raw
- Tons of new construction
- A distinct city from Miami. Own government, police, fire, etc
- Tons of condo associations. The presidents of the respective condo associations form a city/neighborhood-level association that has some say in local development. e.g. when five park was going up, the Big Association negotiated the creation of a public park and a pedestrian bridge in exchange for the building..
- Pricy as all hell. Cost of living statistics can not be correct.
- South beach is surprisingly quiet and residential on the west side of the
island. as you move east noise and tourist activity steadily increase. I would
say Pennsylvania and east is unlivable due to this, especially during the
Three Bad Weeks of the year to live in miami beach:
- Miami Music week
- Spring break (generally 2-3 weeks)
- Art Basel
- Three main neighborhoods in the city of miami beach: south beach, mid-beach, north beach. Notable minor neighborhoods: South of Fifth, Sunset Harbor. Weird places that aren’t on the island proper but are nevertheless intertwined: Hibiscus/Palm/Star Island, Fischer Island, the Venetian Islands.
- Man-made island: used to be attached to the peninsula but was opened up to allow boats to flow both ways around the bay
- Cruise ships are hilariously tall. We live on the fifth floor and they are taller than ten story buildings when they are leaving.
- Companies will post an identical (remote) role in 50 different cities. Each of these shows up as a separate job listing.
- No way to filter out jobs I’ve already applied to
- Promoted results are the overwhelming majority of the results on each page. (25/25 on the page I’m on). I found some ublock origin filters to hide these and, just as an example for four pages of results (25 per page): first page is all promoted (filters show page empty). second page is three roles (i.e. 22 promoted roles). All three of these roles are the same job at the same company in three different locations. Third page has 15 roles (10 promoted). 11 are the same role as on page two.
- Jobs that have been “reposted” count as newly posted. So you can filter by “Jobs posted in the last 24 hours” and see pages of jobs with hundreds or thousands of applicants
- You can specify you only want to see in-person or hybrid roles for a particular search and still see remote roles (both promoted and not promoted)
Work for a client has required working with Excel files. The work I do for this client results in a website (built with Biff) whose pages are utilities that automate previously-manual parts of their business processes. Many of these utilities take an Excel spreadsheet as input and output some report as TSV/CSV/Excel. The code I write for them is private, but I wanted to collect snippets of how to handle these transformations in a generic way.
Over the course of my last regular bout of therapy, my therapist got me to learn about behaviors that he referred to as my mental health toolkit. Some of these behaviors are things we learned are necessary every day (as close as I can get to it) while others are good for times of more difficult mental health challenges than the usual. I’m listing them partly to have them written down for myself, but also in the hopes someone finds a behavior that helps them too. A mental health toolkit can include behaviors that my good friend Mark calls ‘psychic anchors’ — things you can do to center yourself when you find yourself in need.For my particular set of mental illnesses, the behaviors I want in my toolkit are those that induce my body to create dopamine (among other regulatory neurotransmitters). Part of the challenge is that some dopamine-creating behaviors don’t go about dopamine production in a “sustainable” manner; instead, they cause a dopamine spike. You might feel good, really good, for a bit, but then the crash comes and you might end up feeling worse than before. Another part is that there isn’t a prescriptive set of the sustainable behaviors that we’re looking for that works for everybody. One person’s positive mental health behavior might be another’s mental health incident trigger. You’ve got to experiment.
I should note I’m not an expert: I’m just a guy that works at Computer. I have gone to many (many) years of therapy, though. This is what I’ve learned works for me, and my layman analysis of what that might mean for my brain.
Another important point is that these behaviors don’t always work. Some days you can do everything right and still be in the mud psychologically. One of the many injustices of mental illness. But we must do what we can.
This is an important one, and one that most people (anecdotally) find great success with. For me, just going on a long walk isn’t enough. I need to get my heart rate up! Cardio and weight-lifting are great for this. I’m not as consistent as I should be but I do feel a large difference in my baseline mental health even going just once.
It was kind of funny to find out how much this helped me. I always dreaded doing household chores (the self-sabotaging nature of ADHD is horrific) but once I realized how much better I feel when our space is neat I started actively seeking out opportunities to pick up. This positive feedback loop is very powerful:
I feel good -> let me clean up a little
↑ ↓
↖ ↙
Our space is clean
While this one is dangerous:
I feel bad -> tidying up is the worst thing I can imagine
↑ ↓
↖ ↙
Our space is messy
I wasn’t able to really harness the positive feedback loop until I started taking medication that actually worked for me.
I spent years in undergrad trying but failing to find medication that worked for me. This type of diagnosis is hard! Eventually I just stopped taking medication altogether and dealt with life raw. It was only when I started seeing my latest therapist that I was able to get a proper diagnosis. After a couple sessions with me, he blew my mind when he said I had “a textbook case of undiagnosed adult ADHD.” ADHD medication changed almost everything about how I engage with my life. It can’t and won’t be a solution for everyone, but if you have a therapist and doctor you trust and they recommend something, I hope it is helpful.
I spent most of my life thinking I was an introvert because I felt awkward in social situations. Some of those feelings were certainly part of the process of coming into my own as a person — finding your way as a teenager and young adult can be hard! Looking back, I now recognize that many of those feelings stemmed from mental illness. That type of feeling can often push you away from socializing.
I learned I’m not an introvert when the government began reducing COVID restrictions and people started congregating again. I’ve always worked from home, but because I started working professionally in 2021, I had no ability to get out of the house for much of my early professional life. Once I had the ability to do so, I realized I needed to — that social contact was deeply energizing for me in a restorative way. This is different than for my partner, who is a self-described “extroverted-introvert”. She feels the need to recharge her social batteries with some alone time after a series of repeated outings.
Getting adequate amounts of socializing is tough, because working from home means I don’t really have a “third place”.[fn:1] A potential solution is just paying for one by going to a local coffee shop or buying access to a co-working space. Though I do like to go to our local coffee shop, it isn’t a perfect solution because of the ongoing costs, the un-ergonomic work environment, and the difficulties of taking meetings in a public space. Co-working spaces are even more expensive than a daily coffee or two. This is all cheaper than a daily commute, of course.
“Just go out on weekends” is not an end-all solution either. Weekend outings are great, and definitely help! But they yield a big dopamine spike compared to the steady socializing you might get from a co-working space or commuting to an office.[fn:2] This isn’t something I always want to do, either — if my partner wants to stay in to decompress, going out means her sacrificing her social battery recharging time for my well-being (I love her for this, but it’s not ideal) or it means not necessarily spending quality weekend time together. It certainly isn’t a requirement that we be joined at the hip all weekend, so sometimes I go this route. Going out, of course, costs money. Very few social places remain where you can go without paying for the privilege.
I have contemplated getting an in-person or hybrid job, but the Miami tech scene is not conducive to my doing so. There’s a lot of reasons for this that aren’t related to this post, so I won’t get into them. I would also probably have to buy a car, which seems like nasty business given how much I’ve enjoyed being car-free for the last couple years.
My boss at my first software job (a great person) taught me this one when I expressed I was overwhelmed with the number of tasks I had to do for a project. He told me to write everything down to get it out of my head. It is shocking how much it helps. My therapist later taught me I should be doing this for my personal things too. Especially in moments where my mental health is poor, journaling helps me to externalize those thoughts.
One of my first girlfriends (my first serious girlfriend) taught me about writing a letter when you’re angry at someone, explaining how you feel. Then you shred or burn it. The process of writing down how you feel while addressing it to someone is a calming exercise that helps you settle before talking to the person about how you feel (related: “Never send an email when you’re angry.”)
Blogging is a similar tool. I’m doing it right now! I think it’s better for writing about things I’ve learned and want to have somewhere than for my thoughts and feelings, especially when I’m in a poor state of mental health — the privacy of the journal page brings a lot of psychological safety. I also don’t have to edit out curse words. But having a written, public record of an idea makes you refine the thought in a way that journaling doesn’t. You have to pick the right tool for the job.
This is the primary “psychic anchor” I learned from Mark. This doesn’t refer to a needed shower as part of a regular hygiene schedule, though it can. This refers to the positive effect of taking a step out of the (physical, mental, emotional) space I’m in and taking a quiet couple minutes in the shower. It’s really effective and helps a lot for anxiety. This is more of a “quick fix” type strategy than the others, but the dopamine spike is long lasting.
I’ve been dabbling with cold showers recently, and have really been enjoying it. I can’t explain why, but after the initial five seconds of “damn, that’s cold!” I feel good. It feels good to do something that involves “mental toughness” but that isn’t the only aspect that’s pleasant about it.
Lily and I wear retainers every night. We clean them daily using a regular toothbrush and liquid hand soap. Cleaning these retainers at the end of the day, before bed, is one of my least favorite chores. I dealt with that for a long time! I would delay, put it off, getting in to bed fifteen or twenty minutes later than I would have if I would have just washed the damn things as soon as I finished flossing and brushing my teeth. For a while, I tried cleaning the retainers before the flossing and tooth brushing, but that didn’t improve things. After a while I figured out a way to resolve my issue: I now clean our retainers in the morning, immediately after brushing my teeth. It’s the easiest thing in the world at that point in the day, but feels impossible at night.Though my issue with the nighttime retainer cleaning is probably just a classic ADHD Moment, after I got the morning thing going, it got me thinking about task ordering. It’s not a novel idea that tasks have orderings. A simple example is a task where you don’t have the knowledge to accomplish it yet. You can’t accomplish it without getting the knowledge first. Not every ordering is “strict”, though — the retainer cleaning saga involved at least three orderings.
floss -> nighttime tooth brushing -> clean retainers -> get in bed
clean retainers -> floss -> nighttime tooth brushing -> get in bed
wake up -> random morning things -> morning tooth brushing -> clean retainers -> [ .. the whole day .. ] -> floss -> nighttime tooth brushing -> get in bed
Once I had noticed that, I realized I’d seen variations of the concept before.
Structured Procrastination is well known, and one of my favorite essays of its kind. It’s about ordering your tasks so that there’s always something you don’t want to do (but have committed to doing) at the “end of the list.”
CPUs do out-of-order execution.
The Engineer/Manager Pendulum is about flipping the traditional
Start Career -> IC -> Management -> End Career
order into
Start Career -> IC -> Management -> IC -> Management -> End career
↑ ↓
↖_______↙
There are algorithms that utilize amortization to improve their average performance. C++’s std::vector
notably uses this technique to achieve (amortized) constant cost when growing in capacity. This is a reordering of tasks from this expensive loop:
Make vector with capacity 1 -> add item -> increase capacity
↑ ↓
↖_______↙
To one that minimizes the number of times we increase capacity
.
DFA minimization is an algorithm for reducing the number of states in a (deterministic and finite) automaton. We remove states if we can show they’re equivalent. Now that I think about it, removal is only sort of like reordering. There’s a world of difference between “I clean my retainers in the morning instead of at night” and “I don’t clean my retainers”.
Project management tools are all about task reordering.
Task reordering isn’t a magical solution. I despise washing our coffee pot and can’t find a good time of day to do it. Part of the problem is that we don’t use it every day; some mornings we have tea, yerba mate, or go out for coffee instead. Maybe if I worked the washing of the coffee pot into a fixed place in my daily routine, I would realize it’s in the wrong place in the routine, place it correctly, and then be able to wash it as easily as I clean the retainers.
Maybe part of the problem is that reordering tasks only works for low-friction tasks where the cost to start doing them is low. Some tasks are really four or five tasks dressed in a trench coat disguised as a single task, and it’s not always easy to tell that from a todo list. Comparing “cleaning the retainers” to “washing the coffee pot” doesn’t convey any of this context. But cleaning the retainers takes two minutes at most, while the coffee pot involves making sure there’s space on the dish drying rack, ensuring there’s space in the sink, putting on the dishwashing gloves, then washing the four separate pieces of the coffee pot ensemble.
Those first two steps (of the single “washing the coffee pot” task!) might create a cascade of new tasks. If the dishes on the drying rack are wet, we’d have to dry them then put them away. Is the sink full because the dishwasher is running? If that’s the case, maybe there isn’t space in the sink to wash the coffee pot. This can go on and on.
Getting things done is hard, especially with executive function disorders like ADHD. Thinking about the order of tasks has helped me a great deal.
Here’s how I set upmu4e
with Doom Emacs on Arch Linux for my custom domain
hosted on iCloud. I’m using mbsync
, mu
, and msmpt
. I originally went with
a systemd timer as detailed in the first two sections as recommended in the Arch
wiki, but mu4e
actually has a built-in functionality to deal with this for us.
Note that what I’ve written here is the minimum I needed to do to actually
sync, send, and read emails from emacs
. There’s a lot more you can do.
In init.el
, under :email
(mu4e +org)
config.el
:
(set-email-account! "icloud"
'((mu4e-sent-folder . "/icloud/Sent")
(mu4e-drafts-folder . "/icloud/Drafts")
(mu4e-trash-folder . "/icloud/Trash")
(mu4e-refile-folder . "/icloud/Archive")
(smtpmail-smtp-user . "lucianolaratelli")
(mu4e-compose-signature . "\n\nLuciano"))
t)
(after! mu4e
(setq sendmail-program (executable-find "msmtp")
send-mail-function #'smtpmail-send-it
smtpmail-stream-type 'starttls
message-sendmail-f-is-evil t
message-sendmail-extra-arguments '("--read-envelope-from")
message-send-mail-function #'message-send-mail-with-sendmail))
In $HOME/.config/system/user/mbsync.timer
:
[Unit]
Description=Mailbox synchronization timer
[Timer]
OnBootSec=1m
OnUnitActiveSec=5m
Unit=mbsync.service
[Install]
WantedBy=timers.target
$HOME/.config/system/user/mbsync.service
:
[Unit]
Description=Mailbox synchronization service
[Service]
Type=oneshot
ExecStart=/usr/bin/mbsync --verbose --all
[Install]
WantedBy=default.target
$HOME/.mbsyncrc
:
# imap account information
IMAPAccount icloud
Host imap.mail.me.com
User lucianolaratelli@icloud.com
PassCmd "secret-tool lookup email luciano@laratel.li"
SSLType IMAPS
Port 993
# remote storage (use the imap account specified above)
IMAPStore icloud-remote
Account icloud
# local storage
MaildirStore icloud-local
Path ~/Dropbox/mailbox/icloud/
Inbox ~/Dropbox/mailbox/icloud*Inbox
Subfolders Verbatim
# channel to remote storage
Channel icloud
Far :icloud-remote:
Near :icloud-local:
Patterns *
Create Near
Sync All
Expunge Both
SyncState *
The crucial part when you’re using a custom domain hosted on iCloud is to use
your iCloud email address instead of the custom one. I thought this was a bug
with custom domains (I’ve run into another one) but I called Apple’s support and
they told me I needed to use the iCloud email address. You can find this on an
iPhone or iPad by going to Settings, tapping on your name up top, and tapping on
Name, Phone Numbers, Email
. I had @me.com
and @icloud.com
emails there. I
went with the @icloud.com
one. Apple’s docs on third-party iCloud clients say
you can use just the part before the domain, but I included the whole thing just
in case. Without further ado, $HOME/.msmptrc
:
defaults
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.maildir/msmtp.log
protocol smtp
account icloud
auth on
host smtp.mail.me.com
port 587
protocol smtp
from luciano@laratel.li
user ${ICLOUD_EMAIL_ADDRESS}
passwordeval "secret-tool lookup email luciano@laratel.li"
tls on
tls_starttls on
account default : icloud
I have tls
and tls_starttls
both on. I think I only need one of these, but I
don’t want to muck with testing my mail configuration to get a blog post out.
You might need one, the other, or both. Exercise for the reader!
I was originally using gpg
as described by Erich Grunewald in his very helpful
post, but unlocking my yubikey every five minutes became a pain and I figured my
login keychain was secure enough for my (unsophisticated) threat model.
yay mbsync
sudo pacman -S msmtp
yay mu mu4e # impossible to find mu otherwise
mkdir -p ~/home/Dropbox/mailbox/icloud
mbsync -Va
mu init -m ~/Dropbox/mailbox --my-address luciano@laratel.li
mu index
systemctl enable --user --now mbsync
systemctl enable --user --now mbsync.timer
doom sync
At this point you can run emacs
, <SPC> o m
, and get to emailin’!
This was working fine but I wasn’t getting in-=emacs= notifications when new
emails came in, even though mbsync
was running on schedule! So I got rid of
the mbsync.timer
service with systemctl disable --now --user mbsync.timer
. I
kept mbsync.service
so that my email syncs when I log in for the day. Then, in
my config.el
:
(after! mu4e (setq mu4e-get-mail-command "mbsync --verbose --all"
mu4e-update-interval 300))
I restarted emacs
and I was good to go.
- Tecosaur’s awe-inspiring config
- The already-mentioned post from Erich Grunewald
- The Doom Emacs
mu4e
module documentation (also from Tecosaur) - davemail
- This article, though it focuses on macOS
DigitalOcean (DO) Functions: “a serverless computing solution that runs on-demand, enabling you to focus on your code, scale instantly with confidence, and save costs by eliminating the need to maintain servers.” Since I’m a fanatic, I would like to write some Clojure for my serverless use case. Because DO offers Node as a runtime, we’re able to use ClojureScript to write code and deploy it to the serverless, er, server.
Source code for this blog post is available.
You’ll need a DO account. Log in, select the appropriate team, then select Functions
on the left-hand column. Create a function namespace and you’re ready to go.
Next we need the doctl
binary. Here’s what I did:
brew install doctl
doctl auth init
doctl serverless install
doctl serverless connect
This gets you authenticated with DO so you can deploy from the command line.
npx create-cljs-project do_serverless
cd do_serverless
Now, let’s edit the generated shadow.cljs
a bit. Add this map as the value under :builds
:
{:core {:target :node-script
:main core/main
:output-to "packages/do-serverless/core/core.js"}}
Create src/main/core.cljs
and define main
in it:
(ns core)
(defn main [])
Create packages/do-serverless/core/package.json
with this in it:
{
"name": "core",
"version": "1.0.0",
"description": "CLJS on DO!",
"main": "core.js",
"dependencies": {
"source-map-support": "^0.5.21"
},
"devDependencies": {}
}
Lastly, create project.yml
:
packages:
- name: do-serverless
actions:
- name: core
runtime: nodejs:default
OK! Let’s see where we’re at:
shadow-cljs release core
doctl serverless deploy .
Now we can go to the Functions tab on DO’s site and run our function by first going to the function namespace, clicking on the name of the function, and hitting Run. I get this error:
2023-01-12T11:14:08.172732642Z stdout: Action entrypoint 'main' is not a function.
What tha…
At this point, I dug around and found that DO maintains a bunch of sample functions. Going to the Node one, we see this:
exports.main = (args) => { ... }
Huh. OK, so let’s do that in our example, src/main/core.cljs
:
(ns core)
(defn main [& args]
(println "hello!")
(println "args: " args))
(set! js/exports.main main)
And re-build and deploy.
2023-01-12T11:22:14.933096349Z stdout: hello!
2023-01-12T11:22:14.933797937Z stdout: args: nil
2023-01-12T11:22:14.961195498Z stdout: hello!
2023-01-12T11:22:14.982016323Z stdout: args: (#js {} ... // output truncated
Ok, so when our function executes, our main
gets executed twice. I don’t know why this happens. If I run our compiled javascript file locally with node
, I only see one execution:
$ node packages/do-serverless/core/core.js
hello!
args: nil
So, OK, some detail that’s above my head. My use case for serverless would, uh, not do well with running everything twice. So, what to do?
Well, we know whatever we tell shadow
our main
is will get run. And we also know whatever we tell DO our main is (the js/exports.main
bit) will also run. Well, I only care about the DO side of things!
(ns core)
(defn my-actual-function [& args]
(println "hello!")
(println "args: " args))
(defn main [])
(set! js/exports.main my-actual-function)
2023-01-12T11:28:57.786063804Z stdout: hello!
2023-01-12T11:28:57.793552189Z stdout: args: (#js {} ... // output truncated
Neat!
[fn:2] This is a huge topic on its own; I don’t want to derail by getting into the 800 externalities on each side of the WFH debate.
[fn:1] See wikipedia