Pretty general question about the pipe or pipeline design pattern and how it relates to purity and testability.
The code is a case of a read-read-process pipe, that is, two reads from database/file that depend on each other, and both stop if they find null.
This is the code, taken from our real code-base:
function getAttributesFromTheme(string $themeName)
{
$theme = $this->getTheme($themeName);
if (empty($theme)) {
return null;
}
$xml = $this->getXmlFromTheme($theme);
if (empty($xml)) {
return null;
}
return $this->extractAttributes($xml);
}
function caller()
{
$attributes = $this->getAttributesFromTheme('mytheme');
}
function getAttributesFromTheme(string $themeName)
{
return Pipe::make(
$this->getTheme(...),
$this->getXmlFromTheme(...),
$this->extractAttributes(...)
)
->stopIfEmpty()
->from($themeName);
}
function caller()
{
$attributes = $this->getAttributesFromTheme('mytheme')->run();
}
The interesting thing to notice is that getAttributesFromTheme is a pure function in the second case, meaning it has no side-effects. It only decides how to organize effectful code without applying any of the effects itself.
On the other hand you now give more responsibility to the calling code caller, that has to:
- Know it gets a pipeline object
- Execute the pipeline with
run()