← Back to list

How to Write Clean & Maintainable Code (Without Losing Your Mind)

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”

Sourav Kumar Dash · 2025-06-19 16:15 · 2 claps · 5.6 min read
#clean-code #development #web-development #clean-code-principle #code-practices
Open on Medium ↗
Wiki topics: 🌐 · Web Development

How to Write Clean & Maintainable Code (Without Losing Your Mind)

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”

Martin Fowler

As developers, we’re not just building pretty buttons — we’re building systems that scale, that other devs can understand, and that future you won’t rage at during a late-night bug hunt.

So how do you write code that’s not only functional, but also clean, maintainable, and future-proof?

Let’s break it down, dev-to-dev, with real examples and zero fluff.

1. Clarity Over Cleverness

If someone (including you) can’t read your code and instantly get what’s going on, you’ve lost.

// ✅ Do this it's more clear
const totalPrice = price * quantity;
// 🚫 Not this it's confusing
const t = ip * q;

Be obvious. Be boring, even. That’s good coding.

2. Use Meaningful Names

Forget x, data1, and value123. Your variables and functions should tell a story.

// ✅ Clear
let userEmail = "hello@example.com";
// 🚫 What even is this?
let x = "hello@example.com";

If your code reads like a sentence, you’re doing it right.

3. One Thing, One Job (Single Responsibility)

Split your code into small, focused chunks that each do one job well. It makes debugging and reusing things way easier.

// ✅ A Button that only handles display and click
function Button({ label, onClick, type = "button", className = "" }) {
  return (
    <button type={type} onClick={onClick} className={`btn ${className}`}>
      {label}
    </button>
  );
}
// ✔️ Reusable
// ✔️ Customizable
// ✔️ Clean & testable

// 🚫 Hardcoding Styles Inline (Bad Reusability)
function SubmitButton({ onClick }) {
  return (
    <button 
      onClick={onClick} 
      style={{ backgroundColor: 'blue', color: 'white', padding: '10px' }}
    >
      Submit
    </button>
  );
}
// Inline styles are hard to override.
// Repetitive if multiple buttons need the same look.
// No separation of concerns.

// 🚫 Mixing Logic Inside the Component
function SubmitButton() {
  const handleClick = () => {
    // fetch, form validation, state updates, alert, everything...
    alert("Submitted!");
    // more side effects...
  };
  return <button onClick={handleClick}>Submit</button>;
}
// Makes the component tightly coupled to logic.
// Not reusable in other contexts.
// Harder to test.

// 🚫 Making It Inflexible (No Props)
function SubmitButton() {
  return <button>Submit</button>;
}
// You can’t change the label or add a handler.
// Not reusable outside a very narrow case.

// 🚫 Not Using Semantic HTML
function SubmitButton({ onClick }) {
  return <div onClick={onClick}>Submit</div>;
}
// Not accessible (keyboard users can’t "click" a div).
// Breaks browser expectations and screen reader behavior.

// 🚫 Anonymous Functions in JSX (if performance matters)
function SubmitButton() {
  return (
    <button onClick={() => console.log("Submitted")}>
      Submit
    </button>
  );
}
// Creates a new function on every render.
// Could cause unnecessary re-renders in optimized components.

Now you can use this button anywhere. That’s component reusability.

4. Format Like a Pro (Use Prettier)

Formatting isn’t just aesthetics — it’s clarity. Use tools like Prettier and ESLint to keep things consistent.

// ✅ Clean spacing and consistent style
function sayHello(name) {
  return `Hello, ${name}!`;
}

Inconsistent formatting = friction for your team. Automation helps.

5. DRY (Don’t Repeat Yourself)

Copy-pasting the same logic all over? Time to refactor.

// ✅ Good: Abstract it into a function
const TAX_RATE = 0.18;

function getTotalWithTax(price) {
  return price + price * TAX_RATE;
}

const item1Total = getTotalWithTax(item1.price);
const item2Total = getTotalWithTax(item2.price);

// 🚫 Bad: Repeating the same tax calculation
const item1Total = item1.price + item1.price * 0.18;
const item2Total = item2.price + item2.price * 0.18;

Repeated logic = repeated bugs. Keep it centralized.

6. Component Reusability

Build UI pieces once, use them everywhere. That’s the dream of component-based architecture — and React nails it.

// ✅ Reusable button
function Button({ label, onClick, className = "btn-primary" }) {
  return (
    <button className={className} onClick={onClick}>
      {label}
    </button>
  );
}

// Use it anywhere:
<Button label="Save" onClick={handleSave} />
<Button label="Cancel" onClick={handleCancel} className="btn-secondary" />

// 🚫 function SaveButton() {
  return <button className="btn-primary">Save</button>;
}

function CancelButton() {
  return <button className="btn-primary">Cancel</button>;
}

This is why we love component-driven frameworks like React.

7. Organize Files Like You Care

“A messy file tree is like a messy desk — you can still work, but you’ll lose time, sanity, and probably that one button component.”

Good folder structure saves time and headaches later.

