Now that I am fully managing this website's back-end, I've had to educate myself on configuring nginx. Here are a few of the things I've learned since starting down this path:

Using try_files

At first, I couldn't figure out the magic for having nginx serve a static file if it was actually present on the server, but fall back to my Django application if it wasn't. The answer is to use try_files, a handy built-in resource for this exact use case. I found this via this helpful entry in the Pitfalls and Common Mistakes article (which itself is a treasure trove of information). The specific entry ended up looking like this:

server {
    location / {
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
        # Typical proxy-pass stuff here
    }
}

Shortcutting Known Bad Paths

Don't let your Django app handle paths you know are bad; let nginx offload that processing work for you! I was seeing plenty of accesses against .php files in my server access logs, so I wrote a quick block to reject them:

server {
    location ~* \.php$ {
        return 404;
    }
}

Enabling Strict-Transport Security

Until recently, I didn't even know that HTTP Strict Transport Security was a thing, but it turns out to be pretty easy to implement. Once you have your SSL stuff ironed out and working, you simply need to enable the appropriate header:

add_header Strict-Transport-Security "max-age=5184000; includeSubDomains";

Blue LEDs

Mar 20, 2024

I really enjoyed this video detailing the surprising history of blue LEDs (and why they were so difficult to produce).

A 2018 article on how Joel Spolsky broke IT recruiting randomly popped up in my news feed today. I particularly enjoyed the section that discussed IT recruiting, though the bits relating to StackOverflow haven't aged well; that site is beyond having jumped the shark.

I'm not a people manager, but I have assisted in hiring a number of folks over the years. Some of them turned out to be great developers, while others turned out to be terrible. It's so hard to vet folks based on a handful of interviews. Back when in-person interviews were more of a thing, it was easier. Today's online-only world makes that nearly impossible, especially given that some candidates are no longer local.

Having an actual apprenticeship program would make the process so much easier. New candidates could come aboard for a trial period; 6 or 12 months. Financially, it would be treated like a contract position. During this period they could then be evaluated over time:

  • Is the candidate reliable?
  • Are their development skills what they said they were?
  • Can they communicate effectively?
  • Do they complete deliverables on time?

After the apprenticeship is up, they'd become a "journeyman" and a full-time employee. A program of this sort would greatly reduce the ridiculous speed bump some employers put in the way of hiring developers. It would also make it really easy to get rid of the downright awful developers who occasionally creep in.

This really needs to become a thing.

New Backend

Mar 18, 2024

This website is now running on a DreamCompute instance. One perk of this is that I can run the software stack of my choosing, rather than having to rely on whatever the shared stack is. One drawback, however, is that I'm now in total control; if there's a problem, I have to solve it.

Migrating to this has been fairly rough so far, but I got there in the end. I'll likely have another post in the near future detailing some of the headaches I ran into. There are still a ton of loose ends to tie up, but at least this site is back on the air. Let me know if you spot something broken. Note that I will likely pull down my photos subdomain, as I don't really keep it up to date, and it's not worth migrating in my opinion.

Online Radio Scanners

Mar 15, 2024

What a world we live in.

A few moments prior to my writing this, I heard fire engine sirens outside my house. Looking out my office window and through our neighbor's trees, I could see multiple units responding to a house across the nearest main street. I wondered to myself: "Could I determine what problem they were responding to?" A quick google for "Raleigh fire scanner" returned several hits, one of which was OpenMHz. I pulled up the site, saw that I could filter on "EMS Fire Alerts Only," and selected that option.

Clicking backwards through the playlist, I found the corresponding entry: a gas leak! Cross referencing the reported address, I verified that the house was indeed near our neighborhood. Success!

It's amazing what is possible through the internet. As an aside, this website appears to be a really neat way to listen to what's going on in the area. I can listen to the airport (there was a reported ash-can fire this morning), Raleigh police, or a general overview of all channels (a multiple-vehicle crash occurred a few minutes ago down near Fuquay Varina). Other filters are also available; pretty neat!

Django Web Hosting?

Feb 2, 2024

The web host I've used since the inception of this site will be dropping support for Python (and by extension Django) based applications at the end of March. As such, I'm wondering what alternatives exist. Is anyone familiar with a host that supports Python / Django applications? I'd appreciate any suggestions.

Python dict to tuple

Feb 1, 2024

I had no idea Python could do this, but Ruff taught me something new this morning. Suppose I want to transform a dict into a set of tuples. You can do it in a single line, with no comprehension required!

mydict = {
    'a': 123,
    'b': 456,
    'c': 789,
}
myset = set(mydict.items())
# myset is now: {('a', 123), ('b', 456), ('c', 789)}

I love stumbling upon little hidden gems like this!

High Quality Work

Dec 31, 2023

