Table of Contents
KEY TAKEAWAYS
- KISS: the simplest solution that meets the requirements is the best solution
- Avoid dynamic memory allocation when a fixed-size buffer works
- Avoid abstractions when you only have one concrete implementation
- Write code for the reader, not to show off — you will be the reader in 6 months
- If you cannot explain your code to a colleague in 30 seconds, it is too complex
What Is the KISS Principle?
KISS stands for Keep It Simple, Stupid. It means: prioritize simplicity; avoid unnecessary complexity. The simplest solution that works correctly is usually the best one.Clever code impresses no one during a 3 AM debugging session. Simple code does.Example 1: Over-Engineered Config Parser
Bad: Dynamic memory, linked lists, and generic parsing for a 5-setting config
/* Over-engineered: dynamic allocation, linked list, generic parser */
typedef struct config_node {
char *key;
char *value;
struct config_node *next;
} config_node_t;
config_node_t *config_head = NULL;
int config_parse(const char *filename) {
FILE *f = fopen(filename, "r");
if (!f) return -1;
char line[128];
while (fgets(line, sizeof(line), f)) {
config_node_t *node = malloc(sizeof(config_node_t));
node->key = malloc(32);
node->value = malloc(32);
sscanf(line, "%31[^=]=%31s", node->key, node->value);
node->next = config_head;
config_head = node;
}
fclose(f);
return 0;
}
const char *config_get(const char *key) {
config_node_t *n = config_head;
while (n) {
if (strcmp(n->key, key) == 0) return n->value;
n = n->next;
}
return NULL;
}
/* Plus you need config_free() to avoid memory leaks... */Good: Simple struct, simple parsing, no dynamic memory
/* Simple: fixed struct, no allocation, no linked list */
typedef struct {
int baud_rate;
int sensor_interval_ms;
int alarm_threshold;
int log_enabled;
char device_name[32];
} config_t;
config_t config = {
.baud_rate = 9600, /* Defaults */
.sensor_interval_ms = 1000,
.alarm_threshold = 80,
.log_enabled = 1,
.device_name = "Sensor-01",
};
int config_load(const char *filename) {
FILE *f = fopen(filename, "r");
if (!f) return -1; /* Use defaults */
char line[128];
while (fgets(line, sizeof(line), f)) {
sscanf(line, "baud_rate=%d", &config.baud_rate);
sscanf(line, "sensor_interval=%d", &config.sensor_interval_ms);
sscanf(line, "alarm_threshold=%d", &config.alarm_threshold);
sscanf(line, "log_enabled=%d", &config.log_enabled);
sscanf(line, "device_name=%31s", config.device_name);
}
fclose(f);
return 0;
}No malloc, no free, no linked list, no generic lookup function. The config struct is directly accessible with config.baud_rate. Simple, fast, and impossible to leak memory.Example 2: Clever One-Liner vs Clear Code
Bad: Compressed, “clever” code
/* What does this do? */ int r = (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); /* Or this? */ val = val mx ? mx : val;
Good: Clear, readable code
/* Find maximum of three values */
int max_of_three(int a, int b, int c) {
int max = a;
if (b > max) max = b;
if (c > max) max = c;
return max;
}
/* Clamp value to range [0, max] */
int clamp_positive(int val, int max_val) {
if (val max_val) return max_val;
return val;
}The clear version takes a few more lines but can be understood instantly. It is also easier to set breakpoints and step through in a debugger.KISS in Practice
| Complex Approach | KISS Approach |
|---|---|
| Generic callback-driven state machine for 3 states | Simple switch-case with 3 cases |
| Dynamic array with realloc for a fixed-size list | Fixed-size array with a count variable |
| Custom string library | Standard snprintf and strncpy |
| Thread pool for 2 tasks | Two dedicated threads (or a simple super-loop) |
Key Takeaways
- KISS: the simplest solution that meets the requirements is the best solution
- Avoid dynamic memory allocation when a fixed-size buffer works
- Avoid abstractions when you only have one concrete implementation
- Write code for the reader, not to show off — you will be the reader in 6 months
- If you cannot explain your code to a colleague in 30 seconds, it is too complex
Example 3: Over-Engineered String Comparison
Developers sometimes write elaborate solutions for simple problems. Here is a case where a straightforward task gets buried under unnecessary complexity.Bad — Reinventing the Wheel
int strings_match(const char *a, const char *b) {
int len_a = 0, len_b = 0;
const char *pa = a, *pb = b;
// First pass: compute lengths
while (*pa++) len_a++;
while (*pb++) len_b++;
// Early exit on length mismatch
if (len_a != len_b) return 0;
// Second pass: compare character by character
for (int i = 0; i < len_a; i++) {
if (a[i] != b[i]) return 0;
}
return 1;
}This is 15 lines that iterate over both strings twice. It is correct, but it ignores a well-tested standard library function that does exactly this.Good — Use What Exists
int strings_match(const char *a, const char *b) {
return strcmp(a, b) == 0;
}One line. Universally understood. Tested by millions of programs. strcmp is part of the C standard library — no need to rewrite it.How to Recognize Violations of KISS
Ask yourself these questions when reviewing code:- Can I explain this function in one sentence? If you need a paragraph, it is probably too complex.
- Does this use a feature just because it is clever? Bitwise tricks, macro magic, and pointer arithmetic have their place — but only when they genuinely improve performance or clarity.
- Would a junior developer understand this in under a minute? Code is read far more often than it is written. Optimize for the reader.
- Am I solving a problem that does not exist yet? That overlaps with YAGNI, but it is a common source of unnecessary complexity.
KISS in Architecture
KISS applies beyond individual functions. At the system level:- Prefer flat module structures over deeply nested hierarchies
- Use direct function calls before reaching for callback tables or event systems
- Start with a simple
if/elsebefore building a rule engine - Use arrays before linked lists unless you genuinely need O(1) insertion
📖 Related: Dynamic Memory Allocation in C

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.







