DALLE generated chalkedgoose programming logo

Elevating Your Software Development: Embracing Humility, Simplicity, and Purpose

Hurting Harold meme.

As a software engineer, you’re no stranger to the complex world of coding, but there are three fundamental principles that can make your work more effective and enjoyable: humility, simplicity, and purpose.

Embrace Humility: Accepting Our Limitations

Just as construction workers don protective gear to compensate for our physical vulnerabilities, software engineers must acknowledge their mental limitations. Our brains, like our bodies, are imperfect, so we must always strive to refine our code and be prepared for potential failure. Automation tools such as end-to-end, unit, and integration tests can help us verify our software, while implementing quality assurance tools like linting and code quality checks further safeguard our work. Human verification, though fallible, remains a valuable final check, offering insights machines may miss due to environmental or engineering constraints. Implementing strong standards and processes will ensure your projects remain reliable and secure.

Embrace Simplicity: Less Is More

Adding more code or tools isn’t always the answer. Instead, focus on whether each addition contributes value to your product. In his book “Code Complete” (2nd Edition), Steve McConnell cites several studies, indicating that the industry average for bugs ranges between 1 and 25 errors per 1,000 lines of code for delivered software, depending on the development techniques used. By reducing your codebase, you are likely to encounter fewer bugs. Opting for a language that requires less boilerplate can be one solution, though performance trade-offs should be carefully considered. Functional programming offers an alternative approach, emphasizing minimal boilerplate for concise, efficient code. Modern languages have also integrated functional programming concepts like immutable data structures and powerful iteration and pattern matching functionalities, further simplifying the coding process.

Embrace Purpose: Prioritizing Goals Over Code

Remember to focus on the purpose of your code rather than its inner workings. Engineers can become consumed by performance, refactoring, and endless debate, but it’s crucial to keep sight of what your code is designed to achieve. Is it meant for life support systems, communication with planes, or simply streaming a favorite show or facilitating social media interactions? By putting the objective front and center, you can create code that truly serves its intended purpose, whether it’s keeping someone safe or bringing joy to cat-loving, fixie-riding Ruby enthusiasts who enjoy weekend trips to Blue Bottle or Half Moon Bay.

Tread Carefully: Generative AI Tools as a Double-Edged Sword (Apr 2023)

The emergence of generative AI tools like GitHub Copilot and ChatGPT has undeniably revolutionized the software development landscape. When used responsibly, these tools can speed up the process of fleshing out boilerplate code and unblock developers by offering suggestions based on well-crafted prompts.

However, like wielding a sledgehammer, using AI tools comes with its own set of risks. It’s crucial to approach them with caution and mindfulness, as they can also generate significant bugs and vulnerabilities, expanding attack surfaces if misused. For instance, a developer might unintentionally generate vulnerable code in a React application or a Java Spring application using an ORM:

Example 1: React XSS Vulnerability

Generate code to render user input in a React component.

...
function VulnerableComponent() {
  const [userInput, setUserInput] = useState("");

  const handleChange = (e) => {
    setUserInput(e.target.value);
  };

  return (
    <div>
      <input type="text" onChange={handleChange} />
      /* Using dangerouslySetInnerHTML with unsanitized user input creates a
      potential XSS vulnerability. Malicious users can inject JavaScript code
      that gets executed when the HTML is rendered. */
      <p dangerouslySetInnerHTML={{ __html: userInput }}></p>
    </div>
  );
}

Example 2: Java Spring SQL Injection Vulnerability

Generate code to search for a user by their email address in a Java Spring application using an ORM.

@RestController
public class VulnerableController {

  @PersistenceContext
  private EntityManager entityManager;

  @GetMapping("/search")
  public List < User > searchUserByEmail(@RequestParam String email) {
    /*
     Concatenating user input directly into the query string exposes the
     application to SQL injection attacks. A malicious user can input
     an email containing SQL code that manipulates the query, allowing
     unauthorized access to sensitive data or compromising security.
     */
    String queryString = "SELECT u FROM User u WHERE u.email = '" + email + "'";
    Query query = entityManager.createQuery(queryString);
    return query.getResultList();
  }
}

To harness the power of generative AI effectively, developers must always conduct thorough human review and avoid relying solely on the AI-generated code.

Remember, AI tools are designed to support and augment your skills as a developer, not replace your expertise. By treating these tools like a precise instrument rather than a blunt force, you can minimize risks and maximize their potential in enhancing your software development process. Ultimately, the responsibility lies in the hands of developers to use AI technology wisely and ensure that the code generated aligns with the principles of humility, simplicity, and purpose that guide effective software engineering.

Made in 🇪🇸 without the S.