DEV Community

Cover image for The Art of Writing Ugly Code That Works, Then Beautifying It for Optimal Functionality
Fernando González Tostado
Fernando González Tostado

Posted on

The Art of Writing Ugly Code That Works, Then Beautifying It for Optimal Functionality

Introduction:

When I was starting my career as a developer I usually wrote ugly code — I didn't know it was ugly at the time, but it was. I was so focused on getting the job and I didn't take the time —or even know how- to make my code readable, maintainable, and scalable. As a result, I spent a lot of time debugging and fixing bugs. I also had a hard time explaining my code to other developers. This was a frustrating experience that I didn't want to repeat.

Once I started learning about software development best practices such as the SOLID principles, Atomic Design, abstraction and design patterns my first instinct when writing any piece of new code was to write beautiful code from the very beginning. I wanted to make sure that my code was readable, maintainable, and scalable. However, I quickly realized that this approach was not only time-consuming but also led to frustration. I was spending too much time trying to make my code look perfect, and not enough time focusing on getting the job done. This got worse when I started working on larger projects with more complex code and TypeScript, where typing can be a bit tedious for reusable components.

So I thought, what if I start writing ugly code that initially works and then refactor it to make it more readable, maintainable, and scalable?

"Write Ugly Code That Works": The Benefits

Many software developers make the mistake of trying to write perfect code from the start. However, this approach can be time-consuming and often leads to frustration. By writing ugly code that works, you can focus on getting the job done quickly and efficiently. This allows you to test your ideas and make changes quickly without having to worry about making your code look perfect.

Some of the benefits of writing ugly code that works include:

  • Faster time to market
  • Increased productivity
  • Reduced frustration
  • More time to focus on testing and debugging

Here's a simple example of a form that works, but is ugly:

Why it is ugly?

  • If the elements inside it are not reusable.
  • If the form grows larger and more complex, it will be difficult to maintain and read.
  • We'd have to copy all the tailwind classes to each element that you'd want to use elsewhere.
// an ugly form
import React from "react";

const UglyForm = () => {
  const [value, setValue] = React.useState("");

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setValue(e.target.value);
  };

  return (
    <form>
      <input type="text p-4 border border-gray-400 rounded w-64" value={value} onChange={handleChange} />
      <button type="submit p-4 bg-blue-500 text-white rounded hover:bg-blue-600">Submit</button>
    </form>
  );
};

export default UglyForm;
Enter fullscreen mode Exit fullscreen mode

Our first instinct as a seasoned would be to start writing first the reusable components and then the form. But that would bring us the problems earlier mentioned. That's why we wrote ugly code first!

So this is just half of the process, now that it works, we can start beautifying it.

"Beautifying Your Code for Optimal Functionality"

Once your ugly code works, it's time to start beautifying it. This process involves making your code more readable, maintainable, and scalable. By doing this, you can ensure that your code is optimized for performance and efficiency. Some of the steps you can take to beautify your code include:

  • Refactoring your code to make it more readable and understandable
  • Adding comments to explain complex parts of your code
  • Using descriptive variable names
  • Implementing design patterns to make your code more maintainable
  • Cleaning up unused or redundant code
import React from "react";

interface Props {
  handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
  value: string;
}

// src/components/atoms/Input.tsx
export const Input: React.FC<Props> = ({ handleChange, value }) => {
  return (
    <input
      className="p-4 border border-gray-400 rounded w-64"
      type="text"
      value={value}
      onChange={handleChange}
    />
  );
};

// src/components/atoms/Button.tsx
const Button: React.FC = () => {
  return (
    <button
      className="p-4 bg-blue-500 text-white rounded hover:bg-blue-600"
      type="submit"
    >
      Submit
    </button>
  );
};

// src/components/molecules/Form.tsx
const Form: React.FC = () => {
  const [value, setValue] = React.useState("");

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setValue(e.target.value);
  };

  return (
    <form className="p-10">
      <Input handleChange={handleChange} value={value} />
      <Button />
    </form>
  );
};

export default Form;
Enter fullscreen mode Exit fullscreen mode

We now have three reusable components that we can use in other parts of our application, we can easily modify them as needed as our application grows, they also comply with the Atomic Design principles and two of the SOLID principles:

  • Single responsibility principle: Each component has a single responsibility, the Input component is responsible for rendering an input element, the Button component is responsible for rendering a button element, and the Form component is responsible for rendering a form element.
  • Open/closed principle: Each component is open for extension but closed for modification. This means that we can easily extend the functionality of each component without having to modify the existing code.

Following this strategy we got rid of frustration, time-consuming bugs, and we can now focus on what's next, testing and debugging. So the next time you're working on a project, remember to write ugly code that works, then beautiful code that also works.

Conclusion:
In conclusion, writing ugly code that works, then beautiful code that also works is an effective approach for software developers. This approach saves time and results in cleaner, more efficient code in the long run. By focusing on functionality first, and then optimizing for readability and maintainability, you can ensure that your code is optimized for performance and efficiency. So the next time you're working on a project, remember to write ugly code that works, then beautiful code that also works.

Photo from Ralph (Ravi) Kayden at Unsplash

Top comments (0)