Author Archives: kevin

About kevin

I write the posts

Speeding up Javascript Test Time 1000x

*This post originally appeared on Shyp's engineering blog in July 2015. It has since been deleted. It is reproduced as closely as possible here. The original is accessible on the Wayback Machine.

Eight months ago when I ran our core API tests at Shyp, it took 100 seconds from starting the test to seeing output on the screen. Today it takes about 100 milliseconds:

Screenshot of a fast test run

Why Bother?

There are a lot of different demands on your time, why is a speedy test framework so important? Here are a few reasons we put a premium on being able to run tests quickly.

  1. Deployments get faster. Our build/deployment server runs every test before a deployment. Making our tests faster means that we spend less time between pushing code and seeing it live in production. In situations where production is broken and we need to push a fix, faster tests mean we can get that fix to production more quickly.

  2. Gains accrue over time. We run tests 400-500 times a day; a ten second improvement in every test run translates to an hour of saved developer time, every day.

  3. Slow tests lead to context switches. Context switches are harmful. Distractions are everywhere with Slack, push notifications and open-plan offices. A ten or twenty second delay between kicking off a test run and viewing the results means you might be tempted to check email or Twitter or do any other activity which causes you to lose focus on the task at hand. Faster tests mean you can stay focused more easily.

    Our target is to get feedback within 100ms; that’s about as much time as a UI can take before it stops feeling responsive and your mind starts to wander.

  4. Fast tests lead to better code. We are subconsciously biased against things that are slow. Amazon famously found that 100ms of latency costs 1% of sales. You might want to refactor a module, but subconsciously decide not to, because refactoring implies running the tests, and the tests are slow. You might not write an extra test you really should write, because it means running the test suite again, and the tests are slow. You might decide not to be curious about a test anomaly, because narrowing down the issue would require running the tests, and the tests are slow.

For these reasons, it’s important to us that we start to see test output in under 100ms. Fortunately, we were able to hit that goal. How did we do it?

Measuring Performance

The first step to making anything faster is to measure how fast or slow it is. At a minimum, you’ll want to measure:

  • How long it takes before the first test starts running

  • How long it takes to perform any global, per-test setup/teardown actions

  • Minimum amount of time to do a database read (for us, 4ms)

  • How long each test takes. If you run your tests with mocha, I encourage you to set the --slow flag to 2 (milliseconds) so you can clearly see how long each test takes to run.

There’s an awesome Unix tool called ts (available on Macs via brew install moreutils) that will annotate every line of your test output with a timestamp. Pipe your test output through ts like so:

mocha test/api/responses/notFound.test.js | ts '[%Y-%m-%d %H:%M:%.S]'

And you’ll get test output annotated with timestamps with millisecond precision; all you need to do is find the right place to put console.log lines.

[2015-04-19 21:53:45.730679] verbose: request hook loaded successfully.
[2015-04-19 21:53:45.731032] verbose: Loading the app's models and adapters...
[2015-04-19 21:53:45.731095] verbose: Loading app models...
[2015-04-19 21:53:47.928104] verbose: Loading app adapters...
[2015-04-19 21:53:47.929343] verbose: Loading blueprint middleware...

We observed right away that a) our Node framework requires a ton of files before starting a test run, b) require is synchronous, and really slow in Node (on the order of milliseconds per file imported), and c) There were a ton of stat() syscalls to try and load modules in places where those modules did not exist.

The latter problem is documented in more detail on my personal blog, and there have been two promising developments in that area. First, Gleb Bahmutov developed the cache-require-paths library, which helps Node remember where it found a file the last time it was imported, and avoids many wasteful/incorrect file seeks. Gleb observed a 36-38% speedup when loading an Express project - our speedup was closer to 20%, but we are still really glad this tool exists.

Second, Pierre Ingelbert submitted a patch to io.js to avoid extraneous stat() syscalls in directories that do not exist. This patch was part of the io.js 2.3.1 release.

Loading Shared Folders Kills Performance

We run our tests in a virtual machine, so our development environment matches production. The core api project is shared between the host machine (usually a Mac) and the VM. Loading the test suite means that a lot of files in the node_modules directory are being loaded. If that node_modules folder lives inside the folder that’s being shared, the VM will have to reach across the system boundary to read it, which is much slower than reading a file inside the virtual machine.

It was clear we needed to install our node_modules folder somewhere inside the VM, but outside of the shared folder. Node’s NODE_PATH environment variable provides a mechanism for loading a folder saved elsewhere on the filesystem, but our Javascript framework hard-codes the location of the node_modules folder in its imports, so it failed to find the files we had placed elsewhere.

Instead we installed the node_modules folder elsewhere and symlinked it into place. Here’s a bash snippet you can use to replicate this behavior.

pushd ~/api
    npm install --prefix /opt/lib/node_modules
    ln -s /opt/lib/node_modules ~/api/node_modules
popd

Savings: This sped up test initialization time by a whopping 75%, or one minute and fifteen seconds.

More Specific Regex

We used to specify a test to run by typing mocha -g 'testname' at the command line. Unfortunately, mocha always loads a mocha.opts file if it is present, and our mocha.opts file hard coded a filename regex that matched every single test file in our system (100+ files). We added a new test runner and instructed people to manually specify the test file they want to run.

Savings: This sped up test run time by about 50% (10-13 seconds).

Stubbed database reads/writes

The old test framework would do authentication by writing a valid access token to the database, then reading/returning the valid access token in the controller. We introduced a synchronous signIn test helper that stubbed these two network calls.

Savings: 10-20ms across ~600 tests, a 6-12 second improvement.

Batched writes