The Essential Craftsman channel on YouTube occasionally has great philosophical videos (I've featured a few here on the site before). Today's video on "The Mindset of Doing High Quality Work" is worth a watch. In the new year, one of my professional goals will be to improve the quality of my work. In recent times, I've become much more lax in testing the code that I write. This has led to bone-headed bugs that ended up needing a hot-fix, often something that I could have caught had I spent some time testing.

One of the comments in this video really resonated with me: "Strive for perfection, settle for excellence." I think that will be my mantra in 2024 for my professional work.

Classical Meets Rock

Oct 26, 2023

Alice Cooper's My God, a track from the Lace and Whiskey album, is unlike any rock and roll track you've heard. I stumbled upon it while listening to the album for the first time this week, and it's been stuck in my head ever since. Its lyrics are intriguing, especially given that this was recorded during an increasingly troubling time in Cooper's life. Good stuff.

Pretty cool video on the complexity of one of the greatest songs in Sesame Street. It's amazing just how intricate the musicianship is in this!

Roboforming

Sep 18, 2023

The latest Smarter Every Day video is engineering on an entirely different level. The math, software, and other challenges this company face are tremendously complex. It's amazing that people get to do this for a living! I bet we hear a lot more about this technology in the future; this seems like a promising area of development and manufacturing.

Here's another thing that linting taught me recently: Python's str.startswith() method, and str.endswith() as well, takes a tuple as the first parameter! This makes checking for multiple options really simple:

# Verbose way of writing it
if (mystring.startswith('c.') or mystring.startswith('m.') or mystring.startswith('s.')):
    ...

# Easier way
if (mystring.startswith(('c.', 'm.', 's.'))):
   ...

I didn't realize the language allowed this!

As I mentioned previously, I'm now using Ruff to lint my Python projects. Several linter warnings continually crop up in my code, which I find interesting, so I thought I'd highlight a few of them (there are plenty that I'm leaving out; I apparently write fairly crude code by these linters' standards).

missing-trailing-comma
This is a common recurrence in places where I'm setting up a dict for something:

mydict = {
    'posts': some_queryset.all(),
    'today': Date.today()  # Missing a trailing comma
}

if-expr-with-false-true
This pops up on occasion for me, though not terribly often. I apparently easily forget about the not operator.

return False if self.errors else True

# The above is a little more legible if we use:
return not self.errors

superfluous-else-return
I was surprised that this occurred so often in my code. Removing these cases flattens the code somewhat, which is a new practice I'm trying to engrain into my programming habits.

if (is_ajax_request(request)):
    return HttpResponseForbidden('Forbidden')
else:  # This isn't needed
    return redirect(reverse('home'))

# The above looks better as:
if (is_ajax_request(request)):
    return HttpResponseForbidden('Forbidden')

return redirect(reverse('home'))

explicit-f-string-type-conversion
This warning taught me something I didn't know about f-strings; namely that explicit conversion flags are available. Also that the conversions I was making were mostly not necessary in the first place.

error = f"Part not owned by {str(self.part_owner)}!"

# Better:
error = f"Part not owned by {self.part_owner!s}!."

# Best:
error = f"Part not owned by {self.part_owner}!."

type-comparison
Again, I was surprised by how often I do this. Base types can (and often are) subclassed, so it's better to use isinstance() than type is.

if (type(loader) is list):
    return error_response(loader)

# Better:
if (isinstance(loader, list)):
    return error_response(loader)

Running the linting frameworks has taught me a fair amount about my programming habits, and has also informed me about various aspects of the language. I recommend running linters if you don't already, and I highly recommend Ruff!

Linting With Ruff

Sep 8, 2023

I enjoy using linting frameworks for the code I write, primarily employing flake8 for my Python code, which is about 90% of what I write these days. Recently, however, I saw news on Ruff, a new linting framework written in Rust that is orders of magnitude faster. It's so fast that the entire CPython repository, which contains over 1200 files, can be linted from scratch in only 0.29 seconds. Several testimonial quotes in Ruff's README attest to this blazing speed:

Ruff is so fast that sometimes I add an intentional bug in the code just to confirm it's actually running and checking the code. - Sebastián Ramírez, creator of FastAPI

Just switched my first project to Ruff. Only one downside so far: it's so fast I couldn't believe it was working till I intentionally introduced some errors. - Timothy Crosley, creator of isort

Another benefit on top of its speed is the near-parity it brings with Flake8, which is nice. There are still a number of formatting rules from the pycodestyle package that haven't been implemented, which is an annoyance, but there's an active issue tracking the progress on that front.

To top it all off, Ruff includes rules from dozens of Flake8 plugins, most of which I've never run. Enabling all of them in my projects has been humbling, to say the least, but I'm learning a ton of improved practices from doing so. I don't always agree with some of the rules, and have disabled a number of rule sets that annoy me, but it's been an interesting learning process.

In the coming days I'll be writing about a few of the sloppy practices that this framework has pointed out in my code, so stay tuned.

My wife made these the other night for a dinner with neighbors and they turned out terrific. In fact, they're likely better than the snickerdoodle recipe that I posted several years ago! The cookies in this recipe end up way softer, and are just as flavorful. Highly recommended! Note that this recipe was taken from an external website, which I'm transcribing here for both simplicity and posterity.

Makes 36 cookies in about 20 minutes.

Dough

  • 2-3/4 cups all-purpose flour
  • 2 tsp cream of tartar
  • 1 tsp baking soda
  • 1/2 tsp salt
  • 1 cup unsalted butter, just softened
  • 1-1/2 cups sugar
  • 2 eggs
  • 1 tsp vanilla extract

Coating

  • 1/3 cup sugar
  • 2 tbsp cinnamon

Instructions

  1. Preheat oven to 350 degrees F.
  2. In a large bowl, mix together flour, cream of tartar, baking soda, and salt together. Set aside.
  3. In a stand mixer, cream together butter (barely softened) and sugar. Add eggs and vanilla and blend well.
  4. Add dry ingredients to wet ingredients and mix well.
  5. In a small bowl, combine remaining ⅓ cup sugar and 2 tablespoons cinnamon.
  6. Use a small cookie scoop to scoop out dough, roll into a ball and then roll into the cinnamon sugar mixture- twice.
  7. Place 2 inches apart on an ungreased cookie sheet.
  8. Bake for 8 – 10 minutes. Let sit on the cookie sheet for a few additional minutes before removing to a wire rack to cool.

Until recently, I knew next to nothing about Alice Cooper's music. I'd heard School's Out and No More Mister Nice Guy on the radio, but that was the extent of my knowledge. Alice is back in the news with a forthcoming album, so I figured I'd check out some of his music. I'm glad I did! Lots of his albums are particularly good, including Killer (I can't embed the videos here on this site, stupidly, so the link to the album playlist will have to suffice). There are some great tracks on this album: Halo of Flies (my favorite), Under My Wheels, and Dead Babies.

