Imaginative Coding

James Johnson
Jul 16, 2019 · 4 min read
Image for post
Image for post
Image courtesy of Porapak Apichodilok on Pexels

Make your life easier by using imaginative coding to create clear function contracts, faster prototyping, and better architecture.

The first time I saw imaginative coding used was towards the start of my career when I was required to finish implementing code that a coworker had started. His code was a work-in-progress and non-functional. As I began reading his code, I continued to find references to functions that didn’t exist, often with comments above the function reference that described how the function should work. This was confusing to me at the time. It took me longer than it should have to realize that this was his method of programming, not that a file was missing from the source repository.

Eventually I adopted his coding style, something I think of as “imaginative coding”. I have since learned that imaginative coding helps

  • Encourage clear function contracts
  • Enable faster prototyping and iteration
  • Create better architecture

Clear Function Contracts

Functions with clear contracts are simple to create when you define their purpose before defining their implementation.

Consider a situation where we need to parse and interpret a predefined custom scripting language for an application we are developing. Where do you even start? I enjoy starting at an entry point to the new functionality, and ask myself “How do I imagine this being used?”

Akin to writer’s block, it helps if you simply start writing. Get something written down in your editor, and go from there.

In the code snippet above, I am imagining the scripting language interpretation being encapsulated as a stand-alone library, and a single function being called to run a script. At this stage, I need to think about a few things, some of which are listed below:

  • Who will be calling this?
  • What parameters do they need to provide?
  • How will errors be handled?
  • Without planning too far ahead, is there anything I am sure I will want for future expansion, or to make testing easier?

After considering the above questions , I decide that a Script structure or class should be used to hold information about the script, which should be passed into the RunScript method. Experience in writing similar code for custom interpreters tells me I may also want to require a ScriptContext object that describes the environment the script will be executed in (global variables, pre-loaded libraries, etc)

At this point, I am thinking it would make more sense to create a Run method on the Script structure that accepts the script context as a parameter, and to use the RunScript method for logging, output formatting, error handling, and other miscellaneous functionality. This also has me thinking: how do I handle the output of the script? Similarly, is there even a return value? What about script parameters? I decide to update the RunScript arguments to accept a []*ScriptParam array, and to leave the script output/return value question for later:

Notice how as I think through, and imagine how this will be used, that it is natural to create clear function contracts. I find it much easier to have clear function contracts and purpose when developing using this method, as opposed to developing a large monolithic function or script that I then have to refactor into more appropriate design patterns and architecture. To put it simply, functions with clear contracts are simple to create when you define their purpose before defining their implementation.

Fast prototyping and iteration

As obvious as it sounds, it’s easiest to iterate, rework, and refactor code when there is little or no code to work with

I usually take a step back when I have established a rough code flow to consider the direction the architecture is heading in. After some reflection, I realize I want to add the concept of an interpreter, and that Script structures are mostly informational and shouldn’t run themselves. I adjust the code accordingly:

Notice how the interpreter parameter is an interface — this makes it easier for multiple implementations of the scripting language interpreter to exist and be swapped out. I also decided I didn’t like the name ScriptContext and that it should be called a Scope instead. I then added the ScriptExecOpts parameter to the interpreter interface’s Execute function.

Now that I roughly have the execution structure(s) figured out, I would begin writing basic tests to start putting the stubbed-out code through its paces. These tests would later expand to test the fully implemented functions. Writing tests for the stubbed out code will further help me define how I want my code to be used, and will set me up nicely to use test driven development (TDD) while I finish the implementation.

As obvious as it sounds, it’s easiest to iterate, rework, and refactor code when there is little or no code to work with. The refactoring above only dealt with seven lines of code in the previous version of the RunScript method. Compared to large refactorings I’ve done in the past involving hundreds or thousands of lines of code, this is astoundingly easy.

Better Architecture

Better architecture arises when you are able to clearly define what needs to be done, and quickly iterate to “try out” various approaches as you consider how your code will be used and maintained now and in the future. As you gain experience, you will need fewer iterations before you settle on a satisfactory architecture.

GroDev

GroDev on Medium is a publication focusing on building…

James Johnson

Written by

Team builder/manager, software architect/developer, and security researcher with a unique skillset. Simply put, I make things and love efficiency.

GroDev

GroDev

GroDev on Medium is a publication focusing on building software development teams.

James Johnson

Written by

Team builder/manager, software architect/developer, and security researcher with a unique skillset. Simply put, I make things and love efficiency.

GroDev

GroDev

GroDev on Medium is a publication focusing on building software development teams.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store