Amblem
Furkan Baytekin

Single Responsibility & Advanatges in Compiled Languages

How SRP makes compiled languages more efficient and maintainable

Single Responsibility & Advanatges in Compiled Languages
114
5 minutes

When it comes to writing clean, maintainable code, few ideas shine as brightly as the Single Responsibility Principle (SRP). Part of the SOLID design principles, SRP states that a class or module should have only one reason to change, meaning it should stick to one job. This isn’t just a theoretical nicety; it’s a practical superpower, especially in backend development and even more so in compiled languages like Java or C++. Let’s break it down with a real-world example: user authentication in a web app.

The Tangled Mess: A UserService Gone Wild

Imagine you’re building a backend for a web application, and you need to authenticate users. Here’s a UserService class that tries to do it all:

javascript
class UserService { constructor() { this.database = new DatabaseConnection(); } authenticateUser(email, password) { // Validate input if (!email || !password) { throw new Error("Email and password are required"); } if (!email.includes("@")) { throw new Error("Invalid email format"); } // Query database const user = this.database.query("SELECT * FROM users WHERE email = ?", [email]); if (!user) { throw new Error("User not found"); } // Check password const isValid = bcrypt.compareSync(password, user.hashedPassword); if (!isValid) { throw new Error("Incorrect password"); } // Generate JWT token const token = jwt.sign({ id: user.id, email }, "secret_key", { expiresIn: "1h" }); return token; } }

This class is a jack-of-all-trades: it validates input, talks to the database, checks passwords, and generates JWT tokens. At first glance, it might seem efficient, everything’s in one place! But here’s the catch: it’s a maintenance nightmare. If the database schema changes, or you need a stricter email validation rule, or the JWT library gets swapped out, you’re editing this one class for entirely unrelated reasons. It’s a ticking time bomb for bugs and frustration.

Refactoring with SRP: One Job, One Class

Let’s apply SRP and split this into focused components. Here’s the refactored version:

javascript
class UserValidator { validateCredentials(email, password) { if (!email || !password) { throw new Error("Email and password are required"); } // Do not focus this, we are not going to implement this if (!email.includes("@")) { throw new Error("Invalid email format"); } } } class UserRepository { constructor(database) { this.database = database; } findUserByEmail(email) { const user = this.database.query("SELECT * FROM users WHERE email = ?", [email]); if (!user) { throw new Error("User not found"); } return user; } } class PasswordService { comparePassword(plainText, hashedPassword) { return bcrypt.compareSync(plainText, hashedPassword); } } class TokenService { generateJWT(userId, email) { return jwt.sign({ id: userId, email }, "secret_key", { expiresIn: "1h" }); } } class UserService { constructor(validator, repo, passwordService, tokenService) { this.validator = validator; this.repo = repo; this.passwordService = passwordService; this.tokenService = tokenService; } authenticateUser(email, password) { this.validator.validateCredentials(email, password); const user = this.repo.findUserByEmail(email); const isValid = this.passwordService.comparePassword(password, user.hashedPassword); if (!isValid) { throw new Error("Incorrect password"); } return this.tokenService.generateJWT(user.id, user.email); } }

Now each class has one job:

This is cleaner, but why does it matter so much more in compiled languages? Let’s dive into the advantages.

Why Compiled Languages Love SRP

In languages like Java, C++, or Rust, code gets compiled into machine code or bytecode before execution. SRP amplifies the benefits here in ways interpreted languages (like JavaScript or Python) don’t quite match. Here’s how:

  1. Selective Recompilation: Build Smarter, Not Harder
  1. Smaller Patches: Deploy Less, Stress Less
  1. Reduced Side Effects: Change with Confidence

Beyond Compilation: A Universal Win

Even outside the compiled world, SRP shines. That reduced risk of side effects? It’s a lifesaver everywhere. In the refactored version, if TokenService fails to generate a JWT, it won’t crash your database calls in UserRepository. Debugging becomes a breeze—you know exactly where to look. Plus, teams can work on separate components without stepping on each other’s toes.

The Takeaway

The Single Responsibility Principle isn’t just a buzzword—it’s a practical tool for building better software. In compiled languages, it turbocharges your workflow with faster builds and leaner deployments. In our UserService example, splitting duties means a change to password logic doesn’t force a full rebuild or risk breaking unrelated code. Whether you’re slinging Java bytecode or C++ binaries, SRP keeps your code focused, your builds efficient, and your sanity intact.

So next time you’re tempted to cram everything into one class, pause. Give each piece its own job. Your future self—and your compiler—will thank you.


Album of the day:

Suggested Blog Posts