| name | programming-philosophy |
| description | 0xKobold's core programming philosophy. Use when writing code, reviewing PRs, or making architectural decisions. Covers DRY, KISS, functional programming, and NASA's 10 coding rules for safety-critical code. |
0xKobold Programming Philosophy
Core principles for all code in the 0xKobold ecosystem.
Core Principles
1. DRY - Don't Repeat Yourself
Every piece of knowledge must have a single, unambiguous representation.
function processUser1(user: User) { return user.name.toUpperCase(); }
function processUser2(user: User) { return user.name.toUpperCase(); }
function getDisplayName(user: User) { return user.name.toUpperCase(); }
Enforce with:
- Extract shared logic into utilities/helpers
- Use inheritance or composition for shared behavior
- Create shared types/interfaces for common data structures
2. KISS - Keep It Simple, Stupid
Prefer the simplest solution that works.
class DataManager {
private static instance: DataManager;
private cache: Map<string, any>;
private observers: Observer[];
static getInstance(): DataManager {
if (!this.instance) {
this.instance = new DataManager();
}
return this.instance;
}
}
function processData(data: Data[]): ProcessedData[] {
return data.map(item => ({ ...item, processed: true }));
}
Enforce with:
- Avoid premature abstraction
- Write code that's easy to delete
- Prefer explicit over clever
3. Functional Programming Principles
Prefer immutability and pure functions.
function addItem(list: string[], item: string): void {
list.push(item);
}
function addItem(list: readonly string[], item: string): string[] {
return [...list, item];
}
Principles:
- Immutability: Don't mutate inputs or global state
- Pure functions: Same input → same output, no side effects
- Composition: Build complex behavior from simple functions
- Avoid classes: Prefer functions and data
- No null/undefined: Use discriminated unions or optional chaining with defaults
function getUser(id: string): User | null {
const user = findUser(id);
if (user !== null) {
return user;
}
return null;
}
type Result<T> = { ok: true; value: T } | { ok: false; error: string };
function getUser(id: string): Result<User> {
const user = findUser(id);
return user
? { ok: true, value: user }
: { ok: false, error: `User ${id} not found` };
}
NASA 10 Coding Rules (Safety-Critical)
These rules ensure reliable, verifiable, and safe code.
Rule 1: Avoid Complex Control Flow
No goto, setjmp, longjmp, or recursion.
function factorial(n: number): number {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
function factorial(n: number): number {
let result = 1;
for (let i = n; i > 1; i--) {
result *= i;
}
return result;
}
Rule 2: Loops Must Have Fixed Upper Bounds
Every loop must have a compile-time verifiable limit.
while (data.length > 0) {
process(data.pop());
}
const MAX_ITEMS = 1000;
for (let i = 0; i < Math.min(data.length, MAX_ITEMS); i++) {
if (data[i] === null) break;
process(data[i]);
}
Rule 3: No Dynamic Memory After Initialization
No new, malloc, or heap allocation in running code.
function createBuffer(size: number): number[] {
return new Array(size);
}
const MAX_BUFFER = 1024;
let buffer: number[] = [];
For TypeScript/JavaScript:
- Avoid creating objects in hot paths
- Reuse buffers/pools
- Pre-allocate arrays when size is known
Rule 4: Functions Fit on One Page (~60 lines)
Keep functions short and focused.
async function processEverything(data: any): Promise<void> {
}
async function processEverything(data: Data): Promise<void> {
const validated = validate(data);
const normalized = normalize(validated);
const result = await transform(normalized);
await persist(result);
}
Rule: If a function exceeds 60 lines, it likely does too many things.
Rule 5: Use At Least Two Assertions Per Function
Defensive programming with assertions.
function divide(a: number, b: number): number {
return a / b;
}
function divide(a: number, b: number): number {
console.assert(typeof a === 'number', 'a must be number');
console.assert(typeof b === 'number', 'b must be number');
console.assert(b !== 0, 'b cannot be zero');
if (typeof a !== 'number' || typeof b !== 'number') {
throw new Error('Invalid arguments');
}
if (b === 0) {
throw new Error('Division by zero');
}
return a / b;
}
Rule 6: Declare Data with Minimal Scope
Keep variables as local as possible. Avoid globals.
let config: Config;
function loadConfig() { config = fetchConfig(); }
function useConfig() { return config.value; }
function loadConfig(): Config { return fetchConfig(); }
function useConfig(config: Config) { return config.value; }
Rule 7: Check All Return Values and Parameters
Validate everything. Handle all errors.
fetchData();
processData();
const data = fetchData();
if (!data) {
throw new Error('Failed to fetch data');
}
processData(data);
Rule 8: Limit Preprocessor to Includes and Simple Macros
Avoid complex macros and conditional compilation.
#define PROCESS_IF(cond, action) if (cond) { action; } else { log("failed"); }
function processIf(condition: boolean, action: () => void): void {
if (condition) {
action();
} else {
console.log("failed");
}
}
Rule 9: Limit Pointer Usage to Single Level
Avoid multiple levels of indirection.
interface DoublePointer<T> { pointer: Pointer<T> }
interface Node<T> { value: T; next: Node<T> | null }
For JavaScript/TypeScript:
- Avoid deep property access chains
- Flatten nested objects
- Use option types instead of undefined propagation
Rule 10: Compile with All Warnings Enabled
Treat warnings as errors.
tsc --strict --noImplicitAny --strictNullChecks
tsc --noEmitOnError
In tsconfig.json:
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}
Applying These Rules
Before Writing Code
- Does this violate DRY? Is there existing logic I can reuse?
- Is this the simplest solution? (KISS)
- Am I mutating state? Can I make this pure?
- Does this follow NASA's rules?
Code Review Checklist
Examples from 0xKobold
Good Pattern: Pure function with validation
interface ValidationResult {
valid: boolean;
errors?: string[];
}
function validateConfig(config: unknown): ValidationResult {
console.assert(config !== null, 'config cannot be null');
console.assert(typeof config === 'object', 'config must be object');
if (typeof config !== 'object' || config === null) {
return { valid: false, errors: ['Config must be an object'] };
}
return { valid: true };
}
Good Pattern: Immutable data transformation
function mergeConfig(base: Config, override: Partial<Config>): Config {
return { ...base, ...override };
}
function processMessages(messages: readonly Message[]): ProcessedMessage[] {
return messages
.filter(msg => msg.role === 'user')
.map(msg => ({ ...msg, processed: true }));
}
Bad Pattern: Global state
let currentSession: Session | null = null;
function setSession(s: Session) { currentSession = s; }
function getSession() { return currentSession; }
function createSessionManager(initial: Session) {
let session = initial;
return {
get: () => session,
set: (s: Session) => { session = s; }
};
}