In some instances we need to instantiate test environments with users, drivers and other objects. Previously the test helper would write one record, read the id, and then write a record that depended on it. By generating ids up front, we were able to perform multiple writes at the same time.

Savings: 10-20ms across ~200 tests, a 2-4 second improvement.

Faster test cleanup

Between each test, we delete all records from the database. The helper responsible for this would open one database connection per table and then each one would call DELETE FROM <tablename>. Not only would this occasionally hang with no stack trace, it meant that the speed of the cleanup operation was the same as the slowest DELETE query.

Instead we grouped all of the deletes and sent them to the database in a single connection (e.g. Model.query("DELETE FROM users; DELETE FROM pickups; ...")). Some reading online indicated TRUNCATE would be faster than DELETE; plus, it lets you use one command for everything, e.g. TRUNCATE TABLE users, pickups, .... For large datasets it is likely faster, however we observed this to be much slower than DELETE for our small test data sets, on the order of 200ms per action.

An optimization we’d like to implement in the future would only issue DELETEs for tables that have dirty data, which would also let us avoid issuing a DELETE if a test didn’t hit the database. Currently we’re not sure about the best way to hook into the ORM and determine this.

We’re also interested in running every test in a transaction. Unfortunately the ORM we use doesn’t support transactions, and we are very worried about upgrading it.

Savings: Clearing the DB used to take 14-30ms per test, now takes 3-11ms, a ~20 second improvement.

Don’t Load Sails

Our Javascript framework (Sails.js) needs to require every single model, controller, and service before it runs; this is the slowest part of the test run by far.

Where possible, we try to avoid loading Sails when writing/running tests. We try to implement most of our business logic in plain Javascript classes or modules, outside of models and controllers. If this logic operates on objects in memory, you can use fake model objects in your tests - var user = {email: 'foo@bar.com'}, and avoid loading Sails entirely.

Avoiding Sails isn’t possible in every situation, but we’ve found it’s a useful design principle - it helps us separate our business logic and our data storage layer, and will make it easier for us to move off Sails in the future.

For more on this technique, you should check out Gary Bernhardt’s excellent Destroy All Software series of videos. He gave a great introduction to his “don’t load Rails” style of testing at Pycon in 2012 (summary here).

Tighter Editor Integration

Most of the time the test you want to run is the same one that is right underneath your cursor, so manually specifying the filename at the command line wastes time. The awesome vim-test plugin makes it incredibly easy to map leader commands for running the current suite of tests or the current file. It worked on literally the first try; I’ve rarely been so impressed with a piece of software.

Some of our team members use Sublime Text, and we haven’t figured out how to get their editor integration set up yet. It’s on our to do list for this quarter.

Savings: One context switch and ~1-3 seconds per test run.

Avoid Reloading All Dependencies Every Test Run

After all of this we were able to get test run time down to about 7 seconds. Most of this time is spent waiting for v8 to parse/require ~500 files.

We can go much faster if we loaded every dependency once when we sat down at the computer, and then only re-required the files that had changed. You can do this by hacking with Node’s require.cache. I don’t recommend it for production, but it works just fine.

Anyway the end result of this is a command line client and a server called Lucifer. Start Lucifer when you sit down at your computer. When we change a file, we call lucifer invalidate [filename] (or configure our editors to do this for us), which invalidates the cache for that file, and then re-requires it. Then you can kick off a test run by calling lucifer run [filename] from the command line (or from your editor). When you kick off a test every dependency is ready to go, which means your tests start in about 100ms.

Screenshot of a fast test run

Savings: Test initialization time went from 6-7 seconds to 100ms, a 60x speedup.

Caveats

This is similar to the approach taken by spork in Ruby - keep a server up and reload changed files. The same failure modes that apply to Spork - increased complexity, subtle inconsistencies, failure to reload files - apply here. In particular, we’ve found that sometimes Node doesn’t wipe the cache for files that have changed, so new code won’t get loaded. This is probably a result of our limited understanding of how and where Node caches loaded dependencies. We always do a clean run of our test suite on our build server before deploying to production.

Still, it’s been very useful in certain situations - if you’ve flushed out a method or a controller and are writing several tests in quick succession, the only file that’s changing is your test file, so the chance of subtle dependency breakage is low.

Lessons

Your slow test suite isn’t hopeless! But improving it is probably going to take a concerted investment. You also have to get know your stack really well, which is probably a good idea anyway. Look at all of the places we had to inspect to find performance improvements:

  • File reads in a virtual machine
  • The require function in Node
  • Test workflow
  • Use batching to avoid database connection overhead
  • Editor integration

You don’t know what will be slow until you measure it. You’ll also want to know how to use basic profiling tools for your stack:

  • the ts command
  • Strace/DTruss (not covered in depth here, but extremely useful for observing system calls/timings for a running process)
  • Logging / timing for queries that hit the database
  • Logging and profiling your test run time

We’re hiring!

Our team of ten engineers powers four warehouses, four mobile apps, hundreds of drivers and loads of pickups every day. We’re looking for people who are curious about the tools they use and eager to improve their productivity day in and day out. We’d love to hear from you; you can’t waste our time by getting in touch.

Errata

Some odd things I found while profiling:

Liked what you read? I am available for hire.

Let Us Open URLs in a Specific Browser Profile

Most browsers have the ability to launch different browser profiles. Each profile can come with a different theme and a different set of website logins (cookies, application state, etc). This can be helpful if you want to segregate browsing behavior. For example, I have different browser profiles set up for my personal email, my "consulting" email, the nonprofit I volunteer with.

Browser dialog that lets you select a profile

Along with this, command line tools frequently open URL's for various purposes. Docusaurus launches http://localhost:3000 so you can view documentation content in your browser. Lots of different tools open browser profiles to complete authentication workflows - for example, Tailscale starts a web server on your local computer, asks you to log in via the browser, and then redirects to the local web server with a valid token.

