Table of Contents
KEY TAKEAWAYS
- Dispensables are unnecessary code that adds complexity without value: dead code, deep nesting, global abuse
- Dead code (unreachable functions, unused variables) should be deleted, not commented out
- Excessive global variables create hidden dependencies and make code harder to test and reason about
- Reduce deep nesting with early returns, guard clauses, and function extraction
What Are Dispensable Code Smells?
Dispensables are code smells where something exists in the code that should not be there. Removing it makes the code cleaner, shorter, and easier to understand.Smell 1: Dead Code
What it is: Code that is never executed: unreachable branches, unused functions, commented-out blocks, or variables that are written but never read.Smelly Code
int process_value(int value) {
int result = value * 2;
/* Old implementation - kept "just in case" */
// int old_result = value + 10;
// if (old_result > 100) old_result = 100;
// log_value(old_result);
if (result > 0) {
return result;
}
/* This code is unreachable if result is always value*2 and value > 0 */
reset_system(); /* Never called */
return -1;
}
/* Unused function - no one calls it */
void legacy_calibrate(void) {
/* ... 30 lines of code no one uses ... */
}Fix: Delete it
int process_value(int value) {
return value * 2;
}
/* legacy_calibrate() deleted entirely */
/* Commented-out code deleted - it lives in version control if needed */Rule: If code is not being used, delete it. Version control (Git) keeps the history. Commented-out code is not a backup strategy — it is clutter.Smell 2: Speculative Generality
What it is: Abstractions, parameters, or hooks added “in case we need them someday” that are never actually used. This is the code equivalent of YAGNI violations.Smelly Code
/* "Generic" message system - but only one message type is ever used */
typedef struct {
int type;
int priority; /* Always 0 - never used */
int source_id; /* Always 1 - never used */
int destination_id; /* Always 0 - never used */
uint32_t timestamp; /* Never read */
uint8_t flags; /* Always 0 - never used */
int payload; /* The only field that matters */
} message_t;
void send_message(message_t *msg) {
/* Ignores everything except payload */
uart_send_int(msg->payload);
}Fix: Keep only what is used
void send_value(int payload) {
uart_send_int(payload);
}
/* When you actually need message routing, add the struct then */Smell 3: Comments as Deodorant
What it is: Using comments to explain bad code instead of making the code self-explanatory. Good code rarely needs comments to explain what it does.Smelly Code
/* Check if temperature is above maximum allowed temperature
and if the system is not in maintenance mode and if the
alarm has not been silenced by the user */
if (t > 80 && m == 0 && s != 1) {
a = 1; /* Set alarm flag to active */
gpio_set(4); /* Turn on the buzzer on pin 4 */
}Fix: Make the code self-documenting
#define MAX_TEMPERATURE 80
#define PIN_BUZZER 4
int is_alarm_condition(int temp, int maintenance_mode, int alarm_silenced) {
return (temp > MAX_TEMPERATURE)
&& (!maintenance_mode)
&& (!alarm_silenced);
}
if (is_alarm_condition(temperature, maintenance_mode, alarm_silenced)) {
alarm_active = 1;
gpio_set(PIN_BUZZER);
}When comments ARE useful: explaining why (business rules, workarounds for hardware bugs, references to datasheets), not what./* Datasheet Section 4.2: ADC needs 12us settling time after channel switch */ delay_us(12);
Smell 4: Deep Nesting
What it is: Code with 4+ levels of indentation, making it hard to follow the logic and easy to miss edge cases.Smelly Code
void process_packet(uint8_t *buf, int len) {
if (buf != NULL) {
if (len >= 4) {
if (buf[0] == HEADER_BYTE) {
if (validate_checksum(buf, len)) {
if (buf[1] < MAX_CMD) {
if (handlers[buf[1]] != NULL) {
handlers[buf[1]](&buf[2], len - 3);
} else {
log_error("No handler");
}
} else {
log_error("Invalid cmd");
}
} else {
log_error("Bad checksum");
}
}
}
}
}Fix: Use early returns (guard clauses)
void process_packet(uint8_t *buf, int len) {
if (buf == NULL || len = MAX_CMD) {
log_error("Invalid cmd");
return;
}
if (handlers[buf[1]] == NULL) {
log_error("No handler");
return;
}
handlers[buf[1]](&buf[2], len - 3);
}Same logic, maximum 1 level of nesting. Each guard clause eliminates one error case, and the happy path flows straight down.Smell 5: Global Variable Abuse
What it is: Excessive use of global variables, making it impossible to track where values are changed and creating hidden dependencies between modules.Smelly Code
/* globals.h - included by every file */ extern int temperature; extern int humidity; extern int motor_speed; extern int alarm_active; extern int system_mode; extern int error_count; extern int uptime_seconds; /* Any file can read or write any of these at any time */ /* sensor.c writes temperature */ /* display.c reads temperature */ /* alarm.c reads AND writes temperature (to clear alarms) */ /* logger.c reads everything */ /* Who changed motor_speed? Good luck finding out. */
Fix: Encapsulate state in modules with accessor functions
/* sensor.c */
static int temperature = 0; /* Private to this file */
void sensor_update(void) {
temperature = adc_read_temperature();
}
int sensor_get_temperature(void) {
return temperature;
}
/* motor.c */
static int speed = 0; /* Private to this file */
void motor_set_speed(int new_speed) {
speed = clamp(new_speed, 0, 100);
pwm_set(speed);
}
int motor_get_speed(void) {
return speed;
}Now each variable has a clear owner. You can grep for motor_set_speed to find every place the speed is changed.Summary
| Smell | Sign | Fix |
|---|---|---|
| Dead Code | Commented-out blocks, unreachable branches, unused functions | Delete it; trust version control |
| Speculative Generality | Unused parameters, hooks, or abstractions “for the future” | Remove until actually needed |
| Comments as Deodorant | Comments explaining what bad code does | Rename variables and extract functions |
| Deep Nesting | 4+ levels of indentation | Use guard clauses (early returns) |
| Global Variable Abuse | extern variables everywhere | Encapsulate with static + getter/setter functions |

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.







