Programming Fundamentals for Vibe Coding
Understanding programming fundamentals will significantly improve your ability to work with AI coding tools. Even a basic grasp of these concepts will help you communicate more effectively with AI and understand the code it generates.
While we covered some essential programming concepts earlier, this section will dive deeper into the fundamentals you need to understand to effectively communicate with AI coding tools and work with the code they generate. This knowledge will help you bridge the gap between your ideas and functional applications.
Programming Paradigms
Understanding different programming paradigms helps you choose the right approach for your projects:
Procedural Programming
Procedural programming organizes code as a sequence of steps or procedures:
// Procedural approach to calculating total price
let subtotal = 0;
for (let i = 0; i < items.length; i++) {
subtotal += items[i].price;
}
let tax = subtotal * 0.08;
let total = subtotal + tax;
When to use: Simple scripts, straightforward algorithms, and when you're just getting started.
Object-Oriented Programming (OOP)
OOP organizes code around objects that contain both data and behavior:
// Object-oriented approach to a shopping cart
class ShoppingCart {
constructor() {
this.items = [];
}
addItem(item) {
this.items.push(item);
}
calculateTotal() {
let subtotal = this.items.reduce((sum, item) => sum + item.price, 0);
let tax = subtotal * 0.08;
return subtotal + tax;
}
}
// Usage
const cart = new ShoppingCart();
cart.addItem({ name: "Laptop", price: 999 });
cart.calculateTotal();
When to use: Complex applications, when modeling real-world entities, and for code organization in larger projects.
Functional Programming
Functional programming treats computation as the evaluation of mathematical functions and avoids changing state:
// Functional approach to calculating total price
const calculateSubtotal = items => items.reduce((sum, item) => sum + item.price, 0);
const calculateTax = subtotal => subtotal * 0.08;
const calculateTotal = items => {
const subtotal = calculateSubtotal(items);
return subtotal + calculateTax(subtotal);
};
// Usage
const total = calculateTotal(items);
When to use: Data processing, complex calculations, and when you want to avoid side effects and mutable state.
Data Structures and Their Uses
Understanding common data structures helps you organize and manipulate data effectively:
Arrays/Lists
Arrays store ordered collections of items:
// Creating and using arrays
const fruits = ["apple", "banana", "cherry"];
fruits.push("date"); // Add to end
fruits.pop(); // Remove from end
fruits.unshift("apricot"); // Add to beginning
fruits.shift(); // Remove from beginning
When to use: When you need an ordered collection of items, like a list of tasks, products, or user information.
Objects/Dictionaries
Objects store key-value pairs:
// Creating and using objects
const user = {
name: "John",
email: "john@example.com",
age: 30
};
// Accessing properties
console.log(user.name); // Using dot notation
console.log(user["email"]); // Using bracket notation
// Adding/modifying properties
user.location = "New York";
user.age = 31;
When to use: When you need to store properties of an entity, like user profiles, product details, or application settings.
Sets
Sets store unique values:
// Creating and using sets
const uniqueTags = new Set();
uniqueTags.add("javascript");
uniqueTags.add("webdev");
uniqueTags.add("javascript"); // Duplicate, won't be added
// Checking if a value exists
uniqueTags.has("javascript"); // true
When to use: When you need to ensure uniqueness, like tracking unique visitors, tags, or categories.
Maps
Maps store key-value pairs with any type of key:
// Creating and using maps
const userRoles = new Map();
userRoles.set(user1, "admin");
userRoles.set(user2, "editor");
// Getting values
userRoles.get(user1); // "admin"
When to use: When you need to associate data with objects, or when keys aren't simple strings.
Web Development Fundamentals
The DOM (Document Object Model)
The DOM is a programming interface for web documents, representing the page as a tree of objects:
// Selecting elements
const header = document.getElementById("header");
const paragraphs = document.querySelectorAll("p");
// Modifying elements
header.textContent = "New Heading";
header.style.color = "blue";
// Creating elements
const newButton = document.createElement("button");
newButton.textContent = "Click Me";
document.body.appendChild(newButton);
// Handling events
newButton.addEventListener("click", function() {
alert("Button clicked!");
});
When to use with AI: When describing how to interact with web page elements, create dynamic content, or respond to user actions.
HTTP and APIs
Understanding HTTP requests and APIs is crucial for web applications:
// Fetching data from an API
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log(data);
// Do something with the data
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
Modern approach using async/await:
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
console.log(data);
// Do something with the data
} catch (error) {
console.error('There was a problem with the fetch operation:', error);
}
}
fetchData();
When to use with AI: When building applications that need to retrieve or send data to servers, integrate with external services, or store data in the cloud.
Responsive Design
Responsive design ensures your application works well on all devices:
/* Basic responsive design with CSS */
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
/* Media queries for different screen sizes */
@media (max-width: 768px) {
.container {
padding: 0 20px;
}
.column {
width: 100%;
}
}
When to use with AI: When describing how your application should adapt to different screen sizes and devices.
Common Programming Patterns
Understanding common patterns helps you communicate more effectively with AI tools:
Event-Driven Programming
Event-driven programming responds to user actions or system events:
// Event-driven programming example
document.getElementById("saveButton").addEventListener("click", function() {
saveData();
});
window.addEventListener("resize", function() {
adjustLayout();
});
function saveData() {
// Code to save data
}
function adjustLayout() {
// Code to adjust layout based on window size
}
When to use with AI: When building interactive applications that respond to user actions.
CRUD Operations
CRUD (Create, Read, Update, Delete) is a common pattern for data management:
// CRUD operations example
const taskManager = {
// Create
createTask(title, description) {
const task = { id: Date.now(), title, description, completed: false };
tasks.push(task);
return task;
},
// Read
getAllTasks() {
return tasks;
},
getTaskById(id) {
return tasks.find(task => task.id === id);
},
// Update
updateTask(id, updates) {
const taskIndex = tasks.findIndex(task => task.id === id);
if (taskIndex !== -1) {
tasks[taskIndex] = { ...tasks[taskIndex], ...updates };
return tasks[taskIndex];
}
return null;
},
// Delete
deleteTask(id) {
const taskIndex = tasks.findIndex(task => task.id === id);
if (taskIndex !== -1) {
const deletedTask = tasks[taskIndex];
tasks.splice(taskIndex, 1);
return deletedTask;
}
return null;
}
};
When to use with AI: When building applications that manage data, like task managers, contact lists, or inventory systems.
MVC Pattern
MVC (Model-View-Controller) separates application concerns:
- Model: Data and business logic
- View: User interface
- Controller: Handles user input and updates model/view
// Simplified MVC example
// Model
class TaskModel {
constructor() {
this.tasks = [];
}
addTask(task) {
this.tasks.push(task);
}
getTasks() {
return this.tasks;
}
}
// View
class TaskView {
displayTasks(tasks) {
const taskList = document.getElementById("taskList");
taskList.innerHTML = "";
tasks.forEach(task => {
const li = document.createElement("li");
li.textContent = task;
taskList.appendChild(li);
});
}
}
// Controller
class TaskController {
constructor(model, view) {
this.model = model;
this.view = view;
// Initial render
this.updateView();
}
addTask(task) {
this.model.addTask(task);
this.updateView();
}
updateView() {
this.view.displayTasks(this.model.getTasks());
}
}
// Usage
const app = new TaskController(new TaskModel(), new TaskView());
document.getElementById("addButton").addEventListener("click", function() {
const taskInput = document.getElementById("taskInput");
app.addTask(taskInput.value);
taskInput.value = "";
});
When to use with AI: When building larger applications that benefit from clear separation of concerns.
Understanding Code Structure and Syntax
Variables and Scope
Understanding variable scope is crucial for avoiding bugs:
// Global scope
const globalVar = "I'm global";
function exampleFunction() {
// Function scope
const functionVar = "I'm function-scoped";
if (true) {
// Block scope (let/const)
let blockVar = "I'm block-scoped";
var functionScopedVar = "I'm function-scoped despite being in a block";
}
console.log(functionVar); // Works
console.log(functionScopedVar); // Works
console.log(blockVar); // Error: blockVar is not defined
}
console.log(globalVar); // Works
console.log(functionVar); // Error: functionVar is not defined
When to use with AI: When discussing variable accessibility and lifetime in your application.
Asynchronous Programming
Understanding asynchronous code is essential for modern web development:
// Callbacks
function fetchDataWithCallback(callback) {
setTimeout(() => {
const data = { name: "John", age: 30 };
callback(data);
}, 1000);
}
fetchDataWithCallback(function(data) {
console.log(data);
});
// Promises
function fetchDataWithPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = { name: "John", age: 30 };
resolve(data);
}, 1000);
});
}
fetchDataWithPromise()
.then(data => console.log(data))
.catch(error => console.error(error));
// Async/await
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchData();
When to use with AI: When building applications that involve network requests, timers, or other operations that don't complete immediately.
Error Handling
Proper error handling improves application reliability:
// Try/catch for synchronous code
function divide(a, b) {
try {
if (b === 0) {
throw new Error("Cannot divide by zero");
}
return a / b;
} catch (error) {
console.error("An error occurred:", error.message);
return null;
}
}
// Error handling in asynchronous code
async function fetchUserData(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("Could not fetch user data:", error.message);
// Handle specific errors
if (error.message.includes("404")) {
alert("User not found");
} else {
alert("An error occurred while fetching user data");
}
return null;
}
}
When to use with AI: When building robust applications that need to handle unexpected situations gracefully.
Common Programming Patterns in Different Languages
Understanding how patterns translate across languages helps you adapt AI-generated code:
JavaScript vs. Python Example
JavaScript:
// Array manipulation in JavaScript
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(num => num * 2);
const sum = numbers.reduce((total, num) => total + num, 0);
const evens = numbers.filter(num => num % 2 === 0);
Python:
# Array manipulation in Python
numbers = [1, 2, 3, 4, 5]
doubled = [num * 2 for num in numbers]
sum_value = sum(numbers)
evens = [num for num in numbers if num % 2 == 0]
When to use with AI: When you need to adapt code from one language to another, or when you're more comfortable with a specific language.
Practical Application: Reading and Understanding Code
Being able to read and understand code is crucial for vibe coding. Here's a step-by-step approach:
1. Identify the Overall Purpose
Look at file names, comments, and function names to understand what the code is supposed to do.
2. Break Down the Structure
Identify major components:
- Functions and their purposes
- Data structures and what they store
- Control flow (conditionals, loops)
3. Follow the Data Flow
Trace how data moves through the application:
- Where does data come from? (user input, API, etc.)
- How is it processed?
- Where does it end up? (display, storage, etc.)
4. Understand the Control Flow
Follow the execution path:
- What happens when the application starts?
- What triggers different functions?
- How do different parts interact?
5. Look for Patterns
Recognize common programming patterns:
- Event handling
- Data manipulation
- API interactions