When you have multiple profiles, it's frustrating when a URL opens in the "wrong" profile, because this means it's frequently opening in a window where you're not logged in. When this happens, web services typically redirect you to a login page, and remove the information about the URL you were trying to visit (or store it in a cookie). This means if you try and copy and paste the URL to the "right" profile, you frequently lose track of the initial URL you wanted to visit! Very annoying.

Fortunately it turns out there is a solution to this! The way most command line tools open URL's on Macs is by simply invoking open (/usr/bin/open), followed by the URL.

$ open https://example.com/path/to/page

But you can pass additional arguments to the application with --args, and Chrome/Chromium support arguments that let you select the right profile.

open -na "Google Chrome" --args --profile-directory="Profile 4" --new-tab "https://example.com/path/to/page"

That will always open URL's in "Profile 4", whatever you have that configured to.

How do you find which profile is which? The simplest way is to open chrome://version in your URL, and then look at the last bit of "Profile Path" in the page that opens there - it should be 'Default' or 'Profile N'.

Screenshot of the chrome version page, with the profile directory highlighted

On Firefox, you provide the name of the profile from about:profiles, e.g.:

open -n -a "Firefox" --args -no-remote -P 'kevin@burke.services' -new-tab 'https://example.com'

Example configuration

If you operate a command line tool (or an application that has access to /usr/bin/open!), particularly one that opens URL's for authentication, please consider implementing support for opening URL's in specific browser profiles. Example configuration options might be:

# The name of the application you would like to use to open URL's. Defaults to
# "Google Chrome"
browser_application = "Google Chrome"

# The specific browser profile to open URL's in.
browser_profile = "Profile 5"

And then your CLI tool would implement logic similar to this, in the language of your choice, instead of just shelling out to open.

cmd = ['open', url]
if browser_application and browser_profile:
    if any(name in browser_application.lower() for name in ['chrome', 'chromium', 'brave', 'edge']):
        cmd = ['open', '-na', browser_application, '--args',
               f'--profile-directory={browser_profile}', '--new-tab', url]
    elif 'firefox' in browser_application.lower():
        cmd = ['open', '-n', '-a', browser_application, '--args',
               '-no-remote', '-P', browser_profile, '-new-tab', url]

subprocess.run(cmd, check=True)

Please consider implementing this change in your CLI tool! It would really help improve usability for CLI based tools. With sufficient interest, maybe we could create an RFC for both the arguments browsers should accept, and for environment variables that can be read by CLI's for opening URL's in a given browser.

Liked what you read? I am available for hire.

github.com/garyburd/redigo has been deleted

One of the first ever Redis libraries for Go was hosted at github.com/garyburd/redigo.

It has been deprecated for some time and has now been finally removed altogether from Github. If you still have a dependency on this project, this means that will be broken now.

github.com/gomodule/redigo should be a drop-in replacement for github.com/garyburd/redigo. If you still depend on the old service, update the organization name, and you should be good to go.

My hope in writing this is to save time for the next person who is searching for a replacement for this library. Please pay it forward by taking a tiny bit of extra time the next time something breaks, and tell people how to fix the problem.

Liked what you read? I am available for hire.

Transcript of Oval Office meeting between Volodymyr Zelensky, JD Vance, and Donald Trump – February 28, 2025

Source: CSPAN

Transcript was generated using OpenAI Whisper and then cleaned up using ChatGPT o1 pro. All errors are mine.

Volodymyr Zelensky
Do you, and now I’m talking with my friends in Poland, and they are worried that you align yourself too much with Putin.
What’s your message for them?

Donald Trump
Well, if I didn’t align myself with both of them, you’d never have a deal.
You want me to say really terrible things about Putin and then say, “Hi Vladimir, how are we doing on the deal?”
That doesn’t work that way.
I’m not aligned with Putin, and I’m not aligned with anybody.
I’m aligned with the United States of America and for the good of the world.
I’m aligned with the world, and I want to get this thing over with.
You see the hatred he’s got for Putin.
It’s very tough for me to make a deal with that kind of thing.
He’s got tremendous hatred, and I understand that, but I can tell you the other side isn’t exactly in love with him either.
So it’s not a question of alignment.
I’m aligned with the world.
I want to get the things that—I’m aligned with Europe.
I want to see if we can get this thing done.
You want me to be tough? I could be tougher than any human being you’ve ever seen.
I’d be so tough, but you’re never going to get a deal that way.
So that’s the way it goes. One more question.

JD Vance
I want to respond to this.
For four years in the United States of America, we had a president who stood up at press conferences and talked tough about Vladimir Putin, and then Putin invaded Ukraine and destroyed a significant chunk of the country.
The path to peace and the path to prosperity is maybe engaging in diplomacy.
We tried the pathway of Joe Biden of thumping our chest and pretending that the president of the United States’ words mattered more than the president’s actions.
What makes America a good country is America engaging in diplomacy.
That’s what President Trump is doing.

Volodymyr Zelensky
Can I ask you?

JD Vance
Sure.
Yeah?
Yeah.

Volodymyr Zelensky
He occupied our parts, big parts of Ukraine—parts of the east and Crimea—in 2014.
For a lot of years, I’m not speaking just about Biden, but during that time it was President Obama, then President Trump, then President Biden, and now President Trump again.
God bless, now President Trump will stop him.
But during 2014, nobody stopped him.
He just occupied and took.
He killed people.
You know what the contact line is? 2014, 2015.
During 2014 till 2022, people have been dying on the contact line, and nobody stopped him.
We had a lot of conversations with him—my bilateral conversations—and when I was a new president in 2019, I signed with him, Macron, and Merkel a ceasefire.
All of them told me that he would never go.
We also signed a gas contract.
Yes, but after that, he broke the ceasefire.
He killed our people, and he didn’t exchange prisoners.
We signed the exchange of prisoners, but he didn’t do it.
What kind of diplomacy are you speaking about?
What do you mean?

