AI is huge. Yet, many engineers are still sketchy about it. Some don’t use it at all, and many hold strong opinions Against it.
I was one of those engineers until I realized the real power of LLMs. First of all, LLMs cannot do for you what you cannot already do. That s the truth buried beneath all the marketing slogans AI companies use to justify their costs. Investors love that narrative, trust AI talent to deliver on their promises but at the end of the day, they know the risks.
To me, AI as a tool feels like the moment touchscreen phones came out while most of the world was still clinging to their buttony stuff. The difference? This time it is ridiculously accessible. You can chat with state of the art models like Claude Sonnet 4, DeepSeek V3, or ChatGPT-5 for free. And here is the kicker: they want software engineers to use them, because every prompt you feed back into the system makes their models sharper.
Why focus so much on engineers? Logic, logic, logic.
When you tell someone, I know a guy who can take one small piece of a puzzle and instantly complete the whole picture, they would call him a magician.
But experienced engineers already operate on something close to that level. A seasoned professional can take your vague, one-line idea and expand it into a robust architecture covering use cases, scaling considerations, optimizations, and tradeoffs faster than you imagined it yourself.
LLMs work the same way. A prompt is just one piece of the puzzle. The real picture depends on your ability to guide it.
That does not mean vibe coding is the future. Maybe vibe engineering is.
But here is where people often go wrong: once they see AI output, in their excitement, they drop all the fundamentals SDLC, testing, clean code, reviews. AI will happily spit out a solution, but it might not be what you actually need. Sometimes it will even bluff masking uncertainty behind confident words. Suddenly you re second-guessing yourself and running back to Google.
So here s the mindset shift: instead of leaping from step A (a prompt) to step Z (a finished solution), go back to fundamentals. Walk the AI through your process step by step, just like you would a junior collaborator.
For example, if you re building with TypeScript, do not ask for a full implementation right away. Treat the AI as a collaborator (it is just a tool, but it likes roleplay). Give it structure:
Don t implement anything yet. Just show me the interfaces, well-commented, following SOLID principles, and make sure it is scalable.
Let us compare two different approaches for the same problem: creating a bitmap using Cloudflare KV storage. A bitmap stores binary data (0s and 1s) compactly as an encoded string. Each bit represents a state whether a user is active or has performed a specific action. This makes it extremely memory-efficient for large datasets.
Asking AI just to build it
Here we are using AI as the way most people use it, just here is A give me Z, all of Z.
Prompt :
Build me a bitmap system on Cloudflare KV that tracks user activity.
Result :
// user-activity-bitmap.js
export class UserActivityBitmap {
constructor(kvNamespace, userId) {
this.kv = kvNamespace;
this.userId = userId;
this.bitmapKey = `user:${userId}:activity`;
this.actions = {
LOGIN: 0,
PURCHASE: 1,
VIEW_PRODUCT: 2,
ADD_TO_CART: 3,
SEARCH: 4,
// Add more actions as needed
};
}
// Initialize bitmap for a user
async initialize() {
const existing = await this.kv.get(this.bitmapKey);
if (!existing) {
// Start with all zeros (8 bytes = 64 bits)
const initialBitmap = new ArrayBuffer(8);
const view = new Uint8Array(initialBitmap);
await this.kv.put(this.bitmapKey, view);
}
}
// Record an action
async recordAction(action, timestamp = Date.now()) {
const dayOfYear = this.getDayOfYear(timestamp);
const bitPosition = this.calculateBitPosition(action, dayOfYear);
const bitmap = await this.getBitmap();
const updatedBitmap = this.setBit(bitmap, bitPosition);
await this.kv.put(this.bitmapKey, updatedBitmap);
// Also store detailed activity in separate KV key for analytics
await this.storeDetailedActivity(action, timestamp);
}
// Check if user performed specific action on specific day
async hasAction(action, daysAgo = 0) {
const targetDate = new Date();
targetDate.setDate(targetDate.getDate() - daysAgo);
const dayOfYear = this.getDayOfYear(targetDate);
const bitPosition = this.calculateBitPosition(action, dayOfYear);
const bitmap = await this.getBitmap();
return this.getBit(bitmap, bitPosition);
}
// Get user activity summary
async getActivitySummary(days = 30) {
const summary = {};
const bitmap = await this.getBitmap();
for (const [actionName, actionId] of Object.entries(this.actions)) {
summary[actionName] = [];
for (let i = 0; i < days; i++) {
const dayOfYear = this.getDayOfYear(new Date(Date.now() - i * 86400000));
const bitPosition = this.calculateBitPosition(actionId, dayOfYear);
const performed = this.getBit(bitmap, bitPosition);
summary[actionName].push(performed ? 1 : 0);
}
}
return summary;
}
// Helper methods
async getBitmap() {
const bitmapData = await this.kv.get(this.bitmapKey, 'arrayBuffer');
return new Uint8Array(bitmapData || new ArrayBuffer(8));
}
calculateBitPosition(actionId, dayOfYear) {
// 8 actions per day (3 bits for action + remainder for day tracking)
return (dayOfYear * 8) + actionId;
}
getDayOfYear(date) {
const start = new Date(date.getFullYear(), 0, 0);
const diff = date - start;
const oneDay = 1000 * 60 * 60 * 24;
return Math.floor(diff / oneDay) % 365; // Wrap around yearly
}
setBit(bitmap, position) {
const byteIndex = Math.floor(position / 8);
const bitIndex = position % 8;
if (byteIndex >= bitmap.length) {
// Extend bitmap if needed
const newBitmap = new Uint8Array(byteIndex + 1);
newBitmap.set(bitmap);
bitmap = newBitmap;
}
bitmap[byteIndex] |= (1 << bitIndex);
return bitmap;
}
getBit(bitmap, position) {
const byteIndex = Math.floor(position / 8);
const bitIndex = position % 8;
if (byteIndex >= bitmap.length) {
return false;
}
return (bitmap[byteIndex] & (1 << bitIndex)) !== 0;
}
async storeDetailedActivity(action, timestamp) {
const detailKey = `user:${this.userId}:activity:details`;
const activity = {
action,
timestamp,
date: new Date(timestamp).toISOString().split('T')[0]
};
// Store last 100 activities for detailed analysis
const existing = await this.kv.get(detailKey, 'json');
const activities = existing || [];
activities.unshift(activity);
// Keep only the most recent 100 activities
if (activities.length > 100) {
activities.pop();
}
await this.kv.put(detailKey, JSON.stringify(activities));
}
}
If you are experienced software engineer you will see a lot of problems with this code, it is not that maintainable, but it might work as expected with minor fixable bugs !
Asking the AI to prototype with interfaces
Here we are aiming to acceleration not compellation, we are hoping from the AI to do what it does best which is predicting the next text, there is no noise, the input will fly in-out the neural network.
Prompt :
Prototype a Cloudflare KV-based bitmap ( encoded-string of bits to store bits in more efficient way ) system in TypeScript. Do not provide implementation. Instead, define well-commented interfaces following SOLID principles. Ensure the design is scalable and flexible for future changes. Create interfaces as well for a use case of analytics using the the newly created bitmap
Result :
/**
* CORE BITMAP INTERFACES
*
* These interfaces define the fundamental bitmap operations and storage mechanisms.
* Following Interface Segregation Principle (ISP) to keep interfaces focused.
*/
/**
* Represents a single bitmap with basic bit manipulation operations
*/
interface IBitmap {
/**
* Sets a bit at the specified position
* @param position - The zero-based position to set
* @param value - The value to set (true for 1, false for 0)
*/
setBit(position: number, value: boolean): Promise<void>;
/**
* Gets the value of a bit at the specified position
* @param position - The zero-based position to read
* @returns The bit value (true for 1, false for 0)
*/
getBit(position: number): Promise<boolean>;
/**
* Sets multiple bits at once for batch operations
* @param positions - Array of positions to set
* @param values - Corresponding values to set
*/
setBits(positions: number[], values: boolean[]): Promise<void>;
/**
* Gets multiple bits at once for batch operations
* @param positions - Array of positions to read
* @returns Array of bit values
*/
getBits(positions: number[]): Promise<boolean[]>;
/**
* Counts the number of set bits (population count) in the bitmap
* @returns The number of bits set to 1
*/
countSetBits(): Promise<number>;
/**
* Returns the total capacity (number of bits) this bitmap can hold
*/
getCapacity(): number;
/**
* Serializes the bitmap to a compressed string format for storage
*/
serialize(): Promise<string>;
/**
* Deserializes the bitmap from a compressed string format
* @param data - The serialized bitmap data
*/
deserialize(data: string): Promise<void>;
}
/**
* Factory interface for creating bitmap instances
* Follows Factory Pattern for flexible bitmap creation
*/
interface IBitmapFactory {
/**
* Creates a new bitmap with specified capacity
* @param capacity - Number of bits the bitmap can hold
* @param namespace - Optional namespace for organizing bitmaps
*/
createBitmap(capacity: number, namespace?: string): Promise<IBitmap>;
/**
* Loads an existing bitmap by its identifier
* @param bitmapId - Unique identifier for the bitmap
*/
loadBitmap(bitmapId: string): Promise<IBitmap>;
}
/**
* Storage interface abstracting Cloudflare KV operations
* Follows Dependency Inversion Principle (DIP)
*/
interface IBitmapStorage {
/**
* Stores serialized bitmap data
* @param key - Unique identifier for the bitmap
* @param data - Serialized bitmap data
* @param options - Optional storage options (TTL, metadata)
*/
store(key: string, data: string, options?: StorageOptions): Promise<void>;
/**
* Retrieves serialized bitmap data
* @param key - Unique identifier for the bitmap
*/
retrieve(key: string): Promise<string | null>;
/**
* Deletes bitmap data from storage
* @param key - Unique identifier for the bitmap
*/
delete(key: string): Promise<void>;
/**
* Lists all available bitmaps with optional filtering
* @param prefix - Optional prefix filter for bitmap keys
*/
list(prefix?: string): Promise<string[]>;
}
/**
* Options for bitmap storage operations
*/
interface StorageOptions {
expirationTtl?: number;
metadata?: Record<string, any>;
}
/**
* ANALYTICS INTERFACES
*
* These interfaces define analytics-specific operations using bitmaps
* Separate from core bitmap operations to follow Single Responsibility Principle
*/
/**
* Represents an analytics event that can be tracked with bitmaps
*/
interface IAnalyticsEvent {
readonly eventType: string;
readonly timestamp: Date;
readonly userId: string;
readonly properties?: Record<string, any>;
}
/**
* Interface for tracking user events using bitmap-based analytics
*/
interface IEventTracker {
/**
* Tracks a user event and updates corresponding bitmaps
* @param event - The analytics event to track
*/
trackEvent(event: IAnalyticsEvent): Promise<void>;
/**
* Tracks multiple events in a batch operation
* @param events - Array of analytics events
*/
trackEvents(events: IAnalyticsEvent[]): Promise<void>;
}
/**
* Interface for querying analytics data from bitmaps
*/
interface IAnalyticsQuery {
/**
* Counts unique users who performed a specific event
* @param eventType - The event type to query
* @param timeRange - Optional time range filter
*/
countUniqueUsers(eventType: string, timeRange?: TimeRange): Promise<number>;
/**
* Checks if a specific user performed an event
* @param userId - The user identifier
* @param eventType - The event type to check
* @param timeRange - Optional time range filter
*/
hasUserPerformedEvent(
userId: string,
eventType: string,
timeRange?: TimeRange
): Promise<boolean>;
/**
* Finds users who performed multiple events (cohort analysis)
* @param eventTypes - Array of event types to check
* @param timeRange - Optional time range filter
*/
findUsersWithEvents(
eventTypes: string[],
timeRange?: TimeRange
): Promise<string[]>;
/**
* Performs bitwise operations between different event bitmaps
* @param operation - The bitwise operation to perform
* @param eventTypes - Event types to include in the operation
*/
performBitwiseOperation(
operation: BitwiseOperation,
eventTypes: string[]
): Promise<IBitmap>;
}
/**
* Time range for filtering analytics queries
*/
interface TimeRange {
start: Date;
end: Date;
}
/**
* Supported bitwise operations for analytics
*/
enum BitwiseOperation {
AND = 'AND',
OR = 'OR',
XOR = 'XOR',
NOT = 'NOT'
}
/**
* Configuration interface for analytics system
*/
interface IAnalyticsConfig {
readonly defaultBitmapCapacity: number;
readonly storageNamespace: string;
readonly compressionEnabled: boolean;
readonly batchProcessingSize: number;
}
/**
* Main analytics service interface coordinating all components
*/
interface IAnalyticsService {
readonly config: IAnalyticsConfig;
readonly eventTracker: IEventTracker;
readonly analyticsQuery: IAnalyticsQuery;
/**
* Initializes the analytics service
*/
initialize(): Promise<void>;
/**
* Performs maintenance operations (compaction, cleanup)
*/
maintain(): Promise<void>;
/**
* Exports analytics data for external processing
* @param options - Export configuration options
*/
exportData(options: ExportOptions): Promise<AnalyticsData>;
}
/**
* Options for data export operations
*/
interface ExportOptions {
format: 'json' | 'csv' | 'raw';
includeUserIds?: boolean;
timeRange?: TimeRange;
}
/**
* Result structure for exported analytics data
*/
interface AnalyticsData {
summary: AnalyticsSummary;
detailedData: any;
exportedAt: Date;
}
/**
* Summary information for analytics data
*/
interface AnalyticsSummary {
totalUsers: number;
totalEvents: number;
uniqueEvents: number;
timeRange: TimeRange;
}
/**
* STRATEGY PATTERN INTERFACES
* For flexible bitmap encoding/compression strategies
*/
/**
* Strategy interface for bitmap encoding/compression
*/
interface IBitmapEncodingStrategy {
/**
* Encodes a bitmap to a compressed string
* @param bitmap - The bitmap to encode
*/
encode(bitmap: IBitmap): Promise<string>;
/**
* Decodes a compressed string back to a bitmap
* @param data - The compressed data
* @param capacity - The original bitmap capacity
*/
decode(data: string, capacity: number): Promise<IBitmap>;
/**
* Gets the strategy identifier
*/
readonly strategyName: string;
}
/**
* Registry for managing different encoding strategies
*/
interface IEncodingStrategyRegistry {
/**
* Registers a new encoding strategy
* @param strategy - The strategy to register
*/
registerStrategy(strategy: IBitmapEncodingStrategy): void;
/**
* Gets a strategy by name
* @param name - The strategy identifier
*/
getStrategy(name: string): IBitmapEncodingStrategy;
/**
* Gets all available strategies
*/
getAllStrategies(): IBitmapEncodingStrategy[];
}
/**
* OBSERVER PATTERN INTERFACES
* For real-time analytics updates and monitoring
*/
/**
* Observer interface for analytics events
*/
interface IAnalyticsObserver {
/**
* Called when new events are tracked
* @param events - Array of tracked events
*/
onEventsTracked(events: IAnalyticsEvent[]): void;
/**
* Called when analytics data is queried
* @param queryType - Type of query performed
* @param result - Query result data
*/
onQueryPerformed(queryType: string, result: any): void;
}
/**
* Subject interface for managing analytics observers
*/
interface IAnalyticsSubject {
/**
* Registers an observer
* @param observer - The observer to register
*/
registerObserver(observer: IAnalyticsObserver): void;
/**
* Removes an observer
* @param observer - The observer to remove
*/
removeObserver(observer: IAnalyticsObserver): void;
/**
* Notifies all observers of events
* @param events - The events to notify about
*/
notifyObservers(events: IAnalyticsEvent[]): void;
}
I don’t know about you, but the first prompt output looks like junior engineer trying his best and struggling. The second prompt output feels like an engineer trying to build the next Key-value database.
Best,
Ahmed,
Top comments (0)