Skip to content
Home » Software Design » YAGNI Principle (You Aren’t Gonna Need It)

YAGNI Principle (You Aren’t Gonna Need It)

YAGNI Principle featured image with purple background, Clean Code badge, Y icon, You Arent Gonna Need It subtitle in the Software Design in C series by NerdyElectronics
Software Design Principles in C
Part 9 of 31View Full Path →

KEY TAKEAWAYS

  • YAGNI: do not build features until they are needed
  • Speculative code costs time to write, test, document, and maintain
  • Simple code is easier to change later than complex code is to simplify
  • If a feature is needed later, add it then — it will be easier because the codebase is simpler
  • YAGNI works hand-in-hand with KISS: build the simplest thing that works

What Is the YAGNI Principle?

YAGNI stands for You Aren’t Gonna Need It. It means: do not add functionality until it is actually necessary.Developers often build “future-proof” features based on guesses about what might be needed later. Most of the time, those features are never used — but they still cost time to build, test, and maintain.

Example 1: Generic Linked List When You Need a Simple Array

Bad: Building a generic data structure “for the future”

/* Requirement: store up to 10 sensor readings */

/* Developer thinks: "What if we need more? Let me build a linked list!" */
typedef struct node {
    int value;
    struct node *next;
} node_t;

node_t *head = NULL;

void add_reading(int value) {
    node_t *new_node = malloc(sizeof(node_t));
    if (!new_node) return;
    new_node->value = value;
    new_node->next = head;
    head = new_node;
}

int get_reading(int index) {
    node_t *current = head;
    for (int i = 0; i next;
    }
    return current ? current->value : -1;
}

void free_readings(void) {
    while (head) {
        node_t *tmp = head;
        head = head->next;
        free(tmp);
    }
}
/* 40+ lines, dynamic memory, potential memory leaks, harder to debug */

Good: Build what you actually need

/* Requirement: store up to 10 sensor readings */
#define MAX_READINGS 10

int readings[MAX_READINGS];
int reading_count = 0;

void add_reading(int value) {
    if (reading_count = 0 && index < reading_count) {
        return readings[index];
    }
    return -1;
}
/* 15 lines, no malloc, no free, no memory leaks, easy to debug */
If you later need more than 10, then change the approach. Until then, the simple array is faster, safer, and uses less RAM.

Example 2: Unused Callback Hooks “For Future Use”

Bad: Adding hooks that nobody uses

typedef struct {
    void (*on_start)(void);
    void (*on_stop)(void);
    void (*on_error)(int code);
    void (*on_data_ready)(int *data, int len);
    void (*on_timeout)(void);
    void (*on_state_change)(int old_state, int new_state);
    void (*on_config_changed)(const char *key, const char *value);
} motor_callbacks_t;

void motor_init(motor_callbacks_t *callbacks) {
    /* Store all 7 callback pointers */
    /* Every caller must provide this struct */
    /* Most callers set 5 of 7 to NULL */
}

/* Caller: */
motor_callbacks_t cb = {
    .on_start = my_start_handler,
    .on_error = my_error_handler,
    .on_stop  = NULL,            /* Don't need this */
    .on_data_ready = NULL,       /* Don't need this */
    .on_timeout = NULL,          /* Don't need this */
    .on_state_change = NULL,     /* Don't need this */
    .on_config_changed = NULL,   /* Don't need this */
};
motor_init(&cb);

Good: Only implement the callbacks you actually need

/* Only the callbacks that are actually used today */
typedef void (*motor_error_fn)(int code);

static motor_error_fn error_handler = NULL;

void motor_init(void) {
    /* Simple init, no callback struct needed */
}

void motor_set_error_handler(motor_error_fn handler) {
    error_handler = handler;
}

/* Inside motor driver: */
void motor_run(void) {
    if (check_overcurrent()) {
        if (error_handler) error_handler(ERR_OVERCURRENT);
    }
}
When you actually need an on_timeout callback, add it then. Adding it now just creates dead code that must be maintained.

Signs You Are Violating YAGNI

  • “We might need this later” — if you are not sure, you do not need it now
  • Configuration options that no one has asked for
  • Abstract factory patterns for a system with one concrete type
  • Support for protocols or file formats that no requirement mentions
  • Parameters that are always passed the same value

Key Takeaways

  • YAGNI: do not build features until they are needed
  • Speculative code costs time to write, test, document, and maintain
  • Simple code is easier to change later than complex code is to simplify
  • If a feature is needed later, add it then — it will be easier because the codebase is simpler
  • YAGNI works hand-in-hand with KISS: build the simplest thing that works

📖 Related: Factory Pattern in C — With Practical Examples

Leave a Reply

Your email address will not be published. Required fields are marked *