JD Vance
I’m talking about the kind of diplomacy that’s going to end the destruction of your country.
Mr. President, with respect, I think it’s disrespectful for you to come into the Oval Office and try to litigate this in front of the American media.
Right now, you guys are going around and forcing conscripts to the front lines because you have manpower problems.
You should be thanking the president for trying to bring an end to this conflict.

Volodymyr Zelensky
Have you ever been to Ukraine?
Do you see what problems we have? Then come once.

JD Vance
I have actually watched and seen the stories, and I know what happens is you bring people on a propaganda tour, Mr. President.
Do you disagree that you’ve had problems bringing people into your military?
And do you think that it’s respectful to come to the Oval Office of the United States of America and attack the administration that is trying to prevent the destruction of your country?

Volodymyr Zelensky
A lot of questions. Let’s start from the beginning.
First of all, during the war, everybody has problems.
Even you, but you have a nice ocean and don’t feel it now, but you will feel it in the future.
You don’t know that. You don’t know that.
You’re trying to solve a problem—don’t tell us what we’re going to feel.

JD Vance
I’m not telling you, but you’re in no position to dictate that.
You’re in no position to dictate what we’re going to feel.

Volodymyr Zelensky
That’s exactly what you are.

Donald Trump
We’re going to feel very good and very strong.

Volodymyr Zelensky
You will feel influenced.

Donald Trump
You’re right now not in a very good position.
You’ve allowed yourself to be in a very bad position from the very beginning of the war.
You don’t have the cards right now. With us, you don’t have the cards.
You’re gambling with the lives of millions of people.
You’re gambling with World War III.
You’re gambling with World War III, and what you’re doing is very disrespectful to this country.
This country has backed you far more than a lot of people said they should have.
Have you said thank you once in this entire meeting?

JD Vance
You went to Pennsylvania and campaigned for the opposition in October.
Offer some words of appreciation for the United States of America and the president who’s trying to save your country.
Please.

Volodymyr Zelensky
You think that if you speak very loudly about the war…
My country is in big trouble, but we are staying strong from the beginning of the war.
We’ve been alone, and we are thankful.
I said thanks in this cabinet.

Donald Trump
You haven’t been alone.
We gave you, through your stupid president, 350 billion dollars.
We gave you military equipment, and your men are brave, but they had to use our military equipment.
If you didn’t have our military equipment, this war would have been over in two weeks—maybe three days, maybe less.
It’s going to be a very hard thing to do business like this.
Just say thank you.

Volodymyr Zelensky
I said it at all times, except that there are disagreements.

JD Vance
Except that there are disagreements, and let’s go litigate those disagreements rather than trying to fight it out in the American media when you’re wrong.
We know that you’re wrong.

Donald Trump
But you see, I think it’s good for the American people to see what’s going on.
I think it’s very important.
That’s why I kept this going so long.
You have to be thankful.
You don’t have the cards.
You’re buried there. You have people who died.
You’re running low on soldiers. You’re running low on soldiers.
Then you tell us, “I don’t want a ceasefire.”
Look, if you could get a ceasefire right now, I’d tell you to take it so the bullets would stop flying and your men would stop getting killed.

Volodymyr Zelensky
Of course, we want to stop the war.
But I said to you, I want a ceasefire with guarantees, because you’ll get a ceasefire faster than an agreement.
Ask our people about a ceasefire—what they think.
It doesn’t matter to you what they think.

Donald Trump
That wasn’t with me. It wasn’t with you.
That was with a guy named Biden who was not a smart person.
That was with Obama, who gave you sheets, while I gave you Javelins.
I gave you Javelins to take out all those tanks. Obama gave you sheets.
“Obama gave sheets, and Trump gave Javelins.”
You’ve got to be more thankful, because let me tell you, you don’t have the cards.
With us, you have the cards, but without us, you don’t have any cards.

Volodymyr Zelensky
One more question to the Vice President…

Donald Trump
I’m sorry. It’s going to be a tough deal to make because the attitudes have to change.

Volodymyr Zelensky
What if Russia breaks this fire?
What if Russia breaks these talks?
What if the bomb drops on your head right now?

Donald Trump
Okay, what if they broke it? I don’t know.
They broke it with Biden because Biden didn’t respect him.
They didn’t respect Obama. They respect me.
Putin went through a hell of a lot with me.
He went through a phony witch hunt where they used him in “Russia, Russia, Russia.”
You ever hear of that deal?
That was a phony Hunter Biden, Joe Biden scam—Hillary Clinton, shifty Adam Schiff.
It was a Democrat scam, and he had to go through that.
We didn’t end up in a war. He was accused of all that stuff. He had nothing to do with it.
It came out of Hunter Biden’s bathroom, out of Hunter Biden’s bedroom. It was disgusting.
Then they said, “Oh, the laptop from hell was made by Russia,” the 51 agents.
The whole thing was a scam.
Maybe he broke deals with Obama and Bush, and maybe he broke them with Biden—he did, maybe. Maybe he didn’t. I don’t know.
He’s not breaking with me. He wants to make a deal. I don’t know if you can make a deal.
The problem is I’ve empowered you to be a tough guy, and I don’t think you’d be a tough guy without the United States.
Your people are very brave, but you’re either going to make a deal or we’re out.
If we’re out, you’ll fight it out. I don’t think it’s going to be pretty, but you’ll fight it out.
You don’t have the cards. Once we sign that deal, you’re in a much better position.
But you’re not acting at all thankful, and that’s not a nice thing. I’ll be honest—that’s not a nice thing.

