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()