Holism: let's make it official?

As some of you may know, there’s a long-running discussion surrounding so-called holistic charming, as opposed to ‘charming with deltas’.

In a nutshell:

the Juju model is event-based, where each event notifies the charm of a single change in the juju model. Other parts of the state are accessible on a per-request basis by using hook tool calls. But the part of the juju model that has changed, that is what the event is about. If one writes charm logic only looking at the event at hand, we call that charming with deltas.

Sometimes it is easier to reason about charm logic if, instead of looking at the event the charm is being awakened by, we look at the ‘global’ state only. This is the holistic approach.

In reality, we typically use a combination of the two.

The problem

If you want to code holistically, that means having to fight with the Juju model in a number of ways. This has resulted in a sprawl of roll-your-own state-tracking solutions that, to use a common example, allow a charm to know whether a given relation is breaking, even outside of the context of the relation-broken hook that gave us that information in the first place.

The solution

A reductionist like me won’t be caught saying this in any other context than this, but sometimes the solution is a sprinkle of holism.


from charm.holism.v0.holism import Holism  # a charm lib for now?
holism = Holism()

class MyCharm(ops.CharmBase):
    ...  # your regular charm code  

    def some_method(self):
        relation = self.some_relation()
        unit = relation.units[0]  # some unit

        if holism.is_departing(relation, unit):             
            # your logic here

How it works

Holism keeps track in stored state of the ‘known’ state of all relations the charm has received events about.

Holism answers the question: “last I heard, is …”

  • … this relation alive?
  • … this unit joining that relation?
  • … this unit departing that relation?
  • … this relation being broken?

It doesn’t matter what event you’re processing, the relation data will be updated delta by delta, so you can focus on the big picture instead of keeping track of the deltas.

If the charm has received a foo-relation-created in the past (and, so far, no foo-relation-broken), Holism will “know” that foo exists and is alive. If the charm has received a foo-relation-joined in the past for unit remote/1 (and, so far, no foo-relation-departed for the same unit), Holism will “know” that remote/1 is joining foo.


Every event, Holism will clean itself up. For example, if Holism sees a foo-relation-broken, for the duration of that hook, Holism will believe that the relation exists but is in a breaking state:

holism.get_relation('foo').is_breaking == True

However, if Holism has seen a foo-relation-broken at some point in the past (and, so far and from that point onwards, no foo-relation-created!) and, since then, some other event (any other event) has been processed, then Holism will believe that no foo relation is active and exists.

In other words, while we’re processing relation-broken, the relation still exists but is in a breaking state. The next time we’re awakened (no matter the reason), we’ll assume the relation has broken down (it is no longer in a breaking state: it simply is no more).

holism.get_relation('foo') #  --> RelationNotFoundError!


  • something with planned units
  • other transient states other than relations?


The floor is yours.


Thanks Pietro, this is interesting – thanks for the write-up. It’s definitely good fodder for the holistic vs delta discussion.

That said, adding this kind of stuff to stored state gives me pause. Juju already maintains this state: some of it we can already query for, and the other parts are things we should probably add, like Relation.broken (issue 940) (or perhaps Relation.status).

We may need a new Juju hook tool to query for relation status, but I think that’s the better model. We’ll be considering that as part of issue 940 next cycle, and discussing the larger issue as part of the holistic vs delta discussion.

I’d also be interested to see your specific use cases for the Holism attributes/tracking.

This is an interesting proposal, it is kind of going somewhat in the direction of reconcile whilst still staying somewhat event based.

An alternative could be to include more details about the event as a part of the hook (e.g., the concept of CharmState from managing charm complexity and include the previous or the changed state in the event). That way we could implement more event based code for charms - adding to the holistic vs delta discussion

1 Like