JD Vance
All right, I think we’ve seen enough.
What do you think? This is going to be great television.
We’ll see what we can do about putting it together.
Thanks, sir.

Volodymyr Zelensky
Thanks, sir.

Liked what you read? I am available for hire.

Cities Can Cost Effectively Start Their Own Utilities Now

Most PG&E ratepayers don't understand how much higher the rates they pay are than what it actually costs PG&E to generate and transmit the electricity to their house. When I looked into this recently I was shocked. The average PG&E electricity charge now starts at 40 cents per kilowatt hour and goes up from there. Silicon Valley Power, Santa Clara's utility company, is getting power to customers for 17 cents per kilowatt hour. Sacramento's utility company charges about the same.

PG&E's rates are high enough that, even with the massive headache and expense involved, it's feasible for cities to create their own utility and undercut PG&E's rates. When the savings per household are around $800-$1200 per year, though, they should take it seriously.

Here are the basic components of how much it costs to get electricity to your house.

  • Generation: The cost to actually generate the electricity in a power plant or utility-scale solar farm. This varies by time of day but typically costs about 4 cents per kilowatt hour; you can see the current wholesale rate on the CAISO website.

  • Transmission: How much it costs to move the power from the power source to a local substation/transformer, over large transmission lines. PG&E breaks this out in its detailed rate chart at about 4 cents per kilowatt hour.

  • Distribution: How much to get the power from your local substation to your house over local power lines. In PG&E's rate chart, they charge 20 cents per kilowatt hour for this. That just does not match up with how much it actually costs them to transmit power over local lines and keep the lines maintained.

  • Everything else: Operations, maintenance, profit. This is where PG&E is actually seeing large expenses, because their coverage area is massive, it costs a lot of money to deliver power to rural customers, and they are also undertaking a massive project to underground utility lines in fire-prone areas.

The high price and design of the electricity system have a number of bad effects:

  • People really hate inflation. When utility bills spike, it makes people unhappy and also fuels the (not incorrect) perception that California is poorly governed.

  • Lower income people spend a higher percentage of their income on electricity, so higher utility bills disproportionately hurt them.

  • The net effect of charging higher rates to everyone to pay for undergrounding is that people who live in urban areas are paying more money to subsidize energy transmission for people who live in $2 million houses in places like the Berkeley and Orinda hills. This makes no sense.

  • Higher rates for electricity make electricity less competitive vs. gasoline when people are considering a car purchase. It makes electricity less competitive vs. natural gas for heating a house, heating water, or choosing a laundry machine. As gas is warming the planet and electricity is substantially easier to generate in abundance from renewable sources, it's just bad policy to have high electricity rates.

Let's walk through what this might look like for a particular city to undercut PG&E's rates. I will pick Walnut Creek because it's a reasonably big city with a good mix of detached homes and multifamily. Walnut Creek also has experience with public ownership of amenities - the City operates a golf course and a downtown parking garage with ground floor retail.

There are a number of particular problems with applying PG&E's rates to Walnut Creek:

  • Walnut Creek is an urban area with a compact footprint that has little acreage in a high severity wildfire zone. It has two transmission lines as well as a local transformer grid along Ygnacio Valley Road. It is very cheap to transmit power from power plants to Walnut Creek, and from transmission lines to every house in Walnut Creek.

  • Walnut Creek has an above average number of apartments. Apartments do not have as much space for rooftop solar, and landlords don't have an incentive to provide rooftop solar because they typically pass through utility costs. This means NEM1 and NEM2 subsidies — 12% of the average non-solar bill — disproportionately hurt Walnut Creek renters.

  • Local businesses have disproportionately high energy costs. Safeway and Whole Foods need to keep a row of refrigerators and freezers running 24/7. When they pay PG&E's rates to do that, those high energy costs are passed through as higher food prices.

We are going to adapt Palo Alto's income statement, found on page 50 of their annual report, to Walnut Creek's situation. For each category, I am going to try to shade the numbers assuming we can't be as efficient as Palo Alto.

Usage, Revenue, Expenses

Palo Alto's total electric consumption was 830 gigawatt hours in 2024 - 19% of this usage was residential, and 81% was businesses and industry uses. Applying some adjustments for Walnut Creek - our population is bigger, it's a bit hotter here, and energy use has increased - let's say Walnut Creek uses about 1150 gigawatt hours per year.

Palo Alto earned $172 million in revenue for 830 gigawatt hours, which is about 20 cents per kilowatt hour.

Expenses

Here's where Palo Alto's utility company spends money:

Acquisition of the network and financing cost

The first thing you need to do is buy out PG&E's distribution network - all of the power poles and local equipment that sits between the transmission lines and people's houses. San Francisco proposed buying this for $2.5 billion in 2019; PG&E rejected this offer for being too low. Adjusted for inflation and Walnut Creek's population, this is about $230 million, let's round up and say $350 million. Let's also assume it costs $50 million in startup costs and one time expenses to hire utility staff, buy equipment, marketing expense.

Cities with an AA credit rating can issue a 30 year loan at about 4% interest. Borrowing $400 million would cost about $23 million per year in interest and principal payments.

$23 million per year of financing cost spread across 1150 gigawatt hours is only about 2 cents per kilowatt hour.

Generation and distribution

Palo Alto spent $114 million buying energy in 2024, about 14 cents per kilowatt hour. Let's assume Walnut Creek can get power for about 17 cents per kWh.

Operations