🚫 What Not to Do

/src
  - Button.jsx
  - HomePage.jsx
  - utils.js
  - styles.css
  - index.jsx

✅ What to Do Instead

/src
  /components
    /Button
      - Button.jsx
      - Button.css
  /pages
    /Home
      - HomePage.jsx
      - HomePage.module.css
  /utils
    - formatDate.js
  /hooks
    - useAuth.js
  - App.jsx
  - index.js

Structure by feature or role — not just “stuff”.

8. Avoid Side Effects

Keep your functions pure unless absolutely necessary. Predictability wins.

// ✅ Pure function
function add(a, b) {
  return a + b;
}

// if we use it
add(2,3);  // total = 5
add(2,3);  // total = 5
// Now you can call it independently and expect the same result.
// It's independent on history
// Call it anytime, anywhere—it just works.

// 🚫 Impure Function (with side effects)
let total = 0;
function addToTotal(amount) {
  total += amount; // modifies external state (side effect)
}

// if we use it
addToTotal(5);  // total = 5
addToTotal(5);  // total = 10
// Now you can’t call it independently and expect the same result.
// It’s dependent on history, not just inputs.
// Even if the function looks small, it mutates something outside
// that's risky and non-reusable.

Pure functions are easier to test, debug, and trust.

9. Comment When Necessary (Not Always)

Your code should speak for itself. But if something needs a comment, write a good one.

// We use parseFloat here to handle blank inputs safely
const price = parseFloat(input.value) || 0;

Avoid obvious comments. Explain why, not what.

10. Handle Errors Gracefully

“Users shouldn’t see your bugs — and you shouldn’t cry while debugging.”

Always check inputs and be ready for things to go wrong.

// 🚫 No error check
function submitForm(data) {
  api.send(data); // What if this fails?
}

// 🚫 Crashing the app
const user = JSON.parse(badJson); // Throws error, app crashes

// ✅ What to Do Instead

// 1. Validate Inputs
if (!email) {
  showError("Email is required");
}

// 2. Use Try-Catch for Async/Unknowns
async function fetchUserData() {
  try {
    const res = await fetch("/api/user");
    if (!res.ok) throw new Error("Failed to fetch");
    const data = await res.json();
    return data;
  } catch (error) {
    console.error("Error fetching user:", error.message);
    showError("Could not load user. Please try again.");
  }
}

// 3. Use Optional Chaining
const username = user?.profile?.name ?? "Guest";
// Prevents: Cannot read property 'name' of undefined

Catching bugs early saves you later.

11. Make Code Testable

Clean code isn’t just easy to read — it’s easy to prove right.

Write functions and components that are easy to test. Avoid deeply nested logic.

// 🚫 Deeply nested logic in UI
function Checkout({ user, cart }) {
  if (user && cart.length > 0 && !user.isGuest) {
    const total = cart.reduce((acc, item) => acc + item.price, 0);
    const discount = user.vip ? total * 0.1 : 0;
    const final = total - discount;
    return <div>Total: ₹{final}</div>;
  }

  return <p>No items to show</p>;
}

// ✅ Do This Instead

// 1. Move logic into pure functions
function getDiscountedTotal(cart, isVip) {
  const total = cart.reduce((sum, item) => sum + item.price, 0);
  const discount = isVip ? total * 0.1 : 0;
  return total - discount;
}

// Now you can easily test this:
// ✅ Easy to write a unit test for
expect(getDiscountedTotal([{ price: 100 }], true)).toBe(90);

// 2. Keep components clean and dumb
function Checkout({ user, cart }) {
  const final = getDiscountedTotal(cart, user?.vip);

  return cart.length ? (
    <div>Total: ₹{final}</div>
  ) : (
    <p>No items to show</p>
  );
}
// The logic is testable independently
// The component is focused on rendering
// You don’t need 3 mock objects just to check a math operation

If you can’t test it, you probably don’t understand it fully yet.

Bonus Tools to Help You Stay Clean

  • Prettier — auto-format your code
  • ESLint — enforce coding rules
  • React Developer Tools — debug UI easily
  • Husky + lint-staged — stop bad commits
  • Jest + Testing Library — write useful tests

Final Words

Writing clean, maintainable code isn’t about being perfect — it’s about being thoughtful. Code is for humans first, machines second.

So, next time you open your editor, just ask: “Will future me thank me for this?” If yes — you’re already winning.

If this helped you write cleaner, more maintainable code, share it with a fellow dev and let’s level up the development world together!


메타데이터
post_id
30d64b5a8f8d
slug
how-to-write-clean-maintainable-code-without-losing-your-mind-30d64b5a8f8d
url
https://medium.com/@souravkumardash183/how-to-write-clean-maintainable-code-without-losing-your-mind-30d64b5a8f8d
canonical_url
https://medium.com/@souravkumardash183/how-to-write-clean-maintainable-code-without-losing-your-mind-30d64b5a8f8d
author_url
https://medium.com/@souravkumardash183
status
ok
fetched_at
2026-08-03 22:39:48