Blog

  • What I Care About as a Lead Engineer

    I care about different things now that I have grown into a lead engineer. There are some things that I have started to care more about, and some things that I have started to care less about.

    What a lead cares less about

    1. Personal Commit Volume
      • Junior/Senior View: “I need to ship a lot of code to prove my value.”
      • Lead View: “I need to unblock others so they can ship code.”
        • As a lead, you spend time on code reviews, design, answering questions, and clearing the path. As a result, the number of commits you make decreases.
    2. The Latest and Greatest Software
      • Junior/Senior View: “Let’s use this new beta framework; it’s faster, cooler, and more modern.”
      • Lead View: “Can we hire for this? Is it stable? Does it have good documentation?”
        • Leads focus on long-term maintainability and hiring over cutting-edge trends. As a lead, I shy away from big rewrites if they are not critical.
    3. Micro-Optimization & “Perfect” Code
      • Junior/Senior View: “This function can be 5 ms faster if I rewrite it three times.”
      • Lead View: “Is it good enough to ship today?”
        • Seniors often chase architectural purity. Leads are more open to taking on technical debt if it gives a business edge, like meeting a deadline. They need a plan to pay it off later.
    4. How the Team Solves the Problem (Implementation Details)
      • Junior/Senior View: “This is exactly how I would write this class.”
      • Lead View: “Does the interface match the spec? Does it pass tests? Then do it your way.”
        • Leads learn to delegate ownership. Nitpicking every line of a Senior’s code to match their style creates a bottleneck. It also demoralizes the team. They care about the contract (inputs/outputs), not the implementation.
    5. Being the “Smartest in the Room”
      • Junior/Senior View: “I need to have the answer to every technical question to show authority.”
      • Lead View: “I need to find the person who has the answer.”
        • A Lead’s value comes from synthesis and decision-making, not encyclopedic knowledge. They feel at ease saying, “I don’t know, let’s ask the database expert.” This change means they now route knowledge instead of sharing it.
    6. Rigidity in Process
      • Junior/Senior View: “The ticket had incorrect formatting, so I won’t do it.”
      • Lead View: “This is urgent; I’ll fix the ticket later.”
        • While Leads usually enforce process, they also know when to break it. They focus less on sticking to strict rules, like needing 100% test coverage for a prototype. Instead, they focus on the practical needs of the business.

    What a lead cares more about

    Lead engineers change their focus from output, like writing code, to outcomes. This includes system reliability, team speed, and business value. Their focus is on the big picture. They focus on the product’s technical success. Their concerns are strategic, not tactical.

    1. The “Bus Factor” (Risk Mitigation)
      • The Concern: “If we lose someone tomorrow, does the project die?”
      • The Action: Leads obsess over knowledge silos. They push for rotating key tasks. They need documentation for complex systems. They also avoid obscure technologies that are hard to hire for.
    2. Force Multiplication (Developer Experience)
      • The Concern: “Why does it take 45 minutes to deploy a one-line change?”
      • The Action: Leads care about the feedback loop. They invest time in CI/CD pipelines, local dev environments, and linting tools. If they save 5 minutes for 10 developers, that’s 50 minutes of extra productivity per build.
    3. Observability & Average Recovery Time
      • The Concern: “How do we know it’s broken before the customers tweet about it?”
      • The Action: Seniors care that the code passes tests; Leads care that the code emits logs. They focus on metrics, dashboards, and alerting. This way, when issues arise, they can find the root cause in minutes, not days.
    4. Technical Debt as a Financial Instrument
      • The Concern: “Are we paying too much ‘interest’ on this legacy code?”
      • The Action: Leads don’t aim for zero technical debt; they aim for managed debt. They talk with product managers to “buy” time for refactoring. They explain the cost of inaction. For example, they say, “If we don’t fix this now, feature X will take twice as long to build next month.”
    5. Alignment with Business Goals
      • The Concern: “We are building a Ferrari, but the business needs a moving van.”
      • The Action: Leads are the filter between “cool tech” and “profitable tech.” They prevent over-engineering. If a basic CRUD app can solve the business problem, they will block the team from building a complex microservices architecture. Even if the team wants to do so.
    6. Consensus and “Disagree and Commit”
      • The Concern: “Is the team paralyzed by debate?”
      • The Action: Leads care about decision velocity. They lead technical talks and make sure everyone’s voice gets heard. They also finalize decisions to resolve ties, helping the team move forward.

    The transition from Senior to Lead is fundamentally about trading personal output for team output. It requires letting go of the immediate satisfaction of closing tickets to focus on the often invisible work that keeps the system healthy and the team moving. By prioritizing business alignment, risk mitigation, and developer experience over technical perfection and personal commit counts, a Lead Engineer ensures that the team doesn’t just ship code, but delivers sustainable value.

  • Packaging JS Apps with QuickJS

    QuickJS is a tiny JavaScript engine written in C. Its author, Fabrice Bellard, created FFMPEG and QEMU. QuickJS can run outside of traditional browser environments. This includes packaging JavaScript applications for distribution.

    As of writing, QuickJS supports ECMAScript 2023, so you can write modern JavaScript. It is also fast and well-tested.

    One of the engine’s features is compiling JavaScript code into bytecode. Bytecode is a compact set of instructions that an interpreter can execute. It makes execution more efficient, which is perfect where performance is important. Additionally, the engine supports compilation of JavaScript into dependency-free standalone executables. We will use this feature to package JavaScript apps.

    QuickJS’s small footprint is also suitable for embedded systems and resource-constrained environments.

    Recently, Amazon announced its Low Latency Runtime (LLRT), built on QuickJS. According to Amazon, LLRT starts 10x faster and is 2x less expensive than other JS runtimes on AWS Lambda. That’s a pretty impressive use case.

    Installation

    Installing QuickJS in your development environment is straightforward. Here’s how to get started. Note that on Windows, you can use WSL with Linux.

    Before jumping in, make sure you have Make and a C compiler like GCC or Clang.

    The first step is to get a copy of the source code. You can download the source from the QuickJS website or by cloning it from the GitHub repository. We’ll download it from the website and untar the file:

    wget https://bellard.org/quickjs/quickjs-2024-01-13.tar.xz
    tar -xJf quickjs-2024-01-13.tar.xz

    This command creates the directory quickjs-2024-01-13 with all the necessary source files. I’ll refer to this directory as quickjs from now on.

    Compatibility

    QuickJS does not rely on V8, WebKit, or Gecko. It is not compatible with NodeJS or Deno APIs. It does have access to the OS through its own APIs. To make sure your code is compatible with QuickJS, ensure the following:

    • Your code uses ECMAScript 2023 or lower
    • You are not using browser-specific APIs
    • You are not using Node.js or Deno-specific APIs

    QuickJS focuses on the core JavaScript language, so your code should be platform-agnostic.

    Organization

    For this simple Hello World app we’re putting our files into the quickjs directory. In a business context, you should keep your code separate from QuickJS. Otherwise, you can structure your project as you would any other JavaScript project. You can even use modules.

    Building QuickJS

    Once you have the source code, the next step is to compile it. This will convert the code into an executable you can run on your computer. Navigate to the quickjs directory with cd quickjs.

    Finally, compile the source with the make command. QuickJS’s Makefile will detect your OS and choose the appropriate compiler and flags. Run:

    make

    On macOS, Make will use Clang as the default compiler, whereas on Linux, GCC is more common. Compilation will take a few moments. Once completed, several new files will be added to the quickjs directory. qjs is the command-line tool for executing JavaScript files. qjsc is a tool for compiling JavaScript into bytecode.

    Testing QuickJS

    You can run a simple JavaScript file to verify your installation. Create a file named hello.js with the following code:

    console.log("Hello, QuickJS!");

    Save the file into the quickjs directory and then execute it using the qjs binary:

    ./qjs hello.js

    If QuickJS installed, you will see the message “Hello, QuickJS!” Now you have QuickJS set up and ready, it’s time to package an application.

    Packaging JavaScript

    To create a standalone executable, use the qjsc executable in the quickjs directory. You can execute it with these commands:

    qjsc -o hello hello.js
    ./hello

    If it works, you will see “Hello, QuickJS!” on your terminal. This is the file that we will distribute.

    There are many flags that you can pass to qjsc. Try experimenting with each. For example, output bytecode instead of an executable. Or disable regular expressions to decrease binary size.

    Package Size

    The executable for this “Hello, World!” example is 4.6 MB. It may seem large for such a simple program. However, consider the alternatives. Using deno compile I get an executable that is 76 MB. Compiling the hello.js file using Node 21 produces a 98 MB file. So, In perspective 4.6 MB seems pretty good.

    Distribution

    You don’t need anything special to distribute a QuickJS-packaged application. Using the standalone executables, you have a range of distribution options.

    QuickJS is portable. That means that it can run in many environments. When preparing for distribution, consider the target platforms. If you want your application to work on Windows, macOS, and Linux, you must build the app on each system.

    Closing Thoughts

    Whether you’re developing IoT devices or building server-side tools QuickJS is a stellar option. It’s easy to use, fast, and produces relatively tiny executables.

    Try experimenting with it, push its boundaries, and see how it can be used in your projects. What has your experience with QuickJS been? I’d love to hear your stories, successes, and lessons learned.