This covers customer service, financial management, billing, engineering work for maintenance (tree trimming etc), and resource management. Palo Alto spent $65 million on these expenses in 2023. Let's assume Walnut Creek's costs are much higher at $90 million per year. This is about 8 cents per kilowatt hour.

Capital Improvements

Another $25 million per year is allocated for grid modernization, undergrounding, and reliability work. Let's assume this is $35 million per year for Walnut Creek, which would be about 3 cents per kilowatt hour.

Total

Adding this up, we get 30 cents per kilowatt hour, which is ten cents lower than PG&E's base rate and about 15 cents lower than PG&E's blended rate. At 1150 gigawatt hours, this would save Walnut Creek residential ratepayers about $23 million per year in total, about $800 per ratepayer, and Walnut Creek businesses about $92 million per year. That is a huge amount of money that could go toward much more productive uses - paying higher salaries, lowering prices for goods, spending more at local businesses.

Most elected officials would jump at the chance to mail every household a $800 check every year. The next best thing is to put $800 back in their pocket.

Other Benefits for Walnut Creek

There are huge ancilliary benefits for Walnut Creek to running its own utility network.

  • Green infrastructure investments: Walnut Creek has made sustainability a key priority. Palo Alto owns a share in a hydroelectric dam, and Santa Clara owns a share in a geothermal plant. At a time when there are exciting new technologies that have the potential to reduce greenhouse gas emissions and deliver clean, cheap energy to residents - things like Fervo Energy that use the tech behind fracking to deliver geothermal power - Walnut Creek can use its very low cost of capital to finance these investments. This is something PG&E cannot do as effectively, because as a public utility with massive amounts of debt and wildfire liability, their borrowing cost is much higher. Public ownership would enable transformative green energy investments with a low borrowing cost.
  • Encouraging the green transition: A 25% reduction in the cost of electricity relative to natural gas would make electric upgrades like heat pump water heaters or electric cars much more financially prudent investments.

  • Fiscal stabilizer: Like every city in California, Walnut Creek has boom and bust cycles. Utilities have much more stable revenues than cities. Walnut Creek could borrow from its utility in recessions, and loan money during booms.

  • Encourage incorporation: Walnut Creek has a number of unincorporated pockets (San Miguel CDP, Shell Ridge CDP) that administratively make little sense - they are served by different police, they have different tax rules. If these homes could save $800 per year on their utility bill by joining Walnut Creek, this may provide an incentive to incorporate, which would ultimately lead to better governance.

  • The best alternatives are good: PG&E is terrified of cities leaving its service network. Look at the concessions they are offering to South San Jose to try to prevent them from starting their own utility.

    Even if Walnut Creek doesn't ultimately pursue its own utility, just investigating the possibility may lead PG&E to offer concessions such as undergrounding the transmission line over downtown. Because you can't build under a transmission line, this makes a 100 foot wide strip of very valuable land undevelopable. St. Paul's would love to redevelop its parking lot under the transmission line for affordable housing, but can only develop tiny corners of the lot with the transmission line overhead. Undergrounding the line would deliver huge benefits to Walnut Creek.

    Transmission
line over downtown Walnut Creek

  • Lowering the cost of urban living in safe places: PG&E's current rate structure has urban rate payers subsidize rural rate payers and people who live in wildfire zones in e.g. the Orinda Hills, who need substantial investment in order to receive power without sparking wildfires. This is bad policy - instead of subsidizing fire zones, it should be cheap to live in safe places and more expensive to live in dangerous places. Lower cost of electricity would reverse these trends.

California is kneecapping its own climate transition with high electricity prices. The resulting inflation hurts our state's ability to retain a high class, diverse workforce. Perversely, it also serves as a subsidy to wildfire zones at the expense of infill areas. It's time to reverse those trends and deliver lower energy prices in places we want more Californians to live.

What should I do if I want this to happen? Cities around the region are doing "priority setting" exercises for 2025. Contact your Mayor or City Council and ask them to explore the possibility of creating their own utility, potentially partnering with other cities. I would probably select cities that do not have large fire zones (ie, not Orinda or Moraga).

Liked what you read? I am available for hire.

How to Ventilate Your House

Every day we learn more about the importance of good air quality. Here are some tips to help you improve air quality inside your house.

How to Measure

First, you are going to want to be able to measure air quality in your house. There are a few different things you want to measure:

  • PM2.5 measures the amount of particles that are 2.5 micrometers or smaller. Compared with larger particles, PM 2.5 does the most damage because they are so small that they can get embedded far into your lungs, which is why they are measured and tracked. You want to keep this value as low as possible.

  • AQI is an aggregate index that measures PM 2.5, PM 10 (10 micrometer particles), carbon monoxide, sulfur dioxide, and nitrogen dioxide in the air. The formula for calculating it is complicated but basically takes the largest value out of those. You want to keep this value below 50.

  • Carbon dioxide builds up in a stuffy room with no ventilation and can affect cognitive performance, make you sleepy, and have other bad side effects. 400 is the ambient air; a value over 1000 is bad.

To measure PM2.5 and AQI, I like the Temtop M10, though it's very easy to buy a more expensive piece of gear that you can connect to Wifi, or smart devices.

To measure CO2, I like the Aranet4, which can run forever on a single battery.

If you don't want to buy them, try to borrow one from a friend, or see if your library will buy them and loan them out; you'll get a sense for the ranges of air quality in your house after a few days.

When it's nice outside

