Against Usefulness: Why Side Projects Are the Secret Weapon of Great Engineers

We’ve all been there. It’s 11:30 PM on a Tuesday, and you’re staring at a terminal window. You’ve spent the last three hours writing a custom compiler in Rust that translates brainfuck into heavily optimized WebAssembly, or maybe you're building a physical, mechanical button that does nothing but query a local LLM to generate a random, highly specific insult about your code formatting.

Then, the voice of "productivity" creeps in: "What is the business value of this? How does this align with my career goals? Is this useful?"

Today, a fascinating essay titled "Against Usefulness" bubbled to the top of Hacker News. It struck a massive chord with the developer community because we live in an era of hyper-optimization. We are constantly told to optimize our GitHub contribution graphs, build SaaS side-hustles, study LeetCode patterns, and only build things that have a clear return on investment (ROI).

But here is my hot take for today: The pursuit of "usefulness" is quietly killing your growth as a software engineer.

If you only ever build things that are immediately useful, you are limiting your playground to what you already know how to solve. Today, we are going to dive into why useless side projects are actually the secret weapon of elite engineers, how they build deep technical intuition, and we'll even walk through a "completely useless" project of our own to show how absurd rabbit holes teach us real, production-grade systems engineering.

The Trap of the "Productive" Side Project

In our industry, we have commoditized curiosity. If you browse tech Twitter or developer subreddits, the advice for side projects usually looks like this: "Build a Next.js SaaS starter kit, integrate Stripe, add Auth0, and try to get 100 active users."

There is nothing wrong with building a SaaS. But when you build for "usefulness" or market viability, you naturally make conservative technical choices. You use the stack you use at your day job. You avoid risky architectural patterns. You focus on billing APIs, SEO optimization, and landing pages rather than pushing the boundaries of what you know how to program.

When you build something explicitly useless, however, the constraints vanish. You aren't building a product; you are conducting research and development. You are playing. And play is the highest form of learning.

How "Useless" Projects Build Deep Technical Intuition

  • Zero Fear of Failure: If your project has no users and no business model, you can write terrible, experimental code. You can try to write a database engine in Bash just to see if you can. If it corrupts data? Who cares! But along the way, you’ll learn a terrifying amount about file descriptors, I/O multiplexing, and POSIX standards.
  • Inversion of Constraints: When usefulness isn't the goal, you can invent absurd constraints that force deep technical problem-solving. For example: "I want to build a chat app, but it can only transmit data via CSS hover states." (Yes, people have done this).
  • Accidental Expertise: Many of the industry’s most critical tools started as "useless" or purely hobbyist experiments. Linus Torvalds famously announced Linux as "just a hobby, won't be big and professional like gnu." Git was built because Linus was frustrated with BitKeeper. Docker emerged from internal hacking at dotCloud that didn't fit their core hosting business.

Case Study: Building a Totally Useless (But Deeply Educational) Tool

To prove my point, let’s build something completely useless right now.

We are going to build a tool called EntropyDNS. It is a DNS server that, instead of resolving actual domain names to IP addresses, resolves any domain name to a randomly generated IP address that is mathematically guaranteed to represent a color matching the hash of the domain name.

Is this useful? Absolutely not. It will break your internet browser immediately if you try to use it as your primary DNS.

But to build it, we have to learn:

  1. How the DNS protocol works at a byte level.
  2. How to handle UDP sockets in Node.js/TypeScript.
  3. How to parse and construct binary network packets.

Let's look at the implementation. This is real systems programming disguised as a joke.

The Code: A Custom UDP DNS Server

First, let's look at how we parse a raw DNS query buffer and construct a raw DNS response. When a DNS client (like dig) sends a query, it sends a UDP packet. We have to parse this binary data, extract the transaction ID, append our answer, and send it back.

import dgram from 'dgram';
import crypto from 'crypto';

const server = dgram.createSocket('udp4');
const PORT = 5353; // Using 5353 to avoid root privileges

// Helper to hash a string (domain) into an RGB IP address: e.g., "alex.com" -> 162.24.89.X
function domainToColorIP(domain: string): number[] {
  const hash = crypto.createHash('md5').update(domain).digest();
  // We use the first 3 bytes for R, G, B, and hardcode the last byte to 1 for validity
  return [hash[0], hash[1], hash[2], 1];
}

