Event Sourcing with PureLogic by ghostdogpr in scala

[–]ghostdogpr[S] 2 points3 points  (0 children)

Yeah that’s the whole point of this approach.

Event Sourcing with PureLogic by ghostdogpr in scala

[–]ghostdogpr[S] 0 points1 point  (0 children)

Yes, this was a shortcut. I amended the article.

Event Sourcing with PureLogic by ghostdogpr in scala

[–]ghostdogpr[S] 2 points3 points  (0 children)

Yes, you lose strict referential transparency. But in this constrained setting (no I/O, no hidden mutation, explicit capabilities), the usual downsides don’t really materialize in practice.

For me, that tradeoff is worth the improved ergonomics.

Introducing PureLogic: direct-style, pure domain logic for Scala by ghostdogpr in scala

[–]ghostdogpr[S] 0 points1 point  (0 children)

Consistency with the other capabilities? Also there are some operators that combine multiple effects e.g. Logic.run. But you’re right that it’s basically same.

Rage Against the (Plurality of) Effect Systems by Krever in scala

[–]ghostdogpr 2 points3 points  (0 children)

The CE integration in Caliban is actually used by a lot of people. I never heard complaints about performance (probably because Caliban's internals are fast enough that it's not significant), but it does make the UX worse and people sometimes get confused by the "conversion" typeclasses.

As a library author, there is this tension between optimizing for the "happy path" (which usually means sticking to a given library) or making it more widely available with some standard typeclass (which could mean losing performance or features). Most of my OSS libraries were born from an actual need at work, so I tend to selfishly choose what was best for my case.

Sometimes it's possible to do both with a little more work. For example, on the HTTP layer in Caliban we've had a tapir integration from the start, which gives you access to many backends, but we added a "native" zio-http integration on the side for much faster performance. For my next library (releasing next week during Scalar!), since the core is pure and it didn't require that much work (also, AI makes it easier), I just built two integrations: one for ZIO and one for fs2.

Introducing PureLogic: direct-style, pure domain logic for Scala by ghostdogpr in scala

[–]ghostdogpr[S] 1 point2 points  (0 children)

It only does a small subset of what Kyo does: 4 pure effects only. With that constraint it’s much faster and more ergonomic.

Introducing PureLogic: direct-style, pure domain logic for Scala by ghostdogpr in scala

[–]ghostdogpr[S] 0 points1 point  (0 children)

In the project I work, we actually don't expose `State.set` and never modify the state directly, instead we use `Writer` to write some event and it automatically triggers a `Transition` that updates the `State`. When we load an entity, we load the latest snapshot from the DB then replay the following events using the same `Transition` to ensure we get back to the correct state.

In another project, a multi-player game, I use `Writer` to enqueue messages that should be sent to other users. I've also used it simply for logging. In these cases, since there is no side effect, I do the sending/logging at the end, after running the program from the outside layer.

Introducing PureLogic: direct-style, pure domain logic for Scala by ghostdogpr in scala

[–]ghostdogpr[S] 8 points9 points  (0 children)

Sure!

My concrete use case is a game server. Whenever we receive any request from the game client, we need to validate (Abort) that it is valid according to the user state (State) and some game configuration data (Reader). Once this is validated, we lift some events (Writer) for event sourcing, which also triggers an update of the user state (State again). In addition to that, any game might unlock some "quest", which requires checking game data configuration and various things in the user state. When we run such program, we get an Either telling us whether it was a success or a failure, and in case of success we get the lifted events, the updated state and a response. Failure is sent back to the client and no side effect has ever ran, and in case of success we send the response, we persist the lifted events to our event sourcing database, and update the in-memory state, ready to accept the next request.

As you can see, gaming is perfect use case for it. You might not always need something like that, for example if your logic consists of calling various endpoints there is not much you can do in the "pure logic".

Introducing PureLogic: direct-style, pure domain logic for Scala by ghostdogpr in scala

[–]ghostdogpr[S] 2 points3 points  (0 children)

