Photo by Joseph James : Charm of Prague

The Boy Scout Rule: Leaving Code Better Than You Found It

Joseph James (JJ)
4 min readJul 9, 2023

--

Introduction

Immerse yourself in the charm of Prague as we embark on a journey of software craftsmanship and code refinement. In this article, we’ll explore Boy Scout Rule from Robert C. Martin’s book “Clean Code” and uncover how this concept intertwine and inspire continuous improvement in our codebase. Together, we’ll unlock the artistry of software development, leaving a lasting legacy of refined craftsmanship in our projects.

What is Boy Scout Rule?

The Boy Scout Rule, also known as the “Leave No Trace” principle, is a concept introduced by Robert C. Martin in his book “Clean Code.” It draws inspiration from the Boy Scouts’ ethos of leaving a campsite cleaner than they found it. Applied to software development, the Boy Scout Rule encourages developers to leave the codebase in a better state than they found it by making small, incremental improvements whenever they work on it.

The essence of the Boy Scout Rule lies in taking responsibility for the code we encounter and actively seeking opportunities to improve it. It encourages developers to go beyond the immediate task at hand and address areas that can benefit from refactoring, optimization, or enhancing code readability. By making small improvements, such as renaming variables, extracting methods, or removing duplicated code, developers contribute to the overall cleanliness, maintainability, and quality of the codebase.

The Context of Legacy Code

As I delved into a legacy codebase during the hotfix, I encountered multiple tests that required database initialization. Each test duplicated the same set of database initialization code, resulting in verbosity and chances of errors if changes were required. Recognizing the opportunity to enhance the codebase and adhere to the Boy Scout Rule, I decided to streamline the process by encapsulating the database initialization within a custom test rule.

internal class SuperImportantDatabaseTest {

private lateinit var db: com.mypackage.database.Database
private lateinit var myDao: MyDao

@Before
fun setUp() {
val context = InstrumentationRegistry.getInstrumentation().context
db = Room.inMemoryDatabaseBuilder(context, com.mypackage.database.Database::class.java).build()
myDao = db.myDao()
}

@Test
fun `super critical test scenario`(){
// ...
}

// ...

@After
fun tearDown() {
db.close()
}
}

Implementation: Test Rule for Database Initialization

To address the redundancy in database initialization code, I leveraged a test rule — a powerful mechanism provided by testing frameworks — to encapsulate the common behavior across multiple tests. The custom test rule was responsible for setting up the database, loading test data, and cleaning up after each test execution.

inline fun <reified T : RoomDatabase> createDatabaseTestRule() = DatabaseTestRule(T::class)

class DatabaseTestRule<T : RoomDatabase>(private val databaseClass: KClass<T>) : TestWatcher() {
lateinit var db: T
private set

override fun starting(description: Description) {
super.starting(description)
val context = InstrumentationRegistry.getInstrumentation().context
db = Room.inMemoryDatabaseBuilder(context, databaseClass.java).build()
}

override fun finished(description: Description) {
db.clearAllTables()
db.close()
super.finished(description)
}
}

Utilizing the Test Rule

By utilizing the newly created test rule, the database initialization code within each test was reduced to a single line, improving test readability and reducing code duplication. Tests that required database initialization could easily utilize the test rule by annotating the respective test classes or methods.

internal class SuperImportantDatabaseTest {

@get:Rule
val databaseTestRule: DatabaseTestRule<com.mypackage.database.Database> = createDatabaseTestRule()

@Test
fun `super critical test scenario`(){
// usage: databaseTestRule.db
// ...
}

// ...
}

Benefits and Reusability

The introduction of the test rule brought several benefits to our test suite:

  1. Code Readability: The test rule reduced the database initialization code from multiple lines to a single line within each test. This improved code readability and made the tests more concise and focused.
  2. Code Maintainability: By centralizing the database initialization code within the test rule, any changes or improvements could be made in a single place. This ensured consistency across all tests that utilized the rule, reducing the chances of introducing inconsistencies or errors.
  3. Reusability: The test rule provided a reusable component that facilitated future test development. As new tests were added or existing tests modified, the rule ensured consistent and efficient database initialization.

Conclusion

The Boy Scout Rule reminds us to make incremental improvements to leave the codebase in a better state than we found it. During a hotfix, I applied the Boy Scout Rule and optimized the database initialization process within our test suite. By introducing a custom test rule, I reduced code duplication, improved test readability, and enhanced the maintainability of our test suite. Embracing the Boy Scout Rule not only solved an immediate problem but also contributed to a cleaner and more maintainable codebase. As developers, let us embrace this mindset and continuously strive to improve our codebase one small step at a time.

--

--

Joseph James (JJ)
Joseph James (JJ)

No responses yet