7 Anti-pattern: interleaving computation and I/O

Interleaving computation and I/O at a fine-grained level throughout the code is an anti-pattern.

Consider two ways to write a parser:

  1. First read a file into memory, then the parser works on the memory buffer
  2. The parser uses I/O to read characters from an input stream as it goes.

The second involves the anti-pattern. It's bad because:

  • The code is less flexible, it can only be used on files
  • There are thousands of I/O calls littered through the code, each one can produce I/O errors
  • There are correspondingly thousands of error handling and hence test scenarios
  • Performance is MUCH worse
    • Tiny I/O calls typically perform very badly (depending on the OS they might even go into kernel mode every time because there is no user space buffering in the I/O library)
    • More instruction cache is needed
    • Simple memory accesses tend to be in-lined, I/O is not.

So less flexible, almost impossible to test thoroughly and performs badly.

Note that using async/await doesn't change any of this (indeed performance is even worse because async I/O has more overheads than synchronous I/O)

The anti-patterns location transparency and orthogonal persistence are aimed at making this anti-pattern "easier" by promoting the interleaving of computation and I/O by making it implicit. This is achieved in many software tools and libraries, such as Hibernate which aims to provide persistence transparency.