Code Organization: Beyond Arbitrary Size Limits

software-engineering

Beyond arbitrary code size limits, discover key principles for effective software organization. Learn to optimize module interfaces, respect display constraints, and use design principles for robust architecture.

While some coding standards impose strict, seemingly arbitrary limits—such as a hard limit of 70 lines per function or a maximum of 100 columns per line—it's worth noting that even organizations with such rules may also manage very large files. For instance, tidy.zig#L746 is explicitly excluded from 'no large binary blobs in git history' policies, highlighting a common contradiction.

This raises a fundamental question: Just how large should functions, classes, or files truly be? There are two primary perspectives to consider.

Minimize The Cut

The first principle asserts that absolute size is largely irrelevant. Instead, the focus should be on keeping related elements together and independent elements apart. The goal isn't merely to minimize the size of individual components or the number of dependencies between them. Such an approach could lead to degenerate solutions, like a single monolithic component or every line of code existing in its own file.

Instead, the aim is to optimize the ratio of a module's size to its interface. This is akin to dividing the volume by the surface area; it's about the 'shape' of the module, not just its dimensions.

For example, a self-contained data structure should be moved to a separate file, regardless of whether it spans ten or ten thousand lines. We see this in practice with files like replica.zig and timestamp_range.zig.

When applied to functions, this rule suggests a visual metaphor: the 'inverted hourglass.' A function has inputs (arguments) and outputs. The combined count of inputs and outputs defines the size of its interface, while the length of its body measures the implementation. Ideally, functions should have bodies that are large relative to their interfaces. Conversely, an 'hourglass' function—one with a large interface and a small body—is often a design 'smell'.

This principle is also useful for picking dependencies. Dependencies are essential, but sometimes, examining a dependency reveals it doesn't do anything meaningful by itself, merely repackaging actual logic (implemented in a transitive dependency) with a different interface. The goal should be to cut through this 'glue' and get straight to the algorithmic core.

Honor Physical Limits

Against these logical principles stand practical, physical limits. The size of your display, for instance, dictates how much code can be comfortably viewed. This is why a 100-column limit is beneficial: it allows two copies of code to fit side-by-side on a modern 16x9 display, crucial for comparing two versions or seeing both caller and callee to ensure invariants.

Vertical space is equally constrained. There's a significant cognitive difference between a function that fits entirely on a screen and one that requires even slight scrolling. This contributes to a 'Schelling point' for the upper bound on function length, typically around 60-70 lines, making it easier to grasp a function's full context immediately.

However, there's no inherent physical limit on the file size or the total number of files. These can grow, provided efficient navigation mechanisms are in place. The ability to quickly open any file in a project by typing just a few letters, often via fuzzy search, is not optional. Similarly, developers must learn to navigate large files efficiently, swiftly listing all functions or jumping to a specific one by fuzzy name.

Art Is Born Of Constraints

Physical constraints, while restrictive, can be valuable guides to better design. While the 'cut' size doesn't directly correlate with a module's line count, there's often a relationship. A 10,000-line file, for example, might truly be three different subsystems inadvertently fighting each other. Good interface design is not intuitive; the resulting interface shape becomes obvious only after discovery. If code cannot comfortably fit within your field of view, it might be a signal to step away from the screen and engage in deeper architectural thinking.