# Organizing a Small Program

### Organizing a Small Program

A program grows gradually.

At first, everything may fit in one file:

```zig
const std = @import("std");

fn square(x: i32) i32 {
    return x * x;
}

pub fn main() void {
    std.debug.print("{d}\n", .{square(5)});
}
```

As the program becomes larger, declarations should be separated into logical units.

A common organization is:

```text
src/
    main.zig
    math.zig
    parser.zig
    config.zig
```

Each file handles one area of responsibility.

For example:

```zig
// math.zig

pub fn add(a: i32, b: i32) i32 {
    return a + b;
}

pub fn sub(a: i32, b: i32) i32 {
    return a - b;
}
```

Another file handles configuration:

```zig
// config.zig

pub const app_name = "demo";
pub const version = "0.1.0";
```

The main program imports both:

```zig
const std = @import("std");
const math = @import("math.zig");
const config = @import("config.zig");

pub fn main() void {
    const result = math.add(10, 20);

    std.debug.print(
        "{s} {s}: {d}\n",
        .{
            config.app_name,
            config.version,
            result,
        },
    );
}
```

The output is:

```text
demo 0.1.0: 30
```

Good organization reduces complexity.

Each file should answer a clear question:

- What declarations belong together?
- What should remain private?
- What interface should other files use?

A file should usually expose a small public interface and hide implementation details.

For example:

```zig
fn tokenize() void {}
fn parseTokens() void {}

pub fn parse() void {
    tokenize();
    parseTokens();
}
```

Only `parse` is public.

The internal functions may change freely without affecting other files.

Programs are easier to maintain when dependencies are simple.

This structure is preferable:

```text
main -> parser
main -> math
parser -> tokenizer
```

to tangled dependency graphs where every file imports every other file.

Circular dependencies are especially troublesome:

```text
a imports b
b imports a
```

This often means responsibilities are poorly separated.

Shared declarations should instead move into a separate module.

Naming also matters.

File names should describe their contents:

```text
lexer.zig
http.zig
json.zig
config.zig
```

Names like:

```text
misc.zig
stuff.zig
helpers.zig
```

usually indicate unclear structure.

Small functions also improve organization.

This is difficult to understand:

```zig
fn process() void {
    // 300 lines
}
```

Breaking work into smaller functions makes programs easier to read, test, and reuse.

A useful guideline is:

- one file for one major concept
- one function for one operation

The `main` function should often remain small:

```zig
pub fn main() !void {
    try run();
}
```

Most real work moves into helper functions or modules.

This keeps the program entry point easy to understand.

As programs grow, consistency becomes important:

- similar names
- similar file layout
- predictable interfaces
- limited public APIs

Good structure does not eliminate complexity, but it prevents complexity from spreading everywhere.

Zig encourages explicit structure. Files, imports, and declarations are all visible in source code. There is little hidden machinery.

Exercise 4-21. Split a program into three modules: input, processing, and output.

Exercise 4-22. Move private helper functions out of the public interface.

Exercise 4-23. Refactor a large function into smaller functions.

Exercise 4-24. Why are circular imports usually a sign of poor organization?