The easiest case is when the weather is nice outside, and there's no fires or smoky air, and you don't live near a freeway. Open your windows! Bringing in outside air is the only way to lower CO2 counts (you can't just run an air purifier).

The best way to ventilate quickly is to open windows on both sides of your house, called "cross ventilation," so a breeze can flow from one end to the other. A good sign that this is working is that doors between the two windows are slamming shut.

If it's not nice outside

Sometimes you can't or shouldn't keep your windows open - it's too hot or too cold, or the air quality outside is too bad. If you live within 1000 feet of a freeway, you are likely breathing in polluted air almost all the time you are outside or have your windows open, which has been linked to lower birth weight, worse cognitive performance, higher rates of respiratory illness.

You are going to want to pump in outside air anyway. If it's hot or cold, you can use your AC, or your heat, which will take care of this for you, by swapping in new air and swapping out old air.

If you have either of these and can't or don't want to change the temperature, they should have a "fan" mode, which does not apply heat but will just bring in new air. You should be running this mode almost all of the time you have your windows closed.

Your heat or your AC will have a filter between the outside air and the fan. Mine is 16x25x1, and looks like this:

Filter for heating
system

You need to buy a good filter. Filters are rated on the MERV system, which sorts by how much particles they are supposed to catch. Your average filter will be about MERV 5. You want to buy a MERV 13 level filter, which is only a little bit more expensive but is going to be vastly better at stopping particulates.

Plan to replace your filter every 2-3 months, more if you run the fan more often, less if you run the fan less often.

You can supplement outside air with an air purifier like the Coway AP1512-HH. Each air purifier comes with a rating for how big of a room it is designed to clear; this one is for 360 square feet. When it ships to you, the filters are already in the purifier, but covered in plastic. Be sure to remove the plastic or the filters won't work.

I keep my air purifiers (we have four) on the lowest level all of the time. Note that these will be ineffective at lowering carbon dioxide levels; you need outside air for that. Plan to change the odor filter every 6 months and the HEPA filter once a year, more often if you live in a particularly polluted area.

Sources of bad air inside your house

The primary source of bad air inside your house is your stovetop. When we cook, the AQI inside our house spikes up above 300, which is worse than in Beijing. If the fan above your stove vents to the outside, you almost always want to run this at the highest level, in addition to opening your windows and doors, and running your house fan, in order to bring the air quality back to a decent level as quickly as possible.

Other sources of bad air include cleaning products and using the toilet. Understand if bathroom fans vent to the outside (they should, if your house is up to code) and run them. Open windows when you clean.

Your stove, your oven, and your shower will also make your kitchen hot, which can be uncomfortable if you are trying to keep the windows closed. On hot days consider using the BBQ instead, if you have one.

That's it

Modern homes in particular are designed not to leak any air if you don't want to. While this is good news for efficiently heating or cooling your house, it is bad news for air quality inside. Measure air quality inside your house and understand which tools are best for bringing in better air.

Liked what you read? I am available for hire.

How much does a San Francisco Chronicle subscription cost?

The San Francisco Chronicle charges for subscriptions. How much does a subscription cost? This is an impossible question to answer, even for current subscribers. The Chronicle advertises several different prices for new subscribers.

The only public information the Chronicle shares about its permanent subscription rates raises more questions than answers.

Chronicle pricing
page

No one at the Chronicle has ever read through this section.

  • The digital-only rate is $34.50 per week, which means that it is about twice the price of getting the Chronicle delivered to your house every single day.

  • If you get the Chronicle delivered, you can get a free digital subscription so you if you want a digital subscription you should opt for delivery.

  • The "home delivery" prices are listed twice and you have to look particularly close to figure out that one of them includes a digital subscription.

  • No one is paying, or going to pay, $34 a week for digital access to the Chronicle!??

I only started looking into this because after three years, the Chronicle decided to more than double the price of my subscription, from $149 a year to $358 per year. The terms of service say that they are supposed to notify me when they change the price ("We will notify you of any changes if the regular fee for your subscription changes from what was stated at the time of your initial order."). They sent no notification, the first I found out was on my credit card bill.

How much I paid for
the Chronicle

I then tried to find any public information the Chronicle had posted about its subscription pricing, whether they had announced recently that they were raising their prices to invest in the newsroom, anything.

The only thing I found was that FAQ page that says a digital subscription costs $34 a week. This is the only public information anywhere that the Chronicle offers about its rates. There is no notion of a "subscription plan." I couldn't really believe this, so I called the Chronicle customer service line. They confirmed that the Chronicle could decide at any time to charge you $34 per week, or about $1800 per year, for a Chronicle subscription, and anyone who got a lower price than that was just lucky to have it.

By contrast the New York Times clearly shows the introductory price and the standard price.

The Washington Post also clearly explains how much you are going to pay.

By contrast someone at the Chronicle must have looked at my 3 year old subscription and decided I should pay more and charge me for that, without any notification, or justification, or even explanation that "this is the rate most people are paying."

Anyway, if you are a Chronicle subscriber you should be aware that:

  • The Chronicle can and will change the price of your subscription at any time

  • According to the Chronicle, everyone who buys a subscription is getting a discount from the $1800/year rate, and should feel lucky.

  • The Chronicle will not tell you why you're paying the rate you're paying.

Liked what you read? I am available for hire.

Sour Punch Strawberry changed their formula

I have a sweet tooth and one candy I really enjoy is Strawberry Sour Punch.

Unfortunately after twenty years of having the same formula it seems that the company has decided to change the formula for Sour Punch. The new candy has more of a cherry flavor and isn't as sour. It does not taste good at all.

The company confirmed that the formula changed in a DM:

Due to the global supply chain crisis, we’ve had to temporarily tweak our formula. We know the current product isn’t what you’ve come to expect from SOUR PUNCH, which is why we are doing everything we can to return it to its original deliciousness so that you can enjoy the candy you know and love.

People on Reddit have confirmed the new flavor is hitting shelves. Recent reviews on Amazon are not pretty.

Have you had a bad batch of Sour Punch, or a batch with a different flavor? Leave a note in the comments, or contact the American Licorice Company and ask them to bring the old flavor back.

Liked what you read? I am available for hire.

Get Urgent Care from One Medical

On Sunday morning at 1am I had a lot of stomach pain. I am a One Medical customer, had heard that they offered urgent care, and so I searched on their website for information.

Unfortunately their urgent care option does not show up in the list of care options on their website:

I concluded that their urgent care offering didn't actually exist and paid for a competing provider's product, so I could talk to a doctor at 1am.

This morning I was informed that their urgent care option does exist, but only in their mobile apps. So you have to go into the iOS app and then you will see "Video Call Now" as an option.

This is a baffling design choice to me. I don't understand why, as a company, you'd only put features in one of the several ways customers can use your product. Or at the very least you could put "Video Call" in the list of options on the website, and then have a popup that says "open the app." But they didn't do that.

So if you are looking to get urgent care or use any One Medical feature try the app.

If this post was useful please send the One Medical twitter account a DM saying so so they can update their product.

Liked what you read? I am available for hire.

You Can Build a Skyscraper Anywhere in Davis Right Now

Update: Everything in this article about Davis is also currently true in the following cities:

  • Redondo Beach
  • Beverly Hills
  • Manhattan Beach
  • South Pasadena
  • Santa Monica
  • Anaheim
  • Oxnard

To get a full list, visit the HCD website, click "Compliance Report," and filter for "Compliance Status" => "OUT". I would also guess that San Francisco will make it onto this list, but not until much later in the year.

Right now it's legal to build a skyscraper anywhere in Davis, California (a college town outside of Sacramento). Unlimited height, anywhere in city limits, as long as you promise to dedicate 20% of the apartments to people with lower incomes. Well, it's legal in theory, no one has ever tested it. But you could be the one to test it! And hopefully make a boatload of money along the way, and help prevent more sprawl into wildfire zones.

Every eight years, every city in California gets an "allocation" from the state government for very low, low, moderate, and above income housing. Each city then needs to show it has a good plan - typically, a zoning map with some spare capacity - to meet the goals in the allocation. Generally this involves identifying sites in the city - places like empty lots, parking lots, abandoned buildings - and rezoning them for additional density.

Davis, California

There's lots of "cheating" - cities pretending that a site will turn into housing when there's no chance it will turn into housing. However, the state has in recent years A) cracked down on cheating by adding stricter requirements and B) set much larger allocations for each city, especially wealthier cities. So a lot of cities that have historically not welcomed housing are struggling this time around.

Davis (population 65,000, plus about 10,000 college students at UC Davis) is one of those cities - it is the wealthiest city in the area, and has for decades had a 1% cap on growth. This was not enough to meet its aggressive new goal of 2075 new homes. Davis submitted a plan to the state's Department of Housing and Community Development (HCD) for how it would meet the goal, but HCD said the plan was inadequate - it didn't do enough to advance "fair housing" (ie. it dumped all of the new housing in the lowest income parts of town), and HCD disagreed that the plan included enough sites to meet the allocation goal.

Because of this, Davis has what's called a "noncompliant housing element." This subjects them to a different state law that says, while your housing element is noncompliant, you can't legally reject an application for housing that offers 20% of the apartments for low incomes. That's any application, anywhere in the city. This isn't some loophole, this was the explicit intent of the (30 year old) law at the time it was written, and both supporters and opponents understood it.

So it's legal right now to buy any lot in Davis and submit a proposal to build a skyscraper on it.1 You would need to meet Davis's other rules - for example, if Davis has rules about parking or fire egress or whatever, you would have to abide by those. But any rules Davis had about density on a site would not apply. Crucially, Davis can't change the rules after your application. As long as you submit it now, while their housing element is noncompliant, they have to be bound by the rules on the books now.

The problem is that big buildings are expensive and the law has never been tested. If you built it you'd be looking at a legal fight for about 4-5 years. I think you would have a good chance of winning - the California courts have in recent years swatted down local NIMBYism at Vallco Mall, in San Mateo and in Los Altos. But you would still have to go through the process.

Why hasn't someone tested it? Because most developers are playing a repeated game with cities, housing applications have historically relied on a lot of goodwill to get through the planning process, and they haven't wanted to upset the apple cart for one big and uncertain return. So there is room for a brash outsider who doesn't care what people or planning staff in Davis think about them.

Here are some notes from Chris Elmendorf, a law professor at UC Davis, about the legal hurdles you'd likely face.

I know a lot of venture capitalists who hate California NIMBYism, care about climate change, and don't care much what opponents of progress think about them. This is a huge opportunity to do something really big, really valuable for the community and make a lot of money along the way. Also I would guess the return from this project is uncorrelated with the rest of your portfolio so would probably be a good source of alpha. I can put you in touch with talented technical people.

If you are interested in helping but don't have a lifechanging amount of money, a number of groups are auditing the Bay Area's "housing elements" this year (the deadlines are staggered, so the Bay Area cities come later) so cities aren't cheating their numbers.2 If you'd like to help, or to get involved, please donate to, or sign up with, East Bay for Everyone.

1 It's also legal in Redondo Beach in Southern California, and possibly additional cities in the Bay Area, soon.

2 Given how important this process is to getting cities to rezone for additional housing, you would hope that there were lots of professional organizations dedicating lots of staff time to analyzing Housing Elements and ensure compliance with the law. In reality there are a lot of volunteers who are spending their spare time writing letters and hoping for the best. One of the key Housing Element volunteers in Los Angeles County is a radiologist.

Liked what you read? I am available for hire.