Billion Dollar Babies is an equally as good (if not better) album, as is his first solo effort Welcome to My Nightmare. I recommend checking them all out if you're not familiar.

The Operations Room

Apr 30, 2023

The Operations Room channel on YouTube has been killing it for a while now. Their top-down, animated videos show some of the most important battles and events in history. I've learned a ton about events in World War 2, Vietnam, the Gulf war, and even interesting isolated events. Their latest video, on the battle of Alligator Creek at Guadalcanal, is fascinating and I've linked it below. This is definitely a channel to follow; there's lots of terrific content.

We recently bought a new home and have been doing a number of updates. One thing in dire need of updating are the thermostats, which are original to the house (1992). The existing units were clunky, not very user friendly, and not particularly sensitive to temperature change.

I decided to purchase the ecobee smart thermostat, and was particularly motivated when our energy provider recently offered a deep discount on the units. I picked up a couple of them and updated the upstairs unit earlier today (I'll tackle the downstairs unit another day).

Because my setup didn't have a C-wire (for continuous power), the install process required that I installed a power-extender kit, which comes in the box. This involved adjusting the thermostat wires inside the HVAC unit, which was a little daunting at first. This process, however, turned out to be easier than I initially thought.

The entire install process took about an hour or so do, and I now have a modern, easy to use setup. One of the benefits of these units is that they have optional sensors you can buy to place in other rooms, which help the thermostat better control the temperature across the whole house. I plan on picking up one of these eventually to put in our bonus room, which seems to be hotter than the rest of the house on average.

I'm enjoying the DIY aspect of home ownership these days. I've learned a lot, am gaining new skills, and I'm saving a little on having to hire someone to do the work.

Magnet Sweeper

Apr 11, 2023

We recently had our roof replaced, which resulted in a ton of debris in the yard. One of our primary concerns with this was the number of loose nails and screws, which pose a hazard to both our car tires and our feet. Scanning through Home Depot's website, I found this magnet sweeper, which only set me back $12.

The second photo above shows just how many nails, screws, and other debris I was able to pick up with this thing. Wow! There are a few drawbacks to this tool. First, the handle is a little short for my taste. Second, the magnets could stand to be stronger, but they did a decent job. And third, a wider magnet head would have been nice. But for only $12, I'm willing to sacrifice some of the niceties of other, pricier tools. If you ever find yourself in need of something like this, I recommend this model, despite its shortcomings. I can see this tool being useful in other situations (i.e. when I drop a screw or nut in the garage and it rolls out of reach).

On Keeping Records

Mar 21, 2023

My wife and I are in the process of purchasing a new home. The current owners of the property we're buying have kept meticulous records. They have a spreadsheet detailing:

  • The type of home update
  • When the update was made
  • Who did the service (or where it was purchased from)

This information is surprisingly useful to know, and has helped us make some decisions on what to update and what not to update. It also gives us a good picture of the relative ages of each home system (e.g. hot water heater, HVAC units, etc.).

While discussing the selling of our current home with our realtor, I figured I could provide dates for when some of the similar updates here were done. I assumed that I had emails on these items, but it turns out I don't. Maybe I paid for some of these things via a check? And maybe the receipt they sent was a hard-copy? Regardless, I am unable to pinpoint when our hot water heater was installed, for example (this kind of thing is useful to know when selling a home, it turns out).

It's frustrating to know that I had work done to my home but cannot locate the invoice showing me who did it or when it was done. Had I kept better records, this wouldn't have been a problem. Going forward, I intend to do a better job.