Epic failure \/ success? Refactoring to *real* FP
specs2 has been around for 4 years now and while it tried to take the “functional route” (with immutability at least), it is actually largely using uncontrolled effects.
This talk will present a diagnosis of everything that is not “functional” in specs2, and will describe implemented or proposed solutions to remediate to this. Here’s a list of some problems:
- system properties are read directly
- the file system is accessed to get the state of previous runs and written to after execution
- some configuration is global (execution context for threads)
- text is freely emitted to the console via printlns
- an attempt at processing lazily the execution miserably failed (via Reducers)
- the code base is not easily extensible to create new reporters
The solutions (still being implemented/experimented) include:
- using a ReaderT / ErrorT / WriterT / IO stack to control effects. This actually opens very interesting possibilities in terms of flexibility for writing your specification! Question: how tedious is that to use in practice?
- using scalaz-stream to process results as they happen, even when running concurrently. This should remove some poorly performing code and simplify the code base. Question: does it work with specs2 execution model where it is possible to run only some sections of the specification concurrently, where a failed execution can stop the rest of the processing,…?
- using functions extensively instead of traits to compose functionality (who knew?). Traits will only be used to compose implicits for DSLs. Question: why not take the Cake Pattern route?
In conclusion we will talk about strategies for effectively migrating a non-functional code base to a functional one. What was learnt during this experiment?