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:
- First read a file into memory, then the parser works on the memory buffer
- 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.