The repository pattern is one of the most well established patterns in Domain Driven Design. It’s origins can be traced as early as when Object Oriented Programing was born. Of course, like it happens with almost every pattern or tool, you can really use it terribly the first time (or even the second, or the third one). The only way to improve upon that is good literature and seeing other, more appropriate, uses of the pattern/tool.
I used to be a big fan of filesystem abstractions, not only for the abstraction benefit, but also for the testing benefit as well. It is trivial to unit test classes depending in filesystem abstractions like Flysystem or Gaufrette: just a simple mock of the interface and we are done. However, from time to time I was kinda annoyed with some limitations of the abstractions, specially in regards to stream handling.
When it comes to reporting, I have a predefined set of rules that I follow sacredly and that will ensure that my report writing experience will be nice and problem-free.