← All transcripts

The anti-vibe coding philosophy Transcript, AI Summary & Key Points

Awesome · 2 days ago · People & Blogs · 08:49 · EN-US

🧠 AI Summary

Tiger Style is a coding philosophy that prioritizes safety, performance, and developer experience in that order. It emphasizes explicit limits, upfront memory allocation, assertions for critical invariants, batching, cache-aware data layout, deterministic single-threaded transaction processing, careful handling of nondeterministic inputs, minimizing data movement, and fixing known technical debt before adding new functionality.

🔑 Key Points

  • Tiger Style's slogan is to do the hard thing today so tomorrow becomes easy.
  • Tiger Style prioritizes safety first, performance second, and developer experience third.
  • Queues, buffers, loops, and other work should have explicit limits so memory usage and the maximum amount of work remain predictable.
  • Tiger Style prefers explicit integer widths such as U32 over architecture-dependent types such as Usize where possible.
  • TigerBeetle calculates its memory requirements during startup and allocates memory before entering the main event loop.
  • Avoiding general dynamic allocation during transaction processing reduces allocator latency, fragmentation, and lifetime-related states.
  • Assertions encode invariants that may not be represented by the type system and cause the program to fail immediately when assumptions become invalid.
  • The Tiger Style guide recommends averaging at least two assertions per function.
  • Bounded batching reduces the fixed overhead of processing individual operations.
  • Pushing if statements upward and for loops downward can allow a branch to be evaluated once instead of once per element.
  • Tiger Style designs data structures with cache behavior and cache-line boundaries in mind.
  • A modern core running at around 3 GHz gets through roughly 3 billion cycles per second; the transcript compares approximately one cycle for adding register-resident integers with around four or five cycles for L1, 14 for L2, 40 to 60 for L3, and 2 to 400 for main memory.
  • TigerBeetle's transaction state machine is single-threaded because highly contended financial workloads require balance updates to be processed in a defined order.
  • Disk access and replication can run concurrently, while committed transactions are executed sequentially on one core.
  • TigerBeetle prefetches required accounts before processing transfer batches so storage reads do not occur inside the hot loop.
  • Tiger Style treats copying, serialization, deserialization, and other data movement as work that requires justification.
  • TigerBeetle converts physical, nondeterministic inputs into deterministic internal inputs before they reach important business logic.
  • For replicated time values, the primary determines the timestamp and includes it in the replicated operation so every replica uses the same value.
  • TigerBeetle follows a zero technical debt policy: known correctness problems, dangerous performance characteristics, and architectural issues should be fixed before continuing.

✅ Actionable items

  • Set explicit limits for queues, buffers, loops, and other work.
  • Define the maximum amount of work a program can accept and check that the assumption still holds.
  • Use explicit integer widths where possible.
  • Calculate required memory from configured limits and allocate it before entering the main event loop.
  • Use assertions to encode important invariants and fail immediately when they are violated.
  • Collect work into bounded batches instead of processing every operation individually.
  • Push conditionals upward and iterations downward when this reduces repeated branch evaluation.
  • Design data structures around cache behavior and cache-line boundaries.
  • Prefetch required data before entering a hot processing loop.
  • Avoid unnecessary copying, serialization, and deserialization in performance-critical paths.
  • Convert nondeterministic external inputs into deterministic internal inputs before important business logic processes them.
  • Fix known correctness, performance, and architectural problems before building additional functionality on top of them.

🔗 Links mentioned

📄 Transcript

Searchable transcript of The anti-vibe coding philosophy — Awesome (08:49). Search for a phrase, then click its timestamp to jump straight to that moment in the video.

Captions sourced from the original video on YouTube, published by Awesome. The video, its captions and all related intellectual property remain the property of their respective owners; AINotes claims no ownership. Provided for research, accessibility and search — see the Transcript Notice and Copyright Policy.

00:00 For the next 10 minutes or so, let's pretend the year is 2020, the LM craze is not in full swing, and things like software quality and coding standards still matter. Tiger Style's slogan is to do the hard thing today, so tomorrow becomes easy. These days, most of the software world would probably react like >> Ain't nobody got time for that. >> But I have this feeling that we'll all end up paying soon enough for the easy life we are enjoying in the vibe coding, prompt engineering, and agent loop era.

00:26 By the way, you can call me stupid, but I still have no clue what's the deal with this loop agentic engineering, but that's a topic for a different video. Anyway, back to Tiger Style. In this Monday morning review, we look at a coding philosophy focused on safety, performance, and developer experience brought to you by the developers behind the database designed for processing financial transactions at scale.

00:45 I'm mentioning this because TigerBeetle sits in the middle of modern financial systems, where a small mistake can have massive implications with things like duplicated transactions or corrupt balances. When you are working directly with your customers' hard-earned money, the pressure is on, since people tend to be a bit more annoyed if something goes wrong.

01:05 So, Tiger Style focuses on three main values: safety, performance, and developer experience, and this order is actually important. This already makes things slightly unusual because most modern development philosophies start with developer experience. After all, we usually look for the framework that's the most popular and easiest to learn, and that's how we all ended up with React all over the place.

01:24 Don't get me wrong, developer experience matters, but when building serious software, it comes after correctness and performance. Without further ado, let's jump right into the nitty-gritty. One of the core rules is that everything ranging from queues to buffers or basic loops should have an explicit limit because memory usage must be predictable. In practice, we all wrote simple code like this one, which works well if you are building in an ecosystem famous for having major security issues every other week.

01:50 But, if you want to follow best practices, the code should always make the amount of possible work explicit. By the way, don't worry about the programming language in these examples because these rules generally apply if you're aiming to build truly reliable software. So, the program defines the maximum amount of work it can accept and checks that the assumption still holds.

