Table of Contents
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

Vivek Bhageria — Lead Firmware R&D Engineer, 12+ years. Ex-Bosch (automotive powertrain), MusicTribe (real-time audio), medical devices. M.Tech BITS Pilani. I write at NerdyElectronics — practical, register-level embedded systems for engineers who want to understand what’s actually happening under the hood.







