3 ms·
It’s still heavily object orientated. My preferred approach to applications these days is immutable core / imperative shell and Java makes that awkward.
by pharmakom 4y ago
It’s still heavily object orientated. My preferred approach to applications these days is immutable core / imperative shell and Java makes that awkward.
- elric 4y agoCan you elaborate on the immutable core/imperative shell paradigm? Or maybe link me to some references? Sounds interesting! Thx :-)
- pharmakom 4y agoThere is a talk by that name that popularised it. https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell https://www.destroyallsoftware.com/screencasts/catalog/funct... Basically you have business domain objects that have value semantics and are immutable. You have functions that manipulate these objects. This makes the business domain unit-testable. Then on the edge of the application you have imperative code that manipulates databases, serves requests, etc. It’s like Haskell but as a design pattern rather than a language. In the JVM world, Scala and Clojure communities are adopting this approach.
- dgb23 4y agoThe sibling comment explains it well on a conceptual basis. I can maybe add a few notes since I'm in the process of gradually moving code to this architecture (for the lack of a better word). It is essentially straight forward to do. You look at a bunch of code in a module and determine which parts do these kinds of things: - data integrity, validation - parsing, transformation between formats - domain logic, decision making - algorithms and data structures This is your functional core. Note it doesn't matter too much if you have local mutations as long as they don't leak out. What you want to achieve is to have an interface where you can ask questions and you get the same answer for a particular question. This is certainly more productive if your language affords you with functional constructs, but its not strictly necessary to get the benefits. You code these parts in a way that they are data in, data out essentially. This leads to super easy and reliable unit/example tests and generative tests. And this part becomes very simple and easy to reason about. Secondly you have the part of your code that actually _does_ stuff, affecting your environment in some way. - basically any kind of I/O - cross cutting concerns between other side effecting modules and services (think DI and such) - error handling, error reporting and logging - caching, throttling, filtering etc. That's your imperative shell (I just call them modules). This part you write in an imperative/procedural style and you call the functional core parts from here, never the other way around. You coordinate effects so to speak. It is clear that you test these with integration tests, where you need to setup specific program state (or use mocks, but I try to avoid that) in order to find different code paths. This is harder to test properly but at the same time you also get to see everything that actually happens in condensed form. The degree to which you extract "pure" logic from your imperative shell is actually quite flexible. You can go as far as defining purely functional FSMs to extract much of the control for example. I think it really depends on code size and complexity as well as performance implications. The cool thing is that you can be quite pragmatic and iterative about it.
- qsort 4y agoBig fan of that approach as well, but there's no reason why you can't do it in Java. Records and streams are your friends. It's actually rather straightforward to start from a neat, functional pipeline and then do whatever at the edge. Of course you can't have the pure/impure distinction enforced, but nothing that isn't a purely functional language is going to give you that. The only really dumb limitation is that you can't have freestanding functions, but that's aesthetics more than substance.
- absove 4y agoThe latest additions to the standard library generally follow that approach: java.time, java.nio etc. But of course the older API are still fully mutable OO. A new collections API, immutable by default, is still needed and that's not happening any time soon.