server.on('message', (msg, rinfo) => {
  // 1. Extract Transaction ID (First 2 bytes)
  const txId = msg.subarray(0, 2);

  // 2. Set Flags for Response (Standard query response, no error)
  // 0x8180: QR=1 (Response), Opcode=0, AA=0, TC=0, RD=1 (Recursion Desired), RA=1, Z=0, RCODE=0
  const flags = Buffer.from([0x81, 0x80]);

  // 3. Extract Questions Count (Bytes 4-5) and set Answer Count to 1 (Bytes 6-7)
  const qdCount = msg.subarray(4, 6);
  const anCount = Buffer.from([0x00, 0x01]); // We are returning exactly 1 answer
  const nsCount = Buffer.from([0x00, 0x00]);
  const arCount = Buffer.from([0x00, 0x00]);

  // 4. Extract the Question Section to echo it back in the response
  // The question starts at byte 12 and ends with a null byte (0x00) + 4 bytes for Type/Class
  let qEnd = 12;
  while (msg[qEnd] !== 0 && qEnd < msg.length) {
    qEnd += msg[qEnd] + 1;
  }
  qEnd += 5; // Include the null byte and QTYPE (2 bytes) + QCLASS (2 bytes)
  const questionSection = msg.subarray(12, qEnd);

  // Parse the domain name for our fun hashing function
  const domainParts: string[] = [];
  let i = 12;
  while (msg[i] !== 0) {
    const len = msg[i];
    domainParts.push(msg.toString('utf8', i + 1, i + 1 + len));
    i += len + 1;
  }
  const domainName = domainParts.join('.');
  const ip = domainToColorIP(domainName);

  console.log(`[EntropyDNS] Query for: "${domainName}" -> Mapping to Color IP: ${ip.join('.')}`);

  // 5. Construct the Resource Record (Answer)
  // Name: pointer to the domain name in the question (0xc00c points to byte 12)
  const ansName = Buffer.from([0xc0, 0x0c]);
  const ansType = Buffer.from([0x00, 0x01]);  // A Record
  const ansClass = Buffer.from([0x00, 0x01]); // IN (Internet)
  const ansTTL = Buffer.from([0x00, 0x00, 0x00, 0x3c]); // 60 seconds
  const ansDataLen = Buffer.from([0x00, 0x04]); // IPv4 is 4 bytes
  const ansData = Buffer.from(ip);

  const response = Buffer.concat([
    txId,
    flags,
    qdCount,
    anCount,
    nsCount,
    arCount,
    questionSection,
    ansName,
    ansType,
    ansClass,
    ansTTL,
    ansDataLen,
    ansData
  ]);

  server.send(response, rinfo.port, rinfo.address, (err) => {
    if (err) console.error('Failed to send response', err);
  });
});

server.on('listening', () => {
  const address = server.address();
  console.log(`EntropyDNS listening on ${address.address}:${address.port}`);
});

server.bind(PORT);

What Did We Actually Learn Here?

If you copy-paste this code, run it with ts-node, and query it using dig in your terminal:

dig @127.0.0.1 -p 5353 codingwithalex.com

You will get a successful A-record response mapping codingwithalex.com to a random, color-hashed IP address.

By building this "useless" tool, we didn't just write code. We learned:

  • The DNS Wire Format: You now know that DNS uses 12-byte headers, that domain names are encoded as length-prefixed labels rather than null-terminated strings, and how compression pointers (like 0xc00c) optimize packet sizes.
  • Binary Buffer Manipulation: You learned how to slice, read, and concatenate raw Node.js Buffer arrays—a skill that is absolutely vital when writing high-performance WebSockets, gRPC implementations, or custom IoT protocols.
  • UDP Semantics: You worked with connectionless UDP packets, understanding that unlike TCP, we have to manually manage state and map responses to requests via Transaction IDs.

The next time you have to debug a weird DNS propagation issue at work, or write an optimization layer for your API gateway, you won't just be guessing. You will have deep, mechanical sympathy for the network layer because you once spent a midnight session building a useless DNS server that turns domains into colors.

Embrace the Absurd

Some of the most respected developers in our industry are famous for their useless projects.

Consider Doom. Programmers have ported Doom to run on pregnancy tests, IKEA smart lamps, the Apple Watch, and even inside the BIOS of a motherboard. Is it useful to play Doom on a refrigerator? Absolutely not. But the engineers who do this gain an incredibly deep, intimate understanding of embedded systems, memory limitations, display drivers, and low-level C compilation.

When you stop asking "How will this help my resume?" and start asking "What happens if I try to do this?", your brain enters a state of flow that structured, "useful" learning simply cannot replicate.

Your Challenge: Go Build Something Useless

I want to challenge everyone reading this to take a break from your productivity goals this week. Put aside your startup ideas, put aside your clean architecture books, and put aside your LeetCode prep.

Think of the most absurd, technically challenging, completely unsellable tool you can imagine.

  • Write a program that translates your codebase into emojis and tries to compile it.
  • Build a physical device that sounds an alarm whenever your CPU usage goes above 90%.
  • Write a custom database engine that stores data inside the Git commit history of a dummy repository.

Build it. Break it. Laugh at how ridiculous it is. And watch how much better of an engineer you become because of it.

What's the most useless thing you've ever built?

I want to hear about your weirdest, most impractical creations. Did you learn something unexpected from them? Let me know in the comments below, or hit me up on Twitter/X at @sysseder!

Until next time, keep coding, keep breaking things, and keep it useless.

— Alex R.

Post a Comment

Previous Post Next Post