New Story

Test Driven Development and Rails Era Best Practices Could Improve AI Generated Code

by StackWildApril 8th, 2025
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

TDD, where tests are written before any actual implementation code, and other coding practices (DRY, law of demeter, etc) could offer the structure and discipline that AI agents need to make better decisions during development.
featured image - Test Driven Development and Rails Era Best Practices Could Improve AI Generated Code
StackWild HackerNoon profile picture
0-item

AI agents for code generation have gained popularity and attention over the last few months. Large language models (LLMs) can churn out a lot of simple code, but they’re often not very good at managing complexity or making careful, coordinated changes across a large codebase. As we move toward improving the effectiveness of AI agents in coding, I think there’s a strong case to be made for bringing back something that was very popular in the Ruby community in the early 2010s: Test-Driven Development (TDD).


TDD, where tests are written before any actual implementation code, could offer the structure and discipline that AI agents need to make better decisions during development. When you define the tests first, you're essentially guiding the AI agent to think in terms of input/output and side effects before diving into the actual implementation.


This makes sure that the AI focuses on modularity and testability, which can prevent the unstructured code generation that often leads to issues down the line. By breaking the problem into testable units, the agent can implement each layer of functionality in isolation, reducing the risk of errors and making debugging easier.


A great book from the 2000s, "Working Effectively with Legacy Code," described legacy code as "any code without tests." I think this definition is going to become even more relevant with AI-generated code. Without tests, AI agents are more likely to produce tightly coupled, untestable code, which becomes harder for both humans and AI to maintain.


But if we enforce TDD principles, whether through context in the prompt or cursor rules that require the AI to follow a certain order (e.g., write tests first, then functions), we can move toward a future where AI-generated code is far more reliable and maintainable.

The Law of Demeter and AI Agents

Another programming principle that could make a huge difference in guiding AI agents is the Law of Demeter, which was widely emphasized in object-oriented design during the Ruby era. The Law of Demeter dictates that objects should only communicate with their immediate neighbors rather than drilling through layers of objects to access data.


For example, instead of writing code like user.settings.priceSettings.timeZone, you should aim for user.timeZone or settings.timeZone, which keeps the interaction between objects simple and localized.


Following this principle will have a few impacts on AI agents. When a single function invocation involves a long chain of objects, this will require the context to include additional files for each object. Additionally, any changes to an object’s structure then spreads out and requires changes everywhere it was used, which will be many files if the code often “reaches through” one object to another to directly invoke functions or access attributes.


When code respects the Law of Demeter, it's more modular and loosely coupled, which means fewer places for things to break. If an AI agent generates code that respects these boundaries, the code will be far easier to maintain, debug, and extend. This is especially important because AI agents are not yet adept at debugging complex issues, and the simpler the relationships between objects, the easier it is to isolate problems.

Bringing Back Ruby's Influence

In the early 2010s, a book called Practical Object-Oriented Design in Ruby (POODR) had a significant influence on how developers thought about writing clean, modular code. The book laid out principles like DRY (Don't Repeat Yourself) and emphasized keeping functions small, readable, and focused. These principles are not only great for human developers but could also significantly benefit AI agents. Small, well-defined functions allow the AI to understand the code at the necessary layer of abstraction to make meaningful changes.


Rubyists were also big on using domain-specific languages (DSLs), where code reads almost like plain English, and this level of readability is exactly what AI needs to "understand" the intent behind the code. With clear, descriptive methods and classes, there’s less ambiguity, and the AI can make smarter decisions about how to extend or refactor code.

A Ruby Example

class User
  attr_reader :settings

  def initialize(settings)
    @settings = settings
  end

  def time_zone
    settings.time_zone
  end
end

class Settings
  attr_reader :time_zone

  def initialize(time_zone)
    @time_zone = time_zone
  end
end

settings = Settings.new('UTC')
user = User.new(settings)

puts user.time_zone  # Output: 'UTC'


In this example, the Law of Demeter is respected because consumers of the User class don’t need to know about the entire chain of objects (user.settings.timeZone), but rather accesses the time_zone property directly on the user.timeZone. This may seem insignificant, but it means any code that uses the user.timeZone will not be affected if the settings object or however the user chooses to implement its timeZone changes.


It also means any code prompts touching the user.timeZone won’t need any sense of what is going on in the setting object which means more room in the context for meaningful information. When this convention is followed across an entire code base, the consequences are very noticeable in terms of modularity and ease of editing code.

Looking Forward

As AI agents continue to develop, I expect we’ll start seeing a resurgence of these programming styles that enforce modularity and testability. TDD and principles like the Law of Demeter can help AI agents navigate the complexity of large codebases by guiding them to make better design decisions. With TDD, AI can work in steps, focusing on writing tests first to ensure that each piece of code is isolated and functional before moving on to the next. When paired with readable, modular code, these agents might finally start making more significant code changes that are both reliable and maintainable.

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks