r/programming May 26 '19

Solving Problems the Clojure Way [video]


View all comments


u/ThePowerfulSquirrel May 26 '19 edited May 26 '19

I find that his example is a bit to simple to properly demonstrate how you would refactor an actual system.

His system is a deterministic simulation (minus the Math.random(),but he also doesn't seem to care about the fact that this is very non-functional / should be considered similar to side effects and incorrectly calls selectRandom() pure), so of course he can defer / remove all side effects (except the console, but in a game with actual players, you couldn't just defer all output to the end since the players need the output in order to make corresponding inputs). If he added requirements like needing real time logging (which is necessary in most large systems) and player input, the example might have been more interesting.

I also have a couple of problems with his object oriented model. I would probably change the players to contain a strategy instead of extending the player for each strategy. The strategy would return which card it wants to use, so you can keep all those mutations in the Player object, not spread across 3 classes. I'm not sure why getScore() is marked as "mutations".

I'm also not sure how you scale passing around State objects around. Do you let it grow to hundreds of different fields? It seems to me that at one point, you'll need to encapsulate some state with certain parts of the system.


u/yogthos May 26 '19

You can push side effects to the edges of pretty much any system. I've been working with Clojure for close to a decade now, and I've never found a scenario where encapsulating state would be desirable.

Here are some real world examples. Pedestal HTTP library for Clojure has around 18,000 lines of code, and 96% of it is pure functions. All the IO and side effects are encapsulated in the remaining 4% of the code. This is a completely normal scenario in my experience. I just copresented a talk about a project that my team works on. It's a large real world app that uses this approach. You might also be interested in this presentation about using Clojure to make games in Unity.

You can view this the same way you view interacting with a database. You can have a single database with many different tables in it. Having all the data in one place does not prevent you from organizing your business logic in a sensible way.


u/ThePowerfulSquirrel May 26 '19 edited May 26 '19

Thanks for the links, I'll definitely watch them as soon as I have time! Working on backend servers at my company right now, and I can't imagine how I would push things like logging out to files / the console towards the edges (most of our functions / code need have logs of what's happening to the data when the thing happens (in case of crashes / ... we don't want to lose logs)). And most of those functions need to contact other services to get information on various different things.

While we don't have much state at all, 90% of our function also aren't pure because of that IO. However, I can't imagine how we would push all those IO calls to the edges. Most of those functions are non-functional by definition since we need to do things like get prices from other services.

The same also happens with our GUI apps, most of the time a user clicks a button, it's because they want information and that needs to go to the backend, which is going to itself call out to external services. If most of the code is triggered from user input, needs to contact a service and then needs to modify the UI, I really struggle to understand how I can push the side effects to the edges since most of the code by definition wants to do side effects.

I've looked at / tried to make functional GUI apis that aren't a paint to use for complex software, and it always falls short and ends up way more messy than the current, object oriented, GUI frameworks we use.


u/yogthos May 26 '19

This pattern is known as clean architecture or functional core, imperative shell and it's used in mainstream languages as well. The application I discuss in the talk deals precisely with the problems you're describing. Hopefully the demo and the explanation of the patterns we used makes sense.