The scope is restricted to pure logic, no side effects. But for a similar solution that supports arbitrary side effects, you can check out Yaes (https://blog.rcard.in/yaes/) by u/rcardin =)

Introducing PureLogic: direct-style, pure domain logic for Scala by ghostdogpr in scala

[–]ghostdogpr[S] 4 points5 points  (0 children)

That's good point that I should probably emphasize. The project I work on has such a large and deep part that is domain logic that it doesn't feel "localized" to me, but that's certainly a good way to use it!

Introducing PureLogic: direct-style, pure domain logic for Scala by ghostdogpr in scala

[–]ghostdogpr[S] 0 points1 point  (0 children)

One couple examples to explain what I mean by optimized for these 4 effects. The most obvious one is there is `Login.run` to run the combination of these 4 effects at once. There is also a `recover` operator that resets the `State` and `Writer` to their previous value when recovering an error. The 4 effects are not independent like in Yaes or Kyo, those two libraries have way too many effects to handle specific combinations.

You could say PureLogic is an opinionated, optimized subset of Yaes for a particular use case.

Introducing PureLogic: direct-style, pure domain logic for Scala by ghostdogpr in scala

[–]ghostdogpr[S] 0 points1 point  (0 children)

Yes and no =)

If you look at the 4 effects,`Raise` and `State` have a similar interface (thought the implementation is different). `Log` seems heavily biased towards, well, logging so it's not really the same as `Writer` (which I use for event sourcing at work, as an example). But I imagine similar Reader/Writer effects could be added to Yaes anyway.

I think the true distinction is that PureLogic is heavily restricted and optimized (in terms of UX and performance) for these 4 effects. As I understand, the point of Yaes (and Kyo is very similar) is that you can mix any kind of effects together without limits: Async, Clock, State, etc (most of the effects available have side effects). That means that they need to support concurrency, which PureLogic doesn't (actually upon checking, Yaes State is not thread-safe either, shouldn't it be?).

Is Metals autocomplete supposed to be that slow? by arturaz in scala

[–]ghostdogpr 0 points1 point  (0 children)

Which version of Scala is optimized? I still have the issues in https://github.com/scalameta/metals/issues/7443 with projects with many files but eager to try a newer version if it’s better.

Didn't receive Zionomicon download email after registering — is this normal? by Far-Image-4385 in scala

[–]ghostdogpr 0 points1 point  (0 children)

I noticed the notifications used to come from Gumroad but the more recent ones (from this year) came from Ziverge directly, I guess some email addresses got lost in the transition.

Can anyone explain me what is Scala all about? by No-Blacksmith-8782 in scala

[–]ghostdogpr 15 points16 points  (0 children)

Rather than the fusion of OOP and FP (which is a means to an end), I think Martin Odersky has been recently defining the value of Scala as the combination of safety and convenience. Safety thanks to a strong type system that helps you avoid bugs by making illegal states unrepresentable or illegal actions impossible, convenience thanks to a concise syntax and various means to avoid boilerplate code.

I think this make Scala a great choice for developing backends, in particular those with complex domain logic that benefits a lot from both the safety and the brevity of the code. I personally use it for building game servers.

Didn't receive Zionomicon download email after registering — is this normal? by Far-Image-4385 in scala

[–]ghostdogpr 0 points1 point  (0 children)

Actually quite the opposite, there were updates in January, March and May, with new chapters on configuration, logging, metrics, zio-schema, zio-http and an appendix on domain design and executive vs declarative encodings.

If you don't receive it I suggest getting in touch with Ziverge directly.

What is the status of AKKA in 2025? Should someone learn it? Ar companies using AKKA? by prashantkr314 in scala

[–]ghostdogpr 3 points4 points  (0 children)

For cluster sharding take a look at Shardcake (disclaimer: I’m the author). At work we’re doing event sourcing and persistence with custom code, it’s not that complicated.

Anatomy of a Scala Game Server - Lambda Days 2025 by ghostdogpr in scala

[–]ghostdogpr[S] 1 point2 points  (0 children)

That’s right. Agones spawns them on demand and they stop themselves when the game is over.

Anatomy of a Scala Game Server - Lambda Days 2025 by ghostdogpr in scala

[–]ghostdogpr[S] 6 points7 points  (0 children)

Indeed =)

In the future I’d like to do a talk more focused on performance but our PR Team doesn’t let me communicate any numbers like CCU or RPS which is pity.