02:10 Also, note that Tiger style also prefers explicit integer widths such as U32 instead of architecture-dependent types such as Usize where possible. For a bit of context, types like Usize exist in languages such as Zig and Rust and their size depends on the target architecture. On a 32-bit system, they are 32-bits wide, while on a 64-bit system, they are usually 64-bits wide.

02:32 Memory allocation follows the same approach. TigerBeetle does not perform general dynamic allocation after initialization, and this is actually kind of fascinating. During startup, the entire system calculates how much memory it needs based on configured limits and allocates it before entering the main event loop. In other words, code processing transactions does not repeatedly allocate and free heap objects.

02:54 Instead, the implementation uses more specialized data structures. This avoids allocator latency and fragmentation during transaction processing, while also reducing the number of lifetime-related states [music] the program has to handle. Memory fragmentation is not something we usually think about in higher-level software, but it becomes important in long-running low-level systems that constantly allocate and free blocks of different sizes.

03:16 Over time, you can end up with plenty of free memory in total, but split across many small regions that are not large enough to satisfy a bigger allocation. This is usually called external fragmentation. You can also get internal fragmentation, where an allocator gives you a block larger than the amount of memory you actually requested because allocations have to follow fixed size classes or alignment requirements.

03:38 Neither problem necessarily crashes the program immediately, but they make memory usage less predictable. So, when you hear that the memory is garbage collected, we usually take it for granted, but under the hood, working with the memory is actually really, really hard. Tiger style also makes heavy use of assertions, and the style guide recommends averaging at least two assertions per function.

03:58 If you are like me and you almost never use assertions in your day-to-day job, just know that they are mechanism used to encode invariants that cannot always be represented by the type system. If these assumptions stop being true, the program fails immediately instead of continuing with invalid state. Of course, this is particularly important in accounting products.

04:19 If an invariant involving balances or transfers has been violated, continuing execution can produce incorrect financial data. Performance rules are similarly concrete, and the style [music] makes extensive use of batching. Work is collected into bounded batches and processed together instead of paying fixed overhead for every individual operation. This affects control flow as well, and the style guide recommends pushing if statements upward and for loops downward.

04:41 In practice, instead of writing code like this, refactor it and extract the iteration inside a specialized function. Now, the branch is evaluated once instead of once per element. Similar rules apply to data layout. Its structures are designed with cache behavior in mind, so a transfer, for example, is deliberately sized around cache line boundaries.

05:00 Accessing memory can cost far more CPU cycles than performing simple arithmetic on data already in cache. And here is your awesome trivia for the day. >> [music] >> A modern core running at around 3 GHz gets through roughly 3 billion cycles a second. Adding two integers that are already sitting in registers costs about one cycle, and on a wide out-of-order core, it can effectively cost less than that because the machine retires several instructions per cycle.

05:27 Now, compare that to the memory hierarchy. Reading from L1 data cache costs somewhere around four or five cycles. L2 is closer to 14, and L3, which is shared between cores, lands somewhere in the 40 to 60 range. So, reading from the main memory costs somewhere between 2 and 400 cycles, depending on the chip and how busy the memory controller is. In other words, in the time it takes to fetch one value from RAM, the core could have executed several hundred arithmetic operations.

05:53 This is why TigerBeetle spends so much effort making sure that the CPU works on compact data that is already available in cache. Another interesting approach is the actual transaction state machine, which is single-threaded. This might sound like a strange choice for a database designed for extremely high throughput, but financial workloads tend to have a lot of contention.

06:12 If thousands of transactions are constantly touching the same popular accounts, those balance updates eventually need to be processed in a defined order. Adding more threads introduces synchronization, locking, and additional cache traffic without necessarily making this part of the system faster. So, TigerBeetle executes committed transactions sequentially on one core.

06:31 But, of course, the operations that can actually run concurrently, such as disk access and replication, are handled separately. For example, before executing a batch of transfers, TigerBeetle can determine which accounts will be needed and prefetch them from storage. Those reads can happen concurrently. Once the required data is available, the actual accounting logic runs synchronously over the batch without performing storage reads inside the hot loop.

06:54 Another performance rule is to avoid unnecessary copying, serialization, and deserialization in the hot path. Tiger style recommends fixed-size structures aligned around the data the CPU actually needs while avoiding repeatedly transforming the same bytes between internal representations. Imagine receiving a 128-byte transfer over the network, deserializing it into one object, copying it into another structure, converting a few fields again for storage, and then copying the whole thing into another buffer.

07:21 Each individual copy might look cheap, but at millions of operations per second, memory bandwidth starts becoming one of your performance limits. Tiger style therefore treats data movement itself as work that needs justification. External interfaces are treated carefully as well. TigerBeetle tries to convert physical, non-deterministic inputs into deterministic internal inputs before they reach important business logic.

07:46 Time is a good example here. The replicated state machine cannot simply call the operating system and ask what time it is because two replicas might receive slightly different answers. Instead, the primary determines the timestamp and includes it in the operation being replicated. Every replica then executes the state transition using the same value.

08:02 And before wrapping things up, let's look at one of the more controversial rules. TigerBeetle has a zero technical technical debt policy. The idea is that when developers discover a known correctness problem, dangerous performance characteristic, or architectural issue, they should fix it before continuing instead of adding it to a backlog with the assumption that somebody will eventually come back to it.

08:24 Obviously, there is some judgment involved here because almost every software project has imperfect code somewhere, but the actual policy is useful to understand because TigerBeetle is trying to avoid knowingly building new functionality on top of problems that are already understood. If you like this video, you should consider joining our community where I'm posting more dedicated weekly content. Please don't forget to smash all the buttons, and see you in the next one.