Episode 3 — NodeJS MongoDB Backend Architecture / 3.3 — Backend Architectures
3.3 — Exercise Questions: Backend Architectures
Practice questions covering software architecture fundamentals, MVC, Service layers, SOA, microservices, event-driven, and serverless patterns. Work through these to solidify your understanding before moving on.
Section A: Architecture Fundamentals (Questions 1-8)
Question 1: Architecture vs. Design
Explain the difference between software architecture and software design. Give one example of each for a social media application.
Question 2: Separation of Concerns
A teammate writes this single Express route handler. Identify all the concerns mixed together and list which layer each belongs to.
app.post('/api/orders', async (req, res) => {
if (!req.body.items || req.body.items.length === 0) {
return res.status(400).json({ error: 'Items required' });
}
let total = 0;
for (const item of req.body.items) {
const product = await db.collection('products').findOne({ _id: item.id });
total += product.price * item.qty;
}
if (total > 100) total = total * 0.9;
await db.collection('orders').insertOne({
userId: req.user.id,
items: req.body.items,
total,
createdAt: new Date()
});
await transporter.sendMail({
to: req.user.email,
subject: 'Order Confirmed',
text: `Your total is $${total}`
});
res.status(201).json({ message: 'Order created', total });
});
Question 3: Why Architecture Matters
List four ways that poor architecture negatively affects a growing development team. Be specific.
Question 4: Monolith Advantages
Give three situations where a monolithic architecture is the correct choice. Explain why for each.
Question 5: Architecture Documentation
You are starting a new project with 3 developers. Write a short Architecture Decision Record (ADR) explaining why you chose MVC with a Service layer over a microservices approach.
Question 6: Scalability Impact
Explain, with a concrete example, how separating your code into layers (Routes, Controllers, Services, Models) makes it easier to add caching to your application without rewriting existing code.
Question 7: The Architecture Spectrum
Place these five architectures in order from simplest to most complex: Serverless, Monolith, Microservices, Modular Monolith, SOA. Briefly justify the ordering.
Question 8: Team Structure Impact
A company has 4 teams of 5 developers each. Explain why a modular monolith organized by feature (users module, orders module, products module, payments module) might be better than a microservices architecture for this team.
Section B: MVC Architecture (Questions 9-18)
Question 9: MVC Components
Fill in this table with what each MVC component is responsible for and what it should NOT do:
| Component | Responsible For | Should NOT Do |
|---|---|---|
| Model | ? | ? |
| View | ? | ? |
| Controller | ? | ? |
Question 10: Identify the Layer
For each line of code, identify which MVC layer it belongs in (Model, View/Response, Controller, or Service):
a) const hashedPassword = await bcrypt.hash(password, 12);
b) res.status(201).json({ status: 'success', data: user });
c) const { name, email } = req.body;
d) if (user.subscription === 'premium') discount = 0.2;
e) userSchema.pre('save', function() { ... });
f) router.get('/users/:id', userController.getUser);
g) await sendWelcomeEmail(user.email);
h) const user = await User.findById(id).populate('orders');
Question 11: Request Flow
Draw (using ASCII art or describe step-by-step) the complete flow when a client sends POST /api/products with a JSON body to create a new product. Include every layer the request passes through.
Question 12: Fat Controller Refactor
Refactor this fat controller into proper MVC layers. Write the code for the Model method, the Service function, and the thin Controller.
exports.registerUser = async (req, res) => {
const { name, email, password, role } = req.body;
if (password.length < 8) {
return res.status(400).json({ error: 'Password too short' });
}
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(400).json({ error: 'Email taken' });
}
const salt = await bcrypt.genSalt(12);
const hashedPassword = await bcrypt.hash(password, salt);
const user = await User.create({
name,
email,
password: hashedPassword,
role: role === 'admin' ? 'user' : role // prevent self-admin
});
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, {
expiresIn: '7d'
});
await transporter.sendMail({
to: email,
subject: 'Welcome!',
text: `Hi ${name}, welcome to our app!`
});
res.status(201).json({ user, token });
};
Question 13: Folder Structure
Create a complete folder structure for an Express MVC project that has three resources: Users, Products, and Orders. Include routes, controllers, services, models, middlewares, and config directories.
Question 14: Model Responsibilities
Write a Mongoose model for a BlogPost with the following requirements:
- Title (required, max 200 chars)
- Content (required)
- Author (reference to User model)
- Tags (array of strings)
- Status (enum: draft, published, archived)
- A pre-save hook that generates a URL-friendly slug from the title
- A method that checks if the post is editable (only drafts can be edited)
Question 15: Controller Error Handling
What is wrong with this controller's error handling? Rewrite it using the next(error) pattern with a global error handler.
exports.getProduct = async (req, res) => {
try {
const product = await Product.findById(req.params.id);
if (!product) {
return res.status(404).json({ error: 'Not found' });
}
res.json(product);
} catch (error) {
console.log(error);
res.status(500).json({ error: 'Server error' });
}
};
Question 16: Testing Layers
Explain how you would test the following without connecting to a real database:
- A Mongoose model's validation rules
- A service function that calls the model
- A controller function that calls the service
For each, describe what you would mock and what you would assert.
Question 17: MVC Drawbacks
List three drawbacks of using MVC for a very small project (e.g., a single-page API with 2 endpoints). Is there a simpler alternative?
Question 18: Separation of Concerns Violation
This code has Model logic leaking into the Controller. Identify the violations and explain where each piece of logic should live.
exports.updateUserRole = async (req, res) => {
const user = await User.findById(req.params.id);
// Business rule: only superadmins can promote to admin
if (req.body.role === 'admin' && req.user.role !== 'superadmin') {
return res.status(403).json({ error: 'Only superadmins can promote' });
}
// Business rule: cannot demote yourself
if (req.user.id === req.params.id && req.body.role !== user.role) {
return res.status(400).json({ error: 'Cannot change your own role' });
}
user.role = req.body.role;
user.updatedBy = req.user.id;
await user.save();
res.json(user);
};
Section C: MVC with REST APIs (Questions 19-25)
Question 19: View in REST APIs
Explain why we say the "View" in a REST API is the JSON response. What is the equivalent of "rendering a template" when building an API?
Question 20: Response Format Design
Design a consistent JSON response format for the following scenarios:
- Successfully fetching a list of 25 products (page 2 of 5)
- Successfully creating a new user
- Validation error when creating a user (missing email and short password)
- Server error (database connection failed)
Question 21: Service Layer Justification
A colleague argues that the Service layer is unnecessary overhead: "Why not just put the logic in the Controller or the Model?" Give three concrete reasons why the Service layer is worth the extra files.
Question 22: CRUD Implementation
Write the complete code (Route, Controller, Service, Model) for a DELETE /api/comments/:id endpoint that:
- Requires authentication
- Only the comment author or an admin can delete
- Uses soft delete (sets
isDeleted: true) - Returns 204 on success
Question 23: Error Bubbling
Trace how an error flows through the layers when a user tries to create a product with a negative price. Start from the Controller, go through the Service and Model, and show how it reaches the global error handler.
Question 24: Thin Controller Test
This controller is "thin." Write a unit test for it by mocking the productService.
exports.getProducts = async (req, res, next) => {
try {
const result = await productService.getProducts(req.query);
res.status(200).json({
status: 'success',
results: result.products.length,
data: { products: result.products }
});
} catch (error) {
next(error);
}
};
Question 25: Custom AppError
Write a custom AppError class that:
- Extends the built-in
Errorclass - Accepts a
messageandstatusCode - Sets
statusto'fail'for 4xx codes and'error'for 5xx codes - Sets
isOperationaltotrue(to distinguish from programming errors) - Captures the stack trace properly
Then show how you would use it in a service function.
Section D: SOA and Other Architectures (Questions 26-33)
Question 26: SOA vs. Microservices
What are the three key differences between SOA and microservices? Why did microservices evolve from SOA?
Question 27: Inter-Service Communication
You have a User Service and an Order Service. When a new order is placed, the Order Service needs the user's shipping address. Compare two approaches:
- Synchronous: Order Service makes an HTTP GET to User Service
- Asynchronous: Order Service has a cached copy of shipping addresses, updated via events
List the pros and cons of each.
Question 28: Event-Driven Design
Design an event-driven system for the following scenario: When a user signs up, the system must:
- Send a welcome email
- Create a default profile
- Grant 100 bonus points
- Log the signup for analytics
Write the event name, the producer, and the four consumers. Show the code structure (no full implementation needed).
Question 29: Serverless Trade-offs
A team wants to migrate their entire Express REST API (12 endpoints, always-on traffic) to AWS Lambda. List three reasons this might be a bad idea and two cases where serverless would be a better fit.
Question 30: Distributed Monolith
What is a "distributed monolith"? Why is it considered worse than both a regular monolith and proper microservices? Give a specific example of how this happens.
Question 31: Extraction Strategy
You have a monolith with these modules: Users, Products, Orders, Search, Notifications. The Search module receives 5x more traffic than everything else and uses Elasticsearch. Which module would you extract first into its own service? Justify your answer with at least three reasons.
Question 32: Architecture Matching
Match each project description to the most appropriate architecture:
| Project | Options: Monolith, MVC+Service, Microservices, Event-Driven, Serverless |
|---|---|
| A personal blog with 5 pages | ? |
| An image thumbnail generator triggered by file uploads | ? |
| A banking platform with 200 developers | ? |
| A real-time chat application | ? |
| A startup MVP with 3 developers | ? |
| An IoT sensor data pipeline processing millions of events/day | ? |
Question 33: Modular Monolith Structure
Design a folder structure for a modular monolith e-commerce application with these modules: Users, Products, Orders, Payments, and Shipping. Each module should have its own routes, controllers, services, and models. Show how modules communicate through defined interfaces rather than directly importing each other's internals.
Bonus Section: Coding Challenges (Questions 34-37)
Question 34: Build an Event Bus
Write a simple in-memory event bus class in Node.js that supports:
on(event, callback)- register a listeneremit(event, data)- fire an eventoff(event, callback)- remove a listeneronce(event, callback)- listener that auto-removes after one call
Write tests for each method.
Question 35: API Gateway Simulation
Build a simple API gateway using Express that:
- Accepts all requests on port 3000
- Routes
/api/users/*requests tohttp://localhost:3001 - Routes
/api/products/*requests tohttp://localhost:3002 - Adds a
X-Request-IDheader to all proxied requests - Logs every request with timestamp and target service
Question 36: Complete MVC Feature
Build a complete "bookmark" feature for a reading app using MVC with Service layer:
- Users can bookmark articles
- Users can list their bookmarks (paginated)
- Users can remove a bookmark
- A user cannot bookmark the same article twice
Write: Model, Service, Controller, Routes, and at least 3 test cases.
Question 37: Architecture Comparison Essay
Write a 300-word comparison of how these three companies might architect the same feature (user authentication):
- A solo developer building an MVP
- A 20-person startup
- A company with 500 engineers
Cover: where the auth code lives, how it deploys, how it scales, and what happens when it needs to change.
Answer Key Guidance
For each question, check your answer against these criteria:
| Criterion | Check |
|---|---|
| Correct layer assignment | Does each piece of code live in the right layer? |
| Separation of concerns | Does each layer have exactly one responsibility? |
| Testability | Can each layer be tested independently? |
| No HTTP in services/models | Do services and models avoid req, res, next? |
| Error propagation | Do errors bubble up to a centralized handler? |
| Practical trade-offs | Do you acknowledge both pros and cons of each approach? |