Category Archives: Make stuff

Unnecessary code, finance class edition

Ever since classes went fully online in the spring semester, I've had a horrible time concentrating during lectures. There's the usual self-caused distractions—the phone, the browser, literally any other room of the house besides the one with the lecture playing—but even when I'm there, trying to focus like a Good Boy, it's really hard to lock in and take something from the class. Since the classes are three hours long, only twice a week, it's a real grind trying to force focus. Don't look to me for advice on how to do it.

Except today—I tried something accidentally. In the finance class we were doing some calculations on bond values, and I went to Excel like I normally would for calculations. And we occasionally needed to shift the term length on the bonds, and calculate the annual value like we would on a timeline, and Excel was just feeling a little too stiff—changing the number of rows or columns or whatever on the fly, manually. And I was focusing that great anyway, so I popped open Eclipse and started trying to create the calculations in Python instead.

click

I never really got the thing to do much yet (finance_sandbox.py) but there was a different kind of focus that set it once I started doing it. Setting up classes and thinking about what attributes of the bonds I had to capture from the lecture, trying to quickly think of abstractions so that I could calculate problems with different features from the lecture—having to create and re-create the most basic aspects of the things we were learning about turned out to be very helpful.

Overabstraction of the Backyard Steps Project and Backyard Leveling Project

I'll tell you one of my personal hells:

Overabstraction.

"Ce qui vaut la peine d'être fait vaut la peine d'être bien fait". ("What is worth doing is worth doing well".) You've heard that one before. That's just a gateway drug, though. Doing something well leads to wanting to understand the patterns and causes and then, once you can start to get a grip on the classes and methods of that something it's only natural to want to start building a machine of some sort to do that something for you.

(I'm saying "you" but I know I'm thinking "me". Bear with me on this one. I need to talk about this like it's your problem. It's easier to deal with, etc.)

My big Home Project now is building some steps from the back door of the garage down to the back yard—the Backyard Steps Project. In isolation: it's not that difficult of a problem.

Plot twist.

My wife would also like the backyard to be leveled—the Backyard Leveling Project. In its current state (which I was tempted to call its "natural state", although this would be a casual lie because it was certainly modified during the installation of these suburbs in the ~1960s, and perhaps even before that, I don't know) there is a downslope from north-to-south and from west-to-east. As the proud owner of a shovel (a collection of shovels, really, don't judge), the solution to the leveling problem is simple: take a shovelful of dirt from the high side and put it on the low side. Repeat until there is no high side or low side.

Simple specification, simple implementation. I'd crawl on my knees and beg for a spec to be this easy to implement at work. However, there is some coupling between the Backyard Steps Project and the Backyard Leveling Project that is giving me a headache.

How many steps does one need? Assuming you care about your user (you should—I do), the steps should be an equal height—an obvious assumption, sure, but we're just building out the model here. Now you have h_step, and n_steps * h_step will be the total elevation change (h_total) from the landing at the top (z_top) to the landing at the bottom (z_bottom); or, in reverse, the total elevation change will give you n_steps, just divide h_total by h_step. z_top is fixed—the garage slab is not going anywhere. But z_bottom is z_backyard, and the value of z_backyard to use is its future value, after leveling. h_step—we'll limit the values for this one between 6 and 7.5 inches.

And, to some extent, since setting z_bottom affects the rise-over-run of the whole set of steps, z_bottom also affects d_step, the depth (or amount of run) of each step—and we'll also assume d_step to be equal for all steps. But this can be somewhat mitigated by changing the length of the top and bottom landing. (w_step, the width of the path, was fixed at 60 inches through what we might call stakeholder feedback.)

A diagram would be helpful, no?

[TBD: diagram]

I've also gathered measurements (good ol' stick, string, and bubble level) for the project. The measurements break down into two groups: (1) the ground leading from the garage door to the edge of the deck (a single arc); and (2) the back yard measured in 2-ft increments 32 feet south of each deck pier (so, basically, six arcs of data). Call it data_1 and data_2 for reference.

data_1 is easy because it is just measured from the deck (the top edge of the deck planks) down to the ground with a (large) ruler. It assumes that the deck level is fixed because otherwise why bother. It also assumes that the east-west slope here is zero, which is not accurate, but not far off—since this bit is not part of the yard leveling scheme, it doesn't need to be accurate, I'm not accounting for the volume of dirt to move.

data_2 was massively annoying to capture. I attached the string a clamp on the wood supports one inch above each of the concrete piers to provide a reference height for each series of measurements. But each pier has a different absolute height—so, essentially, there is a z_string for each series of measurements that defines the height of the fixed string above the ground to give the raw measurements.

h_pier16.0014.5016.0016.2515.5018.00
h_string_offset1.001.001.001.001.001.00
z_string17.0015.5017.0017.2516.5019.00
y_rawz_1_rawz_2_rawz_3_rawz_4_rawz_5_rawz_6_raw
inchesinchesinchesinchesinchesinchesinches
0.017.015.517.017.316.519.0
24.023.020.522.021.021.522.0
48.029.529.029.528.528.031.0
72.035.034.036.033.034.534.0
96.039.040.040.537.538.040.0
120.045.545.545.043.543.044.0
144.049.549.049.046.047.048.0
168.054.053.055.049.050.051.0
192.056.057.059.052.052.055.0
216.057.558.060.055.055.058.0
240.063.061.063.059.058.059.0
264.064.062.064.061.061.061.0
288.064.063.065.062.064.064.0
312.071.069.067.069.067.068.0
336.073.071.071.070.069.071.0
360.077.077.073.077.073.075.0
384.077.078.078.078.080.077.0

This all needs to be adjusted so that the height measurements are taken from the same level—deck level.

h_deckboard0.500.500.500.500.500.50
h_beam9.139.139.139.139.139.13
h_post25.7531.8836.5044.5050.6355.50
h_string_offset1.001.001.001.001.001.00
z_ref_offset34.3840.5045.1353.1359.2564.13
y_rawz_1z_2z_3z_4z_5z_6
inchesinchesinchesinchesinchesinchesinches
0.0-51.4-56.0-62.1-70.4-75.8-83.1
24.0-57.4-61.0-67.1-74.1-80.8-86.1
48.0-63.9-69.5-74.6-81.6-87.3-95.1
72.0-69.4-74.5-81.1-86.1-93.8-98.1
96.0-73.4-80.5-85.6-90.6-97.3-104.1
120.0-79.9-86.0-90.1-96.6-102.3-108.1
144.0-83.9-89.5-94.1-99.1-106.3-112.1
168.0-88.4-93.5-100.1-102.1-109.3-115.1
192.0-90.4-97.5-104.1-105.1-111.3-119.1
216.0-91.9-98.5-105.1-108.1-114.3-122.1
240.0-97.4-101.5-108.1-112.1-117.3-123.1
264.0-98.4-102.5-109.1-114.1-120.3-125.1
288.0-98.4-103.5-110.1-115.1-123.3-128.1
312.0-105.4-109.5-112.1-122.1-126.3-132.1
336.0-107.4-111.5-116.1-123.1-128.3-135.1
360.0-111.4-117.5-118.1-130.1-132.3-139.1
384.0-111.4-118.5-123.1-131.1-139.3-141.1

There is one more transformation that I did, that might be overkill—but what the hell. As mentioned at the start: if it's worth doing, it's worth overdoing. The distance measured south of the deck is really the distance along the ground, not the distance measured along the north-south axis—so a little trigonometry needs to be done to pull out the y-axis (north-south axis) component.

y_1y_2y_3y_4y_5y_6
inchesinchesinchesinchesinchesinches
0.000.000.000.000.000.00
23.223.4723.4723.7123.4723.81
46.345.9246.2746.5046.5846.06
69.769.3969.3770.0869.6869.87
93.492.6392.9593.6593.4293.11
116.5115.99116.52116.89116.90116.77
140.1139.73140.19140.76140.56140.44
163.7163.40163.43164.57164.37164.25
187.6187.06187.09188.38188.29187.91
211.6211.04211.07212.19212.10211.73
234.9234.85234.88235.86235.91235.71
258.9258.83258.86259.78259.72259.62
282.9282.81282.84283.75283.54283.43
305.9306.05306.76306.71307.35307.10
329.8329.97330.42330.69331.26330.91
353.5353.20354.34353.65354.93354.57
377.5377.18377.81377.63377.88378.49

Then add in the distance between the piers for x-axis (east-west axis):

x_1x_2x_3x_4x_5x_6
inchesinchesinchesinchesinchesinches
0.0071.00142.50214.13285.50349.50

Then, at this point, I've got the transformed (x,y,z) field data for leveling the backyard.

Eggnog 2018

It's the most wonderful time of the year.

This is my third batch of eggnog, and the motivation is still the same as the first time: make an alcohol drink with raw eggs and then age it for 30 days? Gotta try that.

It seemed a little crazy. That's exactly the sort of thing that people who would drink alcoholic milk would say to do. That's what Michael Ruhlman said to do. So did J. Kenji López-Alt. So I tried it, waited 30 days or so, and it worked. And I tried it again, waited 30 days or so and it worked—but we didn't drink it all and I ended up aging a jar and a half for about 13 months and it still worked.

Xiaoqi standing by to call 9-1-1 while I drink the 13-month batch

I used the original recipe without modifications, except for not using the full measure of sugar (I started with 2 cups of sugar, then scooped some out until I felt less disgusted about how much sugar there was):

  • 12 egg yolks [egg whites were used for steamed eggs]
  • ~2 cups granulated sugar
  • 1 liter bourbon [Maker's Mark this time]
  • 4 cups whole milk
  • 1 cup heavy cream
  • 3/4 cup brandy [E&J XO]
  • 1/2 cup Myers’s dark rum
  • pinch of kosher salt

There's not much to it:

  1. Beat the egg yolks and sugar together.
  2. Mix it up with everything else in a big bowl.
  3. Put it in jars. Put the jars in the refrigerator.
  4. Wait.
  5. Drink.




Can't waste the bit that didn't fit in the jar


Bonus: Here's a bunch of links to other people who tried it:

Eggnog 2016

When I saw the phrase "30-day eggnog" show up in my RSS feed, I knew right away that I had to try it. It was too weird of a concept to let it pass by. Michael Ruhlman: "Plan ahead: 30-day eggnog".

I've never made eggnog before. Growing up, we just bought it at the store. I knew eggnog proper had some alcohol in it, but I assumed it was mostly eggs and milk with just a little bit of alcohol. Wrong. Flip that equation around.

So, while the eggnog is aging in the refrigerator—either mellowing into a more complex flavor or preparing to kill me—here's how I set it up. The recipe is 75% of the one on Michael Ruhlman's site because I only wanted to buy a 750 mL bottle of bourbon.

  • 9 egg yolks
  • 1.5 cups granulated sugar
  • 750 mL bourbon
  • 3 cups whole milk
  • 3/4 cup heavy cream (I think I just used a full cup because that was the size of the container)
  • 2/3 cup brandy
  • 3/8 cup Myers’s dark rum
  • pinch of kosher salt

Outcome: TBD 26 Dec: excellent