I really like the “tech debt” metaphor. A lot of people don’t, but I think that’s because they either don’t extend the metaphor far enough, or because they don’t properly understand financial debt.
I learned things about debt and finance reading this, and it certainly helps bring much needed nuance to discussions about technical debt.
The discussion on Hacker News also had this comment that I loved, and I think I’ll use as alternative framing at work when discussing the need to keep code-bases healthy:
I worked with Ward Cunningham for about a year, and he said once that he regretted coining the phrase “technical debt.” He said it allowed people to think of the debt in a bottomless way: once you’ve accumulated some, why not a little more? After all, the first little bit didn’t hurt us, did it?
The end result of this thinking is the feature factory, where a company only ever builds new features, usually to attract new customers. Necessary refactors are called “tech debt” and left to pile up. Yes, this is just another view of bad management, but still, Ward thought that the metaphor afforded it too easily.
He said he wished instead that he’d coined “opportunity,” as in, producing or consuming it. Good practices produce opportunity. Opportunity can then be consumed in order to meet certain short-term goals.
So it flips the baseline. Rather than having a baseline of quality then dipping below it into tech debt, you’d produce opportunity to put you above the baseline. Once you have this opportunity, you consume it to get back to baseline but not below.
When I hear a phrase like “God’s house” the image that comes to my mind is usually a giant building. Perhaps one of the cathedrals of Europe, perhaps a more modern auditorium setting, or perhaps an imagined palatial setting that’s giant and magnificent and heavenly. But in my mind, it’s usually a building.
But here the writer reminds us very clearly that we are God’s house. It’s not a building, it’s people.
It’s also not a single person – it’s plural. They don’t say “and I am God’s house” or “and we are God’s houses”. All of us, together, are where God chooses to live.
And so if you want to find God, your best bet is to look where other humans are gathered.
And that’s what the word church actually means – the gathering, the assembly of people. The building isn’t where God is found. We, the people, are where God is found.
For where two or three gather together as my followers, I am there among them.”
You are coming to Christ, who is the living cornerstone of God’s temple. He was rejected by people, but he was chosen by God for great honor. And you are living stones that God is building into his spiritual temple. What’s more, you are his holy priests.
Don’t you realize that all of you together are the temple of God and that the Spirit of God lives in you? God will destroy anyone who destroys this temple. For God’s temple is holy, and you are that temple.
“Then these righteous ones will reply, ‘Lord, when did we ever see you hungry and feed you? Or thirsty and give you something to drink? Or a stranger and show you hospitality? Or naked and give you clothing? When did we ever see you sick or in prison and visit you?’
“And the King will say, ‘I tell you the truth, when you did it to one of the least of these my brothers and sisters, you were doing it to me!’
God, for whom and through whom everything was made, chose to bring many children into glory. And it was only right that he should make Jesus, through his suffering, a perfect leader, fit to bring them into their salvation.
Everything we see and hear and touch, all of the universe, all of creation, was made. This is one of the starting beliefs of Christianity: that there is a creator. A person behind it all, a person who had a reason to create. It’s not just matter. It’s not just energy. It’s not just existence.
The universe is personal.
“Through whom” is about the craftsmanship. That God is involved in the making of every water-drop, every flower, every person, every galaxy. To quote a church song from my teenage years: “is everything I know marked with my maker’s fingerprints?”
“For whom” is about the intent and the reason. God wanted this universe, and God wanted us in it. That’s our chosen starting point for the big life question: “why are we here?” We’re here because God wanted us, so God created us.
And the intent here is to bring many children – that’s us – into glory. It’s hard to even imagine what this is supposed to mean. The word “glory” here is the same Greek word “doxa” that is used again and again when Jesus talks about “returning in glory“, when Paul is “blinded by the intense light“, when Jesus talks about not needing the approval of the religious leaders, or when he gives examples about the seat of honour at special occasions. Whatever it means, God intends to make us stand out, make something bright and radiant, something honoured, something glorious, out of our lives.
It’s an incredible starting point, that imbues all of life with meaning and purpose and worth and hope.
But we all know life doesn’t actually look like that.
It’s far more messed up.
You know that. I know that.
These grand theological statements just don’t match the experience of our lives. Yes of course there’s joy and radiance… at times. But there’s just as much drudgery, or cruelty, or outright suffering. We feel heartbreak over separation, heartbreak over death, and we live in fear of both of these. We feel shame. We feel loneliness. We know life has suffering, and we know the suffering.
And with that, the writer of this letter to the Hebrews brings us back to Jesus. They promise Jesus is the leader who brings us into salvation, leading from this life to the promised life – from the suffering to the glory.
And while you know and I know that life doesn’t look like the promise being laid out, the writer knows it too, acknowledging that “we have not yet seen” the promise.
They know there is suffering, and they drive home this point: Jesus knew suffering too.
He didn’t just know about suffering. It’s not even that he knows about our suffering and sees us. It’s that he suffered.
Like we do. More, even.
…
So, when I originally thought I’d write a post on these verses, I imagined narrowing in on the idea that it’s through suffering you become a perfect leader. And there’s truth in that… but the more I meditate on this part of the letter to the Hebrews, the more I realise that’s not the truth the writer is trying to get across.
You see, I think Christianity is more about following than about leading. So the thing I’m finding myself focusing on is not me and my leadership… it’s Jesus and his leadership. Because I’m planning to follow him.
And while his path started in a place of honour and privilege – the son of God! – he then became human, deliberately made his home and found his community among those who lived in suffering. Not as a visitor, not as a rescuer, but as one of us. He embraced that, even to death, and through that was lifted back up to the kind of glorious life we talked about. And that is pretty much the story told in our earliest hymn and creed.
If that’s his path, and we’re following him through it, then it’s something worth meditating on.
What we do see is Jesus… because he suffered death for us, he is now “crowned with glory and honor.” Yes, by God’s grace, Jesus tasted death for everyone.
…
Because God’s children are human beings—made of flesh and blood—the Son also became flesh and blood. For only as a human being could he die, and only by dying could he break the power of the devil, who had the power of death.
…
Therefore, it was necessary for him to be made in every respect like us, his brothers and sisters, so that he could be our merciful and faithful High Priest before God.
…
Since he himself has gone through suffering and testing, he is able to help us when we are being tested.
Back in 2018 I gave a talk at a few different meetups and conferences called “Your Web Page Never Listens To Me“, it was all about the Web Speech API and what voice / conversational user interfaces could look like for the web.
At the time, speech recognition was finally getting pretty fast and accurate, but all my demos were limited to saying things the computer was expecting to hear – much like a CLI, you had to give exactly the right command for things to happen the way you want, and the discoverability for what commands might exist was non-existent.
In 2023, we’re getting used to Large Language Models like Chat GPT, which are remarkably good at holding a conversation, and it feels like they do a decent job at understanding what you’re trying to say. It certainly makes my string matching and regex based conversation handling from 2018 look like something from the stone age. Perhaps ChatGPT or similar could help me get a conversational UI going to interact with web pages?
Most people who’ve just had a quick play with ChatGPT are impressed by how much it seems to know and how well it writes, but you quickly realise it can’t do anything. It can’t look things up. It can’t open some other app and do tasks for you. All it can do is chat. And when it doesn’t know something it makes it up.
My main source of following updates to the world of generative AI and large language models is Simon Willison’s blog, and in March one of his blog posts titled “Beat ChatGPT in a Browser” stood out to me: you can get these large language models to interact with “commands” or “functions”. You tell them about a function that you will make available to it, what the function do,es and how to use it, and it will try send a chat message with syntax for calling the function or command as part of the conversation. As a programmer you can then wire that up to a real function or command, that interacts with the outside world, and get it to do something useful. Very cool idea!
At the time I think I experimented for an hour or so trying to prompt ChatGPT to respond in ways that I could use programmatically with little luck, and figured it was a bit harder than it sounded, especially for someone who hasn’t spent much time learning how to work with large language models.
Well, last week Open AI announced an update that introduced “Function Calling” in their Chat APIs. This is using the GPT3.5 or GPT4 models with an API for declaring the functions you want to make available to the chat bot, and it can then utilise them as part of the conversation. Again I experimented for an hour or so, and this time, it seemed to mostly work!
So far my experiment looks like this:
The dialogue of this interaction, in terms of messages between the user and the assistant, looks like this:
User: When and where is DDD Perth happening this year?
Assistant: DDD Perth is happening on 7th October 2023. The venue for the conference is Optus Stadium in Perth.
But there’s a lot more hidden dialogue making function calls, with 8 messages in total, 6 of them “behind the scenes”:
User: When and where is DDD Perth happening this year?
Function getTextFromPage() result:"Skip to contentMenuDDD PerthFacebook iconFacebook, opens in new windowInstagram iconInstagram...."
Assistant: DDD Perth is happening on 7th October 2023. The venue for the conference is Optus Stadium in Perth.
Now, there’s a whole bunch of problems here:
The language model I’m using only allows 4097 tokens, and the only option it has to read a page is to read all the text, which on most pages I try is at least 10,000 tokens. I had to cherry-pick the example above.
This is completely vulnerable to prompt injection. If I get it to visit a website the website could give new instructions to run functions I don’t want it to run, including opening web pages I don’t want it to open (porn, bitcoin miners, something that tries to take a photo of me using a webcam and post it to reddit…)
Interacting with it via a terminal isn’t really great.
I’m relying on a public search engine to locate the page I’m looking for, so it’ll often land on teh wrong page.
The function to get all the text often accidentally leaks JavaScript and CSS code into the output.
And probably many more things!
…but its exciting to see it work. I define a set of functions I want the LLM to be able to interact with, and I give it a natural language prompt, and it successfully navigates its way through my functions to answer the prompt using data from the real live internet.
I was listening to an interview with Krista Tippett and Ada Limón, and it was a beautiful, fun, hilarious interview. When she read the poem “Dead Stars” near the end of the interview I was brought to tears.
Out here, there’s a bowing even the trees are doing. Winter’s icy hand at the back of all of us. Black bark, slick yellow leaves, a kind of stillness that feels so mute it’s almost in another year.
I am a hearth of spiders these days: a nest of trying.
We point out the stars that make Orion as we take out the trash, the rolling containers a song of suburban thunder.
It’s almost romantic as we adjust the waxy blue recycling bin until you say, Man, we should really learn some new constellations.
And it’s true. We keep forgetting about Antlia, Centaurus, Draco, Lacerta, Hydra, Lyra, Lynx.
But mostly we’re forgetting we’re dead stars too, my mouth is full of dust and I wish to reclaim the rising —
to lean in the spotlight of streetlight with you, toward what’s larger within us, toward how we were born.
Look, we are not unspectacular things. We’ve come this far, survived this much. What
would happen if we decided to survive more? To love harder?
What if we stood up with our synapses and flesh and said, No. No, to the rising tides.
Stood for the many mute mouths of the sea, of the land?
What would happen if we used our bodies to bargain
for the safety of others, for earth, if we declared a clean night, if we stopped being terrified,
if we launched our demands into the sky, made ourselves so big people could point to us with the arrows they make in their minds,
rolling their trash bins out, after all of this is over?
The lines that cut through me: “Look, we are not unspectacular things We’ve come this far, survived this much. What would happen if we decided to survive more? To love harder?”
So we must listen very carefully to the truth we have heard, or we may drift away from it… what makes us think we can escape if we ignore this great salvation that was first announced by the Lord Jesus himself and then delivered to us by those who heard him speak?
It’s kind of a relief to read this, honestly. Most of the Christian New Testament parts of the bible were written by people with powerful first hand experiences of Jesus: Peter and John and Matthew were all walking with Jesus everyday for three years before his death. Even Paul who wrote most of the letters in the New Testament talked about his life altering experience as a physical encounter with a resurrected Jesus. I imagine that kind of exposure to a person is indelible, it leaves a permanent mark, its hard to drift away from.
But that’s not what most of us get. We might experience the invisible God, and have spiritual encounters of various kinds, but we don’t see or hear or touch or smell Jesus like they did. Not in a physical, tangible way. If Jesus is the image of the invisible God, we don’t get to see him. We just hear about his life from others. And the experiences we do have first-hand tend to be more intangible.
So it’s refreshing to here someone who wrote an important part of the bible, this letter to the Hebrews, say they’re in the same boat as us. They didn’t give us their name, so we don’t know who exactly it is. (Scholars like to guess. An audio-bible I used to listen to had the voice for Hebrews played by a cast of men and women to demonstrate the ambiguity. I liked the idea that it might have been a woman, because we know several women had important leadership roles in the early church but we’ve mostly been kept from hearing their voices.)
Whoever it was, they say they’re in the same boat as us. They didn’t know Jesus directly, they heard about him from someone else. They’re a second-generation follower. And they say it’s easy to drift and forget.
For me personally, some stuff didn’t drift: a sense of worth, value and dignity, of being made in the image of God. That was deeply internalised. My values as well have been deeply shaped by my faith earlier in life, and those mostly held steady even without continued focus. So what has drifted?
I think its the focus on the “great salvation” they talk about. There’s a big picture, a meta-narrative, an arc of history that ties together the story of Jesus and the stories of us.
When a person keeps this big picture in their field of view, it can yield a big change in the way they lead their lives. Being part of something bigger is incredibly motivating for most of us – and can call us into living courageously, selflessly, resiliently.
And I think that’s the bit that has drifted: without a focus on the big story, the routines and the challenges of my life have become all encompassing. I’m not suggesting I should have been going and serving the poor or preaching in churches instead… keeping my focus on my young family and loving them, providing for them, that should have been the focus anyway. But I wonder if I’d kept a connection to the larger story, if it would help strengthen the moments of joy, help bring meaning to the moments of suffering, and help me see beyond my own troubles to offer compassion to others around me who have their own challenges going on too.
I want to live my life with that big picture in view.
“We must listen very carefully to the truth we have heard, or we may drift away”.
Now, there’s a thousand different ways to understand what “great salvation” means, and I think each person’s experience of it, and the way they describe it, would be different. There’s a deep shared truth in there somewhere, and then the just-as-real truth of each person’s experience of it. And of course for me its complicated, because I don’t feel comfortable with some of the simpler narratives of sin and salvation and heaven and hell.
But there is something speaking there, something true, and if I want my life to follow that path in my life, and not drift away, and I should listen carefully, actively, asking questions and seeking to understand.
Long ago God spoke many times and in many ways to our ancestors through the prophets. And now in these final days, he has spoken to us through his Son.
I was catching up with friends from my church recently and one of them talked about how they’d been struggling to read the bible in any valuable way lately, and I struggled to relate – not because I have a vibrant relationship with reading the scriptures myself, but because it’s been so long since I have that, unlike my friend, I didn’t feel its absence in my life.
Years of daily reading as a teenager and young adult, and years of deep study in preparing to lead a small group or write a blog post or preach a sermon, have meant that the christian scriptures have been deeply embedded in how I think. But as the habit of daily reading dwindled, and the need to prepare for small groups or sermons dissipated, I haven’t found myself opening the book often, and when I did, I was often coming to it with a transactional mindset: looking to find something specific, as if the bible’s main purpose was to be a “proof text” to help me feel better about a position I hold or a life decision I’m making.
My friend mentioned they had been finding something else valuable – a book of readings and prayers for everyday life called “Every Moment Holy“. The bible isn’t the only way to hear God speaking. I know that to be true for me: in the years where bible reading hasn’t been a habit, I’ve still felt God speaking through time in nature, through times of reflection and introspection, through podcasts, through music and art, through friends and family and small children.
In all those I felt a sense that “God spoke”. Not an out-loud voice that moves through the air waves and into my ears. Not even an inner voice with a running dialogue in my head. But a sense that God, the hidden animating force of the universe, the person woven into every moment and every molecule, was somehow imparting and transmitting to me a sense of love, of peace, of strength to live a certain way, of clarity. God does speak in many times and in many ways, and we should attune our ears to hear it in all these ways, not just when we have a bible open.
But, having said all that…
I’ve recently been drawn back into the bible.
It started because our family life has been exhausting, and I’ve been feeling depleted. And a phrase I knew from the bible was ringing around in my head: “enter my rest”. I remembered there’s this whole bit in the book of Hebrews where it talks about entering God’s rest, a “Sabbath” rest, and some people enter it, and some don’t, and we should try to be those who do. I couldn’t shake it from my head, so I wanted to read it. (I had to ask Anna where our bible even was.)
And so I picked up the bible, and have been reading Hebrews, and have been drawn into it. All the ways I described “God speaking” and sending me love and peace and strength and clarity – I found again as every day or two I picked up the bible and kept reading.
And it didn’t feel transactional, like I was coming to check some facts or prove a point. It was different, like I was coming to it open to what it might say to me, what it might do to me.
My Dad also has a blog, and earlier this year he posted something which resonates with what I’m experiencing:
In the age of the printed book and of the internet, modern writings whether blogs or learned tomes are ephemeral, read, perhaps noted, and then discarded. They have no particular authority and different readers ascribe different value to them.
Religious reading, on the other hand, is different for the texts are treated with reverence as an ‘infinite resource,’ as a treasure house of wisdom, etc. As such, the words are read and re-read over and over and in time, tend to be committed to memory. “And as a reader memorizes a text, he becomes textualized; that is, he embodies the work that he has committed to memory”:
“‘A memorized work (like a lover, a friend, a spouse, a child) has entered into the fabric of its possessor’s intellectual and emotional life in a way that makes deep claims upon that life, claims that can only be ignored with effort and deliberation.’ … A memorized text has a peculiarly character-forming effect on the memorizer. The text becomes part of his character; he lives in it and lives it out.” (Wenham, Psalms as Torah, 53, citing Paul J. Griffiths, Religious Reading, 46-47).
And that’s been my experience. Reading and letting it change me, and form me. Chewing on the sentences and the phrases in my mind like you chew on gum, slowly letting its flavour out. Treating it as an infinite resource, and approaching it with reverence, and openness to its character-forming effects.
Some of it engaged me on my usual intellectual-theological level. Some of it felt like a lifeline of support and promises to hold me fast with the life challenges I’ve had going on. Some of it inspired me to carry a different attitude in my approach to life. Some of it was personal, and some of it I want to share. I’ve written down about 14 or so things that stood out that I think would be interesting reflections to share on this blog. So: I’m going to do that, starting with this: God speaks at many times, and in many ways.
Rabbi Danya Ruttenberg has been one of my favourite religious teachers for a few years now. Recently she’s written up two posts exploring what she calls “clobber” texts: verses in the Bible (Hebrew Bible in this case) that are used to clobber the LGBTQ community and justify homophobia / transphobia.
Her analysis is useful (and entertaining) and I imagine I’ll be coming back to these if I ever find myself in a discussion with someone trying to justify homophobia based on the Bible.
Beyond her unpacking of these verses and ways to interpret them, two things stood out to me. First: the role of scripture teachers in a world where religious fundamentalism is taking hold again. She lives in the USA where fundamentalist Christians are gaining significant political power and shaping laws to force their worldview onto others. The reality in Australia’s politics is different, but you see the same religious fundamentalism play out in power structures at the level of families and schools and communities.
Because in the days when drag bans are getting passed and gun bans aren’t, knowing your text inside and out matters.
We have to fight against the encroaching theocracy in many ways at once. One of those ways includes disemboweling bad readings of sacred texts—especially the bad readings that are used to harm people—at every available opportunity.
The other thing that stood out was her willingness to criticise the patriarchal and homophobic ideology when that’s what is in the text. Growing up evangelical, I had been taught “all scripture is God breathed”, and when something in there was completely out of step with our contemporary values, we either tried to change our values to match, or tried to reinterpret the text in some way that downplayed the parts we disagreed with. The Rabbi on the other hand isn’t afraid to question and criticise the scripture itself and the major rabbinic commentary through history – acknowledging it as tainted by human prejudices – even while somehow approaching it with care, treating it as sacred, and allowing it to speak.
As much as I love to hold up the more optimistic texts in my corpus, it’s still a very patriarchal tradition and we have plenty with which to reckon.
I’ve got today off work, the kids are at school or day care, and tomorrow I’ve got a surgery. I’m out in Beelu National Park near Mundaring and it’s very grounding.
It’s a bit of a “clickbait” title, and if you heard someone say it you’d probably imagine them being incredulous, dripping with cynicism: “imagine believing in that! I can’t even imagine how your brain gets to a point where you think a corpse coming back to life and walking out of a tomb isn’t ridiculous…” At some points of my life I’ve been convinced it’s true, and some points not, and well, eh 🤷♂️ That’s not what I’m thinking about today.
Instead, imagine, actually think about what it would be like, when someone believes and internalizes the idea that Jesus came back to life, never to die again. That there’s a life beyond this one, overlapping with this one, that means death is not the end. That those who mean the world to us who passed away we will see again, laugh with, eat with, embrace again. That this life isn’t the final life and so the end of this story isn’t the end of the story. Imagine that resurrection means there’s a chance for justice and restoration and hope even when this life has only been injustice, neglect and despair.
What would be different if someone really believed that? If you really believed that?
Imagining in this way isn’t an exercise in futility. One of the books that most impacted me is “The Prophetic Imagination” by Walter Brueggemann, which drove home the point that if you can’t picture a different future, if you can’t imagine it, then you can’t find the energy to start moving toward it. “Without vision the people perish”; but when you can imagine something new, an alternative future with new possibilities opens up.
So what alternate future is unlocked if people really believe in the resurrection?
As a start, the despair of losing someone to death is gone. The death of a loved one is always going to be painful, and life after will hold a sense of loneliness and loss, but “death has lost its sting”. When you believe they’ll live again, and you’ll see them again, and when you do it will be different, a life without the same suffering… then even though it’s hard, there’s an anchor of hope, both hope for you and hope for them.
Then there’s your own fear of death. You might still fear the fate of those left behind – even Jesus on the day of his death was asking his friend to care for his mum. But your own fear of death wouldn’t be the same. Instead of fearing the unknown, or fearing nothingness, if you believe wholeheartedly that after death comes life, and life without the same suffering… then there’s no fear in that. Instead hope, maybe even longing. That side of death looks “better by far”.
And if you don’t fear death, then you’re harder to control. Think of how much evil in the world is sustained because those in power can threaten to kill anyone who tries to stop them. If you don’t fear death, and even more, if you don’t fear missing out on your dreams for this life – because you trust your life will continue and be made new and right after death – then you’re free from that fear and intimidation, and you can act according to your conscience and your sense of justice. If a whole community believes that, it would be impossible to subdue them without eliminating them. They would have so much courage in the face of injustice and persecution… and courage can be very contagious.
And imagine you believe not just that there’s life after death, but you also believe the full good news message: that all will be set right. That those who weep now will laugh, those who are hungry now will be filled, those who have lived in poverty now will inherit the kingdom… all of a sudden you would see so much more dignity in the lowly parts of life. Any suffering, any wrongdoing, any injustice… you could filter it through your understanding of an eternity set right, and all those unbearably hard things would seem “light and momentary”. You could find hope to endure all of life’s hardships, and probably do so with joy.
And because your perspective has shifted and you know those who are suffering are destined for better things… you would feel compelled to bring that future forward, and work hard to help them today, not waiting for the final act to set things right.
(This is not unlike the stories I’ve heard of the first few centuries of the Christian church…)
So, ignoring the question of if it’s true… can you see the impact on the world if you were to believe the resurrection, living like it is true, and embodying resurrection as a driving force in your life?
So, this morning on Easter Sunday, when I stand with hundreds of other people and sing “Hallelujah, death has lost its grip on me” – I am encouraged. There is a way of life that stands in defiance of fear of death. The resurrection story frees us to imagine an alternative future, and pulls us forward into a new life, a resurrection life. And that life offers not just a bright hope for tomorrow, but strength and courage and clarity for today. And this morning as the voices of my church sang out and claimed this resurrection to be real, not just as history but present life and power, it helps me believe too.
Holy. It’s a word used all the time, especially in church, especially in church songs. The meaning is something like “apartness, holiness, sacredness, separateness” or “revered, set apart for God”1.
Singing about and meditating on God as “holy” is a reminder of how separate God is from us. There is something about God entirely different, foreign and “other” than what we experience as humans, and sometimes its good to remind ourselves that God is set apart, and take on a posture of reverence.
God is holy. God is set apart. God is separate from us.
But if there’s a scale from “separate” to “united”, or perhaps from “sacred” to “everyday”… then God is at the other end of the scale too. God is close, the name “Emmanual” that we have on Christmas cards means “God with us”. Yes, God is separate and different to us, but we’re also united with God. Paul uses the phrase “in Christ” over a hundred times, more than any other phrase in his writings2. We can hardly be separate if we are in God.
The same phrase is often translated “united with Christ”. There’s a deep sense that our goal is not separation but unity. 2 Peter 1:4 even talks about us being given promises through which we can “participate in the divine nature”3.
God is holy. God is separate from us. God is also united with us. God is close.
So when I hear a song celebrating the separate, the sacred, the holy nature of God – have we got it wrong? Are we revering separateness when in fact God is close? Is it time for the pendulum to swing the other way – for us to celebrate the nearness and the unity of God?
A pendulum, swinging from one extreme to another like our interest rate cycles or political climates… perhaps eventually finding a stable middle ground… is that the way we should be thinking about God?
Instead of a swinging pendulum, let’s think about it as a paradox.
Something where both ends of the scale are true. Instead of insisting only one side is correct, or instead of feeling we’ve gone too far one way and pulling hard toward the center again… what does it look like to embrace things, and explore how far we can stretch both ends?
But even the metaphor of stretching out something elastic in two directions still implies it will come back to a single middle point. This is a classic example of dualistic thinking – that there’s a clear true and false, and so if we are stretched in two competing directions, it will one day resolve to a single point.
But paradoxes aren’t like that – we could explore both ends of this scale and discover new and transforming ways of thinking about God and knowing God – on both ends of the spectrum.
Instead of a pendulum that swings between two points, or an elastic material that stretches but snaps back to center, we could think of paradox as a national park to explore. We start at our camp site. We don’t know if its in the exact centre of the park… it doesn’t really matter. We can set off walking in any direction, and explore what we find. Be amazed at what we find. Maybe we’ll come back to our original camp site, or maybe we’ll find a new place to camp – or many new places.
The paradox is not here to be answered or resolved. Its here to be explored. To be lived in. To be wandered and to bring wonder.
God is separate and holy. God is near, and united with us. Yes, to both. Let’s explore that.
You’ll do yourself no favours if you pick a side and try hold it, or if you reflexively always swing back to a middle point that doesn’t challenge your thinking too much.
There’s a bunch of paradoxes that are part of Christian faith and life. Jesus as fully human and Jesus as fully God. Fear God and have no fear. Free will and an all knowing God. Doing good to “let you light shine” and doing good in secret.
When faced with these, instead of trying to resolve the contradiction, or trying to find the middle ground, maybe try exploring. Paradox is an invitation to curiosity, to wonder, to humility, and to God changing how we think and how we live.
These are the irreducible mysteries that no systematic theology can logically explain, and it’s best that we imitate Moses when confronted with paradox. When he stood before the bush that burned and was not consumed, he did two things: drew closer for a better look, then removed his shoes.
I got these definitions of “Holy” from the website Blue Letter Bible, which has some free tools to look up the original language for a verse and see where else those words are used and get some of the feeling of their meaning. Here’s the link for Holy in the Hebrew bible (“קֹדֶשׁ” / qodesh) and in the greek parts of the bible (“ἅγιος” / hagios). I think I’d enjoy learning to read these languages properly one day.
I first came across the importance of this phrase “en Christo” / “in Christ” in Richard Rohr’s book “The Universal Christ”. The same idea is adapted and shared as a meditation here: https://cac.org/daily-meditations/in-christ-2019-02-27/
In The Orthodox Way, Kallistos Ware talks about the eastern orthodox idea of there being the “essence” and the “energy” of God, and we’re destined to join in the energy but will remain separate from the essence… which is an interesting way to think about it. But in line with this post, I wonder if there’s value to be found in not trying to resolve this contradiction but embrace both ends as true.
Content Warning: Jan 26th. This post talks about 26th Jan, European invasion/settlement, systematic oppression, racial abuse, and is generally pretty heavy. But the person we’re talking about was an incredibly strong resilient leader who I find really inspiring.
2023 Note: I wrote this originally in January 2017, but am only recently found the draft, and have tidied it up to publish now in 2023. 6 years later I still find this story gut wrenching, challenging and inspiring. I no longer live on the lands of the Kulin nations. Now I’m on Noongar land, and I pay my respects to their leaders, past, present and those emerging.
January 26th goes by different names in Australia. “Australia Day”, “Invasion Day”, “Survival Day”. On the 26th I saw people posting respects on social media to the traditional custodians of the land, the Aboriginal people who have been here for over 50,000 years.
I wanted to do the same, but realised I know very little of the people who lived here in Melbourne before 1835. So I set out to learn.
I live in Williamstown, one of the oldest suburbs in Melbourne, and one of the first places Europeans tried to settle back in the 1830s.
Before their boats landed, there was already a nation here – the Kulin Nation. A collection of 5 tribes, who had lived in the land for 31,000 years. One of the tribes was the Boonwurrung people, and the clan that hugged the coast from the Werribee River, through to Port Melbourne, Albert Park and St Kilda was called the Yalukit Willam.
This blog post is me sharing what I’ve learned about the Yalukit Willam, and one of their leaders. I pay respect to these people, the traditional custodians of the land I live in, and their leaders past, present and emerging.
A large field near Werribee, with a beautiful sunrise and the Melbourne skyline in the background.A map showing the Yalukit Willam land, and known meeting places at the time of European arrival. Hobson’s Bay. The water is shallow and you can see people and their dogs standing out in the water.
Ancient History
During the last ice age, there was no Port Phillip Bay, the water level was low enough you could walk right across, you could even walk right to Tasmania. After the ice age ended, the water rose to a point higher than it is today, the bay filled, and the area I now live in was completely underwater. It wasn’t until 5,000 years ago that the water level receded, and that was about when the Yalukit Willam people moved in.
(Fun fact, that gives weight to their ancient stories: The geological record lines up with their oral history, as a people they preserved a memory of the last ice age, and as a culture they remembered a time when they could walk across the bay. Even crazier, the Yalukit Willam borders line up closely with the high-water level following the last ice age – they moved in as soon as the water line receded and the land was available to walk on).
Introducing Derrimut
At the time of European Arrival in the area, one of the leaders – an “arweet” – of the Yalukit Willam people, was called Derrimut.
He’s a complicated and sometimes controversial figure… I’ll mention why in a minute, but for me though, in reading his story I’m filled with incredible respect at his strength, and sadness at how much he suffered.
Portrait of Derrimut by Benjamin Duterau, painted in 1837 during a visit to Hobart. Found on Wikipedia, public domain.
One of his first experiences with European forces was before any of them had attempted to settle down in the Melbourne area. It was a band of seal hunters, who came on to the shore and kidnapped several of the local women and took them as slaves. One of the women was Derrimut’s wife, Nandergoroke, another his sister in law, and one the wife of his nephew. When I think about the family close to me… I can’t even begin to imagine the pain.
Even with such a painful personal history to carry, he continued to lead his people with honour and courage. When a small group of Europeans landed and tried to settle, rather than responding in hostility and violence, he remembered the law of his people.
Tanderrum Hospitality: Freedom of the Bush
“This land will always be protected by the creator, Bunjil, who travels as an eagle, and by Waarn (Waa) who protects the waterways and travels as a crow. Bunjil taught the Boon Wurrung to always welcome guests, but he always required the Boon Wurrung to ask all visitors to make two promises: to obey the laws of Bunjil and not to harm the children of the land of Bunjil.
One of the customs of the Kulin people was to grant access to strangers and wanderers who came to their land, to welcome them and offer protection.
In June 1835, John Batman came with the intention to set up a village in what is now Melbourne. (Hilariously, if Wikipedia is to be believed, he wanted to call it Batmania). He met with the locals, and sought to organise a treaty with them, offering to pay them annually with a range of goods.
It seems likely this was misinterpreted by the Yalukit Willam leaders to mean Batman was participating in a Tanderrum ceremony, asking for temporary access and protection as a visitor, and offering gifts in return. The access rights
gave visitors who had no familial ties to the country the opportunity to seek formal permission from clan-heads for temporary access. The safety of all approved visitors was guaranteed.
As wikipedia notes, it was “a diplomatic rite involving the landholder’s hospitality and a ritual exchange of gifts, sometimes referred to as Freedom of the Bush.”
For Derrimut, he was a local leader, and a good man, and it was now his responsibility to care not only for his clan, but for the visitors that had arrived on his shore. (It makes me think about how poorly we treat those who come to our land, seeking our protection, in this day and age.)
Saving the settlement
So when word spread in October that year that a tribe from the North was intending to come and wipe out the new settlement, Derrimut raced to warn the European colonists, so they had time to arm themselves and fend off the attack.
This is where some of the controversy in his legacy comes in – in giving warning to the colonists, the colonists were able to arm themselves, and presumably kill/hurt/harm the people who were coming for them.
To me this feels like an ethically wrought and morally messy decision. It’s not straightforward and calling him a “hero” or a “traitor” for his actions in this moment skips over just how human this moment is – facing no good options and needing to decide what you will do. It’s not as simple as “picking sides”, especially once you count his own moral framework.
When I read the accounts, I suspect Derrimut saw it as his duty to protect them while they were on his land, and he did that by warning them of the oncoming attack, knowing what the consequences would be.
Values mismatch
Everything I’ve read about Derrimut shows me that he was exceptionally strong. Not in an angry, violent way that attacks and lashes out, but in a persistent, courageous, peaceful and moral way. He lived out his beliefs and tried to protect his people and co-operate with the European arrivals.
The Yalukit Willam had a culture that celebrated peace.
The culture he was dealing with though, the European settlement, did not recognise the same principals. The governor refused to recognise Batman’s treaty, and stuck to the arrogant belief that the land was empty when they found it, and therefore belonged to the Queen.
These people, coming to Derrimut’s land, in ever increasing numbers, were not temporary visitors, but invaders.
Fear and cruelty
As European settlers arrived and set out farms, they would fence off areas and claim them as their own. The land the Yalukit Willam people had walked on and hunted on and played on and celebrated over, for 5000 years, was now not in their control – and they were now told they were not welcome.
As the settlers expanded, they new arrivals viewed the Yalukit Willam suspiciously and fearfully. Land management rituals like burning out the undergrowth (without which Victoria’s horrendous bushfires will occur) were how the people kept the land flourishing, safe and sustainable, but Europeans believed the fires were meant to burn their farms and their families, and so responded with violent force.
The Boon Wurrung were known as a very peaceful people and if actually hostile, they would hardly have been deterred by one ‘old sailor’! This was likely a Yalukit Willam party engaged in their regular burning back of the lands during cooler weather necessary to stimulate pasture for kangaroo, reduce undergrowth and promote fire-tolerant food plants. Settlers however strongly discouraged ‘fire-stick farming’ as they were unfamiliar with the role of fire in regenerating Australian flora. This change in land management may have contributed to the Black Thursday disaster in 1851 when a quarter of Victoria burned.
These fears meant that as the farmers kept expanding their borders, they kept pushing the Yalukit Willam people further and further away. They were not subtle about this, they were brutal. I’ll quote a few paragraphs from “The Yalakit Willam: the First People of Hobson’s Bay”:
In June 1846, on government orders, Thomas [a government officer charged with “protecting” the Aboriginal people] removed the valuables from the willums (bark huts) of the Boon Wurrung camp then wrecked and burnt them. He ordered 51 residents to disperse. Thomas lamented that he had to order them to move every time a European objected. ‘Poor fellows, they are now compelled to shift almost at the will and paprice of the whites’. Their hardship was intensified because there was no bark left in the district and they were now compelled to build ‘mud huts’.
The Boon Wurrung and Woi Wurrung increasingly had trouble obtaining food in the vicinity of Melbourne, and they were suffering from introduced diseases. Europeans objected when Aboriginal people entered fenced paddocks to hunt, and, consequently, they were forced to subsist by begging and cutting firewood for the intruders.
The breaking up of camps continued unabated in the latter part of the 1840s. In January 1849, at one Boon Wurrung camp, Thomas was asked ‘where were they to go, why not give them a station’.
(Side note: the disparity between Thomas’s compassionate thoughts and cruel actions is why I think civil disobedience is vital for a just society. If you think something is wrong – don’t do it! Even if it is your job! Even if it puts you on the wrong side of the government and law-enforcement!).
It’s hard to comprehend just how unjust this is.
These people had successfully cared for the land sustainably for 5,000 years. Their first contact with Europeans involved family members being kidnapped. They still did the honourable thing and protected the first white immigrants, working with them cooperatively and peacefully. But the arriving settlers stole their possessions, and burned their homes, because they were prejudiced and afraid, assuming that land management practices were attacks. They banned them from hunting and from their traditional land management practices, and forced them into subsistence, reduced them to begging.
The Yalukit Willam people asked Thomas for a station, a section of land they could care for and continue to live on as they had always done, but free from European encroachment. Benbow, one of Derrimut’s fellow clan leaders, and even an employee of the government, tried to meet with Governor LaTrobe to make the request. LaTrobe left him waiting outside all day and refused to see him.
In March 1849, Benbow resolved to see Superintendent La Trobe to ask for a country for the Boon Wurrung… Benbow stood outside all day but was not admitted.
The last time I saw him was nearly opposite the Bank of Victoria, he stopped me and said, “You give me a shilling, Mr Hull.”
“No”, I said, “I will not give you a shilling, I will go and give you some bread”, and he held his hand out to me and said
“me plenty sulky you long time ago, you plenty sulky me, no sulky now, Derrimut soon die”, and then he pointed with a plaintive manner, which they can affect, to the Bank of Victoria, he said “You see, Mr Hull, Bank of Victoria, all of this mine, all along here Derrimut’s once, no matter now, me soon tumble down and die very soon now”.
Forced into subsistence, being told he’s not welcome on his land, Derrimut soon began to lose hope. The people he had welcomed onto his land, the people he had protected and co-operated with, had taken everything from him, and treated him cruelly.
(You can even feel the racism dripping in the sentence: “I won’t give you money, I’ll buy you a meal” – I’ve said that too! It makes me question how I respond to people on the streets who approach me for help. Did they think Derrimut was not capable of using money wisely? He was a capable and smart leader).
In July 1863, the very last of their land was sold to white settlers; they were now not allowed to live anywhere on the land that had once been their nation for 5,000 years.
They were moved on to a reserve at Coranderrk, North-East of Melbourne. On the day they had to leave, Thomas, the government officer enforcing the rule, wrote:
Poor Derrimut cried & so did Mr Man who hung his head on the breast of Derrimut like Esau and Jacob, I was forced at length to separate them.
Their connection to the land was more than just sentimentality and familiarity. I believe there is a spiritual element to it, and when Derrimut was forced off his land, despair set in. He died the following year.
Derrimut became very disillusioned and died at the Melbourne Benevolent Asylum at the age of about 54 years in 1864. In his honour, over his body, interred in the Melbourne General Cemetery according to European rather than Aboriginal rites, a tombstone was erected.
The tragedy continued after Derrimut’s story ended. His clan, resourceful as they were and with their knowledge of the land, used the station at Coranderrk to farm and run a successful business. They were so successful that they started winning awards, and then the oppression started once more, with neighbouring European farmers believing it was not the people and their farming practices that resulted in the high quality produce, but merely that the land was more valuable. Because of this they started moving the Yalukit Willam people off the reserve, and caused the business to collapse.
Coranderrk Station ran successfully for many years as an Aboriginal enterprise, selling wheat, hops and crafts on the burgeoning Melbourne market. Produce from the farm won first prize at the Melbourne International Exhibition in 1881; and other awards in previous years, such as 1872.
By 1874, the Aboriginal Protection Board (APB) was looking for ways to undermine Coranderrk by moving people away due to their successful farming practices. Neighbouring farmers also wanted the mission closed as the land was now deemed ‘too valuable’ for Aboriginal people to occupy.
The level of abuse and repression they suffered is hard to swallow. I’ve often felt a sense of shame at our national history, but seeing these details of specific incidents, the cruelty of it, it hurts to know that it was my culture inflicting this on good, innocent people.
My reflection
Most mornings I ride my bike along this land, around Hobson’s Bay and through Point Gellibrand, along the river and bay and wetlands where Derrimut once lived freely.
There is a beauty here that is breathtaking. It is also life giving. There is a spirituality to this place. I can only imagine how strong that sense is for the people of a culture that have lived here and sustained the land, and been sustained by it, for thousands of years.
That same respect for land also gave him a respect for other people, even foreigners from a culture he did not understand, and as I read his story I am so inspired by his kindness and decision to honour his commitment to hospitality and protection of visitors, even when it put him in opposition to some of his own people – he stood up for the visitors in his care.
And yet he was crushed by a cruel invading culture, and that is the culture I’m part of. It brought me to tears realising how horribly we treated such a good man, and all his people.. And to think of the generations of pain caused to countless Yalukit Willam people who lost their connection to the land and have been repressed for over a century. And people of nations all over this continent…
It gives me so much more respect for Indigenous people across Australia who are still here, still fighting to be heard, fighting to have their culture recognised, fighting for a positive future for themselves and for their children. The cruelty they have suffered is so significant, to continue on shows such courage.
Learning this history has also been a big reality check for my own privilege, helping me see the systematic racism still at play, and start thinking about what my role has been in it, and what my role needs to be in reversing it.
Your own learning
If you want to learn more, I recommend you look up the history from your local council. Most local governments in Australia will publish some history of the first inhabitants on their website. Take a look, learn about the leaders, past and present, who are the traditional custodians of the land you now live in.
Here are the articles I read in writing this post:
I’d add to that… with an upcoming referendum on giving an Indigenous Voice to Parliament, have a think about who you know, who you’ve got a trusting relationship with, and who will or might vote against it. And have a heartfelt conversation with that person, try to change their mind.
I’ve just set up the ActivityPub plugin for WordPress, which should allow my posts here to be followed on Mastodon and other fediverse accounts using @jason@jasono.co.
I’m creating this as a simple post to see if it works, and how things like comment interactions work!
For the third year now, I’ve been following Advent readings from the book “Watch for the Light“. One of the readings was this poem by Jane Kenyon, it’s titled “Mosiac of the Nativity: Serbia, Winter, 1993”:
On the domed ceiling God
is thinking:
I made them my joy,
and everything else I created
I made to bless them.
But see what they do!
I know their hearts
and arguments:
“We’re descended from
Cain. Evil is nothing new,
so what does it matter now
if we shell the infirmary,
and the well where the fearful
and rash alike must
come for water?”
God thinks Mary into being.
Suspended at the apogee
of the golden dome,
she curls in a brown pod,
and inside her the mind
of Christ, cloaked in blood,
lodges and begins to grow.
The scale of human suffering, so much of it that we inflict on each other, is unbearable. And what does God do with all that?
“God thinks Mary into being… and inside her the mind of Christ, cloaked in blood, lodges and begins to grow.”
Is a baby really going to be enough? Enough to get humanity off an evil course and back on track? What possible difference could a baby make? It reminds me of this line from the song “Seasons”:
You’re the God of greatness Even in a manger For all I know of seasons Is that you take your time You could have saved us in a second Instead you sent a child
Lyrics from “Seasons”. Words and Music by Chris Davenport, Benjamin Hastings & Ben Tan. Published by Hillsong.
This contrast perhaps says something about God, and about the gift humanity wanted vs the gift humanity needed: power vs vulnerability, force vs weakness, hard logic vs trust, quick results vs patience.
Considering our need, the gift most of us would ask for would be the forceful intervention. And yet at Christmas we Christians reflect on the fact that’s not the gift God choose to give us. Instead, God sent a child.
In what areas are you praying for God’s forceful intervention, and instead God is doing something small and fragile, slow and vulnerable?
Where are you using your own power and influence to force a quick solution, when perhaps there’s a less expected approach God is initiating?
Advent is about making space for God to come.
And its quite likely that the way God comes among us now will be in a gentler, slower, easier to ignore, less obvious, more vulnerable form than we want.
The work of advent isn’t for us to take the initiative and plan how God will come, but to make space, to wait, and to commit to that way.
To respond as Mary did, “May it be to me as you have said”.
One of the awful recurring conversations of my teenage and early adults years as a young Christian usually began with a question like “what about all the people who never heard of Jesus because of where and when they lived?”
The reason that I find this an awful conversation, in retrospect, is because a bunch of the assumptions behind it. For example: God is the only meaning in life, so if you don’t have God, your life is meaningless. Worse still, hell is a thing, and that’s the awful default choice for where you go if you’re not connected to God. And you get connected with God when someone tells you about Jesus and you respond in a certain way. So what if you live in one of the many, many times or places where no such opportunity arises? That hardly seems fair!
Here we were, as young Christians, responding to our own spiritual experiences of love that meant the whole world to us, and that pushed us to want to love all people, and yet the belief system surrounding those beautiful experiences was one that assumed a whole bunch of people would suffer intensely and unendingly for something they had no control over.
Now, the conversations weren’t that awful, because for the most part, we were trying to find ways to morph the beliefs back into something more loving, that more closely matched our experiences of love.
I remember clinging to the story of a guy’s near death (or actual death?) experience which apparently involved a supernatural deathbed opportunity to connect with God despite being an atheist until that point. Maybe everyone gets a chance and no-one goes to hell unfairly after all!? Eventually we’d start hearing rumours that maybe the “hell” story isn’t as clear cut as we thought, and when Rob Bell wrote “Love Wins” a bunch of people felt relieved to hear someone articulately argue that we don’t have to believe in the punishment thing. (Disclaimer: I haven’t actually read the book, and many people said he’s a heretic for it, but I love Rob Bell. Any “heresy” he’s pushing I’m likely to agree with him on!)
But even aside from the question of hell, do we really think God is completely absent from humans, except through some of the organised religions?
Back then I studied the bible a lot, and over time some verses that aren’t commonly talked about in evangelical circles started standing out to me, like this little aside from Paul in Romans 2:
Indeed, when Gentiles, who do not have the law, do by nature things required by the law, they are a law for themselves, even though they do not have the law. They show that the requirements of the law are written on their hearts, their consciences also bearing witness, and their thoughts sometimes accusing them and at other times even defending them.
So there’s the most prolific writer of the early church, Paul, acknowledging that sometimes God is interacting with people who’ve never had any conscious interaction with the visible religions that are officially representing God. God just gets in and connects with them anyway, and doesn’t wait for the religion to make its way across the world first.
Eventually, I found myself paying attention to Paul’s sermon to the people of Athens, recorded in Acts 17. After a few years away from church, and when I was not even sure if I’d call myself Christian, this sermon felt really compelling to me:
The God who made the world and everything in it is the Lord of heaven and earth and does not live in temples built by human hands. And he is not served by human hands, as if he needed anything. Rather, he himself gives everyone life and breath and everything else. From one man he made all the nations, that they should inhabit the whole earth; and he marked out their appointed times in history and the boundaries of their lands. God did this so that they would seek him and perhaps reach out for him and find him, though he is not far from any one of us. ‘For in him we live and move and have our being.’ As some of your own poets have said, ‘We are his offspring.’
Acts 17:24-28
For any century you could be born in, for any country you inhabit, “Got is not very far from any of us”. And God’s whole motivation in placing us here on this world… that we would seek God, perhaps reach out for, and find God. God desired relationship, and thats been available – “not far from” – all people in all nations at any point in history.
And this rings true for me: the same God I’ve known, I’ve seen showing up in other parts of the world which hadn’t had exposure to the same Christianity I had.
A few years ago I discovered Karen Armstrong’s book “The Case For God”, which does a beautiful job depicting how cultures across the world have tried to reach out to “the unknown God”, and showing common threads of mystic encounter and a deep ethic of compassion emerging from all different parts of the world.
She’s gone on to start the Charter For Compassion, and perhaps that’s a fitting place to end this post. The love that me and my friends felt so strongly, that made us want to question any belief system that sent innocent people to suffer, that love was the real deal. And that same love is emerging all over the world, in all sorts of communities, religious or not. Making sure your religion – both the spiritual experiences and the belief system – drive you towards love and compassion is absolutely crucial.
We therefore call upon all men and women to restore compassion to the centre of morality and religion ~ to return to the ancient principle that any interpretation of scripture that breeds violence, hatred or disdain is illegitimate ~ to ensure that youth are given accurate and respectful information about other traditions, religions and cultures ~ to encourage a positive appreciation of cultural and religious diversity ~ to cultivate an informed empathy with the suffering of all human beings—even those regarded as enemies.
Edit: 15 Dec 2022: I’ve since discovered the name for this topic: The Fate Of The Unlearned. There’s even a wikipedia page, which explores the same passage in Romans 2. The page lists a range of viewpoints from Christianity and Islam, and my upbringing probably sat on the “harsher” side – many traditions do have theologies that are more inclusive for those who outside the formal religion. Even with that though, I think there’s a lot of the behaviour I described us also doing: trying to find justifications to drag their beliefs back to the reality of the love they’ve experienced… but the starting point for the beliefs is often still out of line with the experience of infinite love. I think our theology can be better than that, we can have belief systems that are more reflective of our experience of infinite love. We should strive for that.
I’ve started participating in a local church again lately, after a few years away.
In that time away my beliefs have continued to evolve (there’s never really been a period in my life where they haven’t), and now I find myself standing in a gathering of people signing songs whose lyrics often make me cringe, and bring on a sense of cognitive dissonance for me – there’s parts of this I do believe are true, parts of this I want to believe are true (but probably don’t, if I’m honest) and parts that I think are downright unhealthy, regardless of their truth.
So what am I doing here?
Well, I want community. And being part of a regular weekly gathering is a way of building friendships that I know works, and that I’m comfortable with. Even if there’s a little dissonance.
I also want a spiritual practice – I’ve never stopped believing in God (if you’ll let me define “believing” and “God” on my own terms at least!) and have wanted to maintain a connection with the spiritual reality that permeates everything. And while I’ve experienced this same connection in music festivals and yoga classes, something I’ve appreciated about the church I grew up in is the absolute insistence that this divine spiritual reality isn’t an impersonal energy, but is a person, and is a person who can be known, and a person who wants to be known. I want that.
But probably the biggest thing is that for all my questions about the meaning of Jesus’ life, I still find his example and his teaching incredibly compelling, and to this day haven’t found anything else that I’d want to have as a foundation for building my own life on, a story to orient myself towards, a starting point for choosing the way I want to live.
I guess that’s what I think of as discipleship. Following the way of the teacher. Regardless of what I intellectually reason to be truth, I can still listen to teachings, learning from the example, and choose to live that way.
This morning at the church gathering, there was a song I felt no awkwardness singing, so I sang it loud:
I have decided to follow Jesus No turning back No turning back
3 weeks ago I heard the incredibly sad news that my friend Li had passed away. I was his manager for a few years at Culture Amp, and to remember him, I want to share a few stories of conversations we had during out time working together that I think speak to the quality of his character.
Talented, but humble
Li was a remarkable front end engineer. He was quietly productive, building high quality user interfaces faster that almost anyone else around. It wasn’t uncommon to hear feedback that he’d finished building out an entire interface on his own while a whole team of back end engineers were still working on making the data available for it. Eventually people started to notice, and Kevin Yank, our Director of Front End Engineering, asked: how do you do it? Is there some secret the rest of us could learn too?
His answer still makes me laugh. “I’ve got my code editor set up really well.”
To this day I don’t know if he was just trying to deflect the compliment, or if he really thought that was his secret advantage. Tool sharpening is definitely a thing in our industry – we like to quote the proverb “Give me six hours to chop down a tree and I will spend the first four sharpening the axe.”
Li’s editor setup was simple, it wasn’t something he wasted time tweaking over and over, but it was effective. When I watched him work he spent his time thinking about the problem at hand, not trying to remember where a file was saved or trying to remember what a keyboard shortcut was.
Remembering it, I love the humility of his response – he didn’t boast, he wasn’t proud. He knew he was good at what he did, and was happy to share the things he found helpful.
Learning, to share
I remember a point where Culture Amp had just acquired a smaller company, and we were looking for some senior engineers to transfer in and join the team we’d just acquired to help them integrate their product into ours.
At first Li was interested in exploring the opportunity, but then backed out when he realized the move would be permanent, not a secondment from his current team.
We had some conversations to explore the opportunity, and he surprised me with his biggest motivation not being the desire for a lead role, or a high visibility project, or the desire to work with a team based in the US, but instead the chance for mutual learning. He wanted to work with an established team, see what he could learn from them, see what he could teach them, and bring that back to his existing team and work, sharing what he had learned. Which explained why he was interested if it was a secondment, but not permanent.
Throughout our time working together I was always impressed at his willingness to learn, be curious, do deep dives into a problem, and then to bring what he’d learned and share it back to the team around him so we would all benefit.
Contentment
I remember wanting to understand some of Li’s long term career aspirations, and I asked a question I learned from Kim Scott’s book Radical Candor: “At the peak of your career, what sort of work do you want to be doing?”
Most people have a few different answers to this, sometimes its a job title (“director of X”) or a specific role (“I want to be focused in Application Security”) or an ambition outside the industry entirely (“I want to run a small business, maybe a food truck”) or a personal goal (“financial independence, then volunteering”).
It was hard to get a picture from Li of a specific goal he was working towards, and the reason I eventually learned, is that he was content. He really liked the kind of work he did, and found it meaningful. He really liked the people he worked with. “I’m actually really happy in my current role” was something he’d say if I kept asking.
Contentment is rare. Especially in the high-growth software industry. When I think about Li’s good-hearted approach to work and life and his ability to actually enjoy the place he’s at, without longing for more, I think of this quote from the bible:
godliness with contentment is great gain.
Li found contentment, and I admire him for it.
There was a whole lot more about Li I never got to know that well – perhaps because of the manager/employee relationship dynamics, perhaps because we worked from different cities, we didn’t share much of our personal worlds with each other. There was a little bit – I’d hear about an upcoming dance congress he was excited about. Or how a lunch we shared reminded him of Sunday lunches after church with his family when he was growing up. Or about the ups and downs of buying, owning, renting out, and selling an apartment. I had no idea he could speak Spanish. I wish I’d had more time with him, and asked more questions, and shared more of myself too. But even without that, I’m grateful for having crossed paths, worked with, learned and laughed together.
There are only two major paths by which the human soul comes to God: the path of great love, and the one of great suffering. Both finally come down to great suffering—because if we love anything greatly, we will eventually suffer for it.
When we’re young, God hides this from us. We think it won’t have to be true for us. But to love anything in depth and over the long term, we eventually must suffer.
I’ve often remembered this thought from Richard Rohr – said in different times and different ways, but basically: the path to transformation is either great love, or great suffering.
I used to hear it and struggle to imagine the great suffering. My life has usually been pretty comfortable.
But he’s right, if you open up enough to experience love, then you’re opening yourself up to suffering too.
Parenting has been that journey for me.
A greater love than I knew was there. More pressure than I knew I’d face. More resilience than I could have imagined I’d had, and more than I thought I’d need. More awareness of my own fragility. More delight too.
Our family is definitely still in the pressure cooker. Its hard to say what the lessons learned will be, what the transformation might look like from the other side. For now, it’s hard to get through, and not much sense of hope for change.
Remembering this thought from Richard Rohr gives a glimpse of purpose to the love and suffering of parenting. Maybe this is one of the paths to God.
Edit: it turns out for that the app Freedom that I talk about in this post, the problem is largely to do with Apple’s App Store policies. Their CEO Fred has left a comment below. My apologies! I did end up getting a coupon for my use, and the mistake in their support team refunded me for the price I paid on top of the coupon code. I use the app regularly and find it valuable. It’s worth checking out! But the UI pattern still annoys me so I’ll leave the blog post up. But without this clarification I’m probably being unfair to a pretty good product team.
One user experience pattern I find annoying is coupon codes. Or more specifically: offering me different prices so often that I’m anxious when purchasing that I might not be getting the best price.
The price of the yearly plan I’m pretty sure I want. $20 less than in-app!
Viewing the pricing page 5 minutes later, a different discount!
The final price I paid, 50% less than the in-app price
A variety of the different price points I was offered while trying to sign up for 12 months, all on the same day.
The first price I saw was $60 in the iOS app. The same subscription on the website was 33% cheaper at $40. And there were two separate discount codes. In the end I saw a price for $29.99, which I tried to pay for.
Consistently offering different prices for the same product causes me to lose trust in the company, feel like I’m being cheated, and hesitate to pay, because I’m unsure of if there will be a better price tomorrow.
Frustratingly, I realized after the fact they’ve charged me $39.99. I’ve contacted their support to ask for a refund for the amount the coupon code would have saved me.
Overall, I’m enjoying the product itself – it lets you start a session that blocks distracting websites across all your devices, and does so at a VPN level so that tricks like switching browsers do not work – which is enough to break some of my time wasting habits.
But this saga with the pricing, which was either buggy enough or confusing enough that I ended up paying 33% more than I thought… has left a bad taste in my mouth. I think they must have analytics to prove the revenue benefit of this style of checkout in the short term, but I can’t help but think the brand/reputation damage isn’t going to help long term.
At Culture Amp we dropped support for Internet Explorer 11 in March this year, despite a significant portion of our annual recurring revenue coming from companies with over 10% of users still on IE11. We did that without complaints. How? Through a mix of customer conversations, clear planning, a neat technical trick, a focus on UX, and clear communication. Here’s the story of how we did it.
About us and our customers
To help understand the context we’re working in, it helps to know a bit about our company. Culture Amp is on a mission to create a better world of work, by building a software platform that helps companies understand their people and improve their company culture.
(p.s. Culture Amp is hiring engineers in Australia and NZ. It’s the best place I’ve ever worked. If you’re interested you can check out open roles or contact me, hello@jasono.co)
We have over 4000 customers ranging from small business to large enterprise. Some of our companies are progressive tech companies that have modern IT systems… and some still were using IE11.
Our leading product is an employee engagement platform which captures survey responses and shares insights and reports with millions of employees around the world. We care a lot about giving those employees a voice, and so we spend a lot of time making sure that our platform is accessible for as many people as possible. And browser support is a form of accessibility.
We don’t want to exclude people from our platform, and prevent their voice from being heard in their company surveys, because of their available technology.
Why we wanted to drop IE11
Having said that, supporting Internet Explorer 11 sucks. Most of our team are developing on MacBooks, so testing in IE11 requires either firing up a virtual machine or using a tool like BrowserStack. If you try to do this for every pull request, your pace of work really slows down. If you don’t, you start getting support tickets coming in because something unexpected broke in IE11, and those are hard work to debug too!
And also, we wanted to use new browser technologies. Being in the team that maintains our Kaizen design system, I was particularly excited about being able to use CSS Custom Properties and CSS Grid finally.
First question… is anyone still using it?
We were initially hoping we could look at IE11 usage and it would be so miniscule, no one would notice if we dropped support. (We dropped IE10 support when usage was below 1%).
Unfortunately, IE11 usage was sometimes still hovering around 8%, and some weeks went as high as 15%.
We wanted to understand it more, and so asked one of our analysts to look at the revenue amounts for the clients with high IE11 usage.
% of ARR
Accounts with >10% IE11 usage
18.6%
Accounts with >20% IE11 usage
9.5%
Accounts with >30% IE11 usage
4.6%
Accounts with >40% IE11 usage
3.4%
Accounts with >50% IE11 usage
1.5%
This table shows a huge portion of our revenue came from companies still with over 10% IE11 usage. We needed to make sure whatever our plan was, we didn’t upset this many customers.
This was pretty discouraging, but we continued to explore our options.
Starting with a conversation
My manager Kevin Yank reached out to one of our biggest customers, who we knew required IE11, and asked to chat to understand what the situation was on the ground, rather than just looking at the analytics and giving up hope. When we chatted to them, we realized this big customer did have Microsoft Edge installed on all of their computers, it just wasn’t always the default browser when people clicked a link from their emails. If we could convince them to switch to Edge, which they already had installed, maybe we could drop support for IE11 after all.
We ended up using a version of this to reach out to all customers of a certain size who had > 20% IE11 usage. Here’s the message we used:
We’re hoping to understand the use of Internet Explorer 11 at your company.
Now that the more modern Microsoft Edge browser is available on all versions of Windows we’re hoping to redirect users of the old Microsoft Internet Explorer 11 (released in 2013) to the modern Microsoft Edge browser.
This browser is getting more and more burdensome for us to support; the user experience of our product in that browser is getting worse and worse (it is both slow and increasingly ugly there), and we’re approaching a couple of technical decisions that, if we need to support IE11, will put us in a restrictive box for years to come. (Even Microsoft themselves are beginning to no longer support Internet Explorer 11 on some of their websites!)
We’d love to understand a bit more about your IT environment:
– Under what circumstances are your users needing to access Culture Amp through IE11?
– Is there a more modern alternative browser installed on those computers that you could switch to if necessary?
Are you able to get answers to these questions, or connect us with the right person so we can discuss?
We worked with our customer account managers to send this message to all customers above a certain threshold who had high IE11 usage.
The result: every one of the customers we spoke to said that employees would have another browser (usually they mentioned Edge, sometimes Chrome) also installed that they could use, but it might not be the default.
So… if they have a better browser installed, how do we get them to use it?
A technical discovery for directing users to Edge
With the Engagement product I mentioned earlier, a key to the success of the product is having high survey participation rates. We knew that if we started blocking ~10% of users (and in some companies, >50%) it was really going to hurt the product’s effectiveness.
We needed a way to have users switch browser with a high conversion rate.
So we began asking, is there a way to open a page in Edge from a page in Internet Explorer? We found our answer on Stack Overflow – there is, using a microsoft-edge: protocol in your links.
You could also use the custom-protocol-check package on NPM to check if the link click worked, and display a message on success or failure. (Unfortunately, it can’t tell you if it will work before the user attempts the action).
A screen recording showing the Codepen example and how a link in IE11 can open the same page in Edge.
There was a big scary alert warning before Edge would open, but if you allowed it, it did work. We hoped that with the write UX design and some encouraging copy, we could convince users to click a button, click allow, and open the link.
Stage 1 UX: a “soft” notification
The first phase was to show a persistent banner across the top of the page to all IE11 users, with a link that attempts to open the same page in Edge.
A screenshot of the notification design.
When we released this, we knew most people would ignore the banner, because ignoring banners is what people do. But for those who did click, it would allow us to get analytics on how many of them were able to successfully launch Edge.
We measured how many users saw the banner, how many clicked it, and how many had Edge open successfully.
The good news: even though only 9% of people clicked the banner, when they did, 90% clicked “Allow” and successfully opened the page in Edge. (Apparently the scary alert box wasn’t as scary as I thought!)
The banner displays in Internet Explorer 11. When the user clicks the “Switch to Microsoft Edge” link, a confirmation popup appears, and when they click “allow” the page opens in Microsoft Edge.
So, all we needed to do was force people to click the button. And that meant something more forceful than a notification banner.
Stage 2 UX: a “hard” interstitial page
We hoped a full page interstitial would do the trick.
For the official end of support, we made it much harder to ignore. At our login screen, we redirected all users to a full page notification where the primary call to action is to open in Edge. This had much better results.
This looks healthier! The absolute numbers here are smaller a few months after the transition – people are now visiting from IE11 less often. But the percentages have stayed about the same since launch.
We now have 55% attempting to open in Edge, and 92% of them still succeeding, for an overall success rate of 50%. We believe most of the other users are switching to an alternative browser manually or bouncing.
Either way, this was enough to give us confidence that anyone who wants to use our platform, is able to. And our customers shared that confidence.
On login the user sees a full page notification directing them to open in Edge. They were 5x as likely to click “Open in Edge” here compared to the top-of-page banner.
The timeline
January 2021
Contact important customers to understand the impact.
January 27th, 2021
Initial email to all customers. Deprecation timeline added to support guide.
February 1st, 2021
Global Notification released and visible on all pages.
March 24th, 2021
Final email warning to all customers. Support guide updated.
March 25th, 2021
Support dropped. Interstitial Page released.
March 26th, 2021
We get to stop caring about IE11 and start using new browser features!
The result
Getting to announce this to the company was a special feeling.Getting to announce this to our front end engineers was even better
We released the change, and no customers were upset by it. We continued to see a healthy conversion of IE11 visitors to Edge by clicking the button, and a trend of less and less IE11 visitors over time.
Our teams no longer have to fix bugs in IE11, and no longer have to fire up a virtual machine to check their latest change in an ancient browser.
And we can now use things like CSS Custom Properties, which we’ve used to roll out a theme switcher in our design system.
What I’ve learned
Matching product analytics with business data (like account value) can paint an important picture of the impact a change will have.
Sometimes product analytics aren’t enough to tell the full story, and conversations with customers unearth a clearer picture, which can open up new options you might have assumed were unavailable.
Releasing a risky change like this in two stages helps! You can use analytics to validate a part of the conversion funnel you’re worried about (for us, if the “Open in Edge” button would actually work for people).
Large enterprise customers are more reasonable about old technology than I had originally thought.
Special thanks to my coworker Roy Zane who was my main collaborator in driving this project through to completion.
At the change of the year I want to engage in some reflection. A reflective exercise I’ve began using in 2020 is a daily prayer called “The Examen”. I believe it’s a Jesuit practice, and I’m following this format shared by Xavier University. I’ve mildly adapted it here to make the language about the year not the day.
The Examen: A Daily Prayer
St. Ignatius Loyola’s Examen is an opportunity for peaceful daily reflective prayer. It invites us to find the movement of God in all the people and events of our day. The Examen is simply a set of introspective prompts for you to follow or adapt to your own character and spirit.
Begin with a pause and a slow, deep breath or two; become aware that you are in the presence of the Holy.
The biggest news of the year came in the final month. On December 4th in the early hours of the morning, Hugo was born. We’d been holding our hopes for a healthy baby and a healthy mum – and both came to be. We’re now a family of four, and I’m so grateful.
Christmas Day 2020. I’m 33, Anna is 30, Louis is 2 and Hugo is 3 weeks old.
One of the other things we’ve been hoping and praying for through 2020 was about making the most of our time with Louis at this young age and while before his brother arrived. He learned so much about the world, and we learned so much from him, and my love grew more than I knew my heart was capable of.
2020 for most of the planet was defined by the COVID19 pandemic. I lived in Western Australia, one of the safest places on earth this year. Safe in a pandemic, locked down in a big home with Anna’s parents who we love. Grateful to have spent this year safe, and for the proximity to family, and for the support we gave each other.
I’m also grateful to be writing this from a beautiful house that’s now our family home. After living in 9 houses over 5 years we were keen to settle. We tried to sell our little unit and buy a family home, but the finances just couldn’t work. We’ve found a rental though that is perfect for our family and our stage of life.
This year we also found a spiritual community where we felt most authentically ourselves since our small Melbourne church closed down. A small group of friends (we know each other mostly from Riverview) started gathering, at first on Zoom, and then face-to-face once it was safe, and sharing our journeys, and finding ways to hone our spiritual practices together. We used the resources at https://practicingtheway.org/ to lead us in growing in two practices in particular: Silence and Solitude, and Sabbath. I also made some small progress in finding words and courage to share where I’m currently at with friends and family whose journey and beliefs now look pretty different to mine.
The first practice our Sunday group worked through was “Silence and Solitude”. I’d highly recommend this series (if you’re up for the church teaching style and the assumed Christian background anyway)
I was grateful for the courage Anna had in writing this post and releasing this song. This has been a big part of our story that we’ve carried privately for a long time. Sharing it took courage.
This song took 3 years from writing to release. And the story behind it spans an entire life.
I felt like this year I had courage at work and have grown as a leader, taking on new teams and harder tasks and speaking up when it’s not been comfortable. The support I’ve had from my co-workers, and my managers in particular, has helped me grow so much.
There’s other places I started to show courage, but wish I had better follow through. After the devastating Australian bush-fire season I reached out to local politicians to discuss an idea for community volunteering in the face of climate change, but dropped the ball when COVID19 took over the world. Similarly I was exploring doing a DEI (Diversity, Equity, Inclusion) talk at tech meet-ups, exploring how privilege has shaped my own journey, to help other people recognise their privilege and work to share it. This also dropped off the radar during COVID19 lock-down. I also made efforts to help people affected by Culture Amp’s layoffs. Not sure if it really helped anyone. And lately I’ve been volunteering to help a small group build a site for collecting stories about those with disabilities and their experience of being Locked Out during lock downs. Hopefully I have better follow through there!
Finally, I’m grateful for this book: “Watch for the Light“. These readings for Advent have been a beautiful way to connect with my faith, and has helped me move beyond what I struggle with intellectually, and into the experience and the politics and the hope of the Christmas season. I’ll be rereading this again next year I suspect.
Petition
I am about to review my year; I ask for the light to know God and to know myself as God sees me.
Most days this year when I tried to reflect on where I felt true joy, the first thing that popped into my head was Louis. The wonder of seeing a small person grow and learn and experience things and imagine.
Louis loves the playground swing. And he loves his picture books, including some which talk about space. He recently started closing his eyes on the swing and imagining his extraterrestrial journey.
Also, in November we celebrated 10 years since Anna and I met. Reflecting on a decade together has been sweet.
One moment of happy tears I’ll remember: receiving news that some of my favourite friends were moving to Perth. We’ve missed them, and haven’t built friendships quite the same back here yet. So glad to have them near again.
Where was I troubled and challenged?
On that note, something that has troubled me this year is noticing how I don’t actively invest in many friendships beyond those people I see regularly by necessity (family, workmates). In particular there was one friendship that has atrophied over the years and at the end of this year, it was heart-wrenching to realise just how dead the relationship now was. I felt awful – for my own sake, and for realising the pain I’d caused by not returning the friendship offered. One of my resolutions out of this is to get counselling and do the “inner work” that is part of repentance. (Shout out to Rabbi Danya Ruttenberg for helping make this clear to me).
There are specific steps to repentance work: 1) owning the harm perpetrated (ideally publicly); 2) do the work to become the kind of person who doesn't do harm (which requires a ton of inner work) 3) Make restitution for harm done, in whatever way possible
Another thing that has troubled me is the work culture at my work. Our company is called Culture Amp, and the thing which attracted me to the company was the mission to be successful by being a company that puts people and culture first – being a great place to work. I’ve been there three years and most of that has been great, this year has been hard though. As well as the lay-offs, there has been an unrelenting period of change, and it’s been hard. I’ve seen plenty of decisions I disagree with, and seen people I like a lot negatively impacted by them. I’m still hopeful we can get back to being a place we’re proud to work but it has been a hard year.
I was also troubled by the amount of time I was glued to my phone. With a constant stream of worldwide drama: bush fires and impeachment and a pandemic and elections – and the addictive nature of an infinitely scrolling social media feed – I spent way too much time staring at my phone (after being on my laptop 8hrs a day for work). Most weeks I’d have an average daily screen-time use of between 1-2hrs. I am troubled that it’s so addictive I do this even while hanging out with my kids. And I’m troubled by the opportunity cost – I don’t have time for friendships, for writing, for reading, for richer things, because of this.
I read this reading from Thomas Merton on December 31st 2020 in “Watch for the light”, and it felt like a perfect description of my addiction to the new news in this eventful year.
Nor are the tidings of great joy announced in the crowded inn. In the massed crowd there are always new tidings of joy and disaster. Where each new announcement is the greatest of announcements, where every day’s disaster is beyond compare, every day’s danger demands the ultimate sacrifice, all news and all judgement is reduced to zero. News becomes merely a new noise in the mind, briefly replacing the noise that went before it and yielding to the noise that comes after it, so that eventually everything blends into the same monotonous and meaningless rumor. News? There is so much news that there is no room left for the true tidings, the “Good News,” the great joy.
Thomas Merton. From Raids on the Unspeakable, 1966.
One way of bringing together all of these challenges: I live a comfortable life in an uncomfortable world. I benefit from a mix of luck and hard work and systematic privilege. And I’ve become more aware of that privilege this year. And seeing the sharp contrast between my comfort and a world in pain can be… challenging. Am I doing enough to change things? Am I there for those who need me? Am I even there for those I consider friends? Is my busyness (from work) and mind cluttered-ness (from screen time) numbing my willingness to see, and to act? Is this just part of the early-parenting stage of life? How might I get less comfortable? How might I do less sympathising and more compassion, more help? Can I love “the storm drenched“? These thoughts have been building into a challenge to myself.
Where did I pause?
I’m glad to have explicitly worked on some spiritual practices that led me to pause. The few minutes of savasana at the end of yoga, a nightly “examen” to pause and reflect, setting aside Sunday as a Sabbath day of ceasing and rest and worship, and this book of readings through Advent. None of them I followed perfectly or consistently, but between them, I did learn to pause. For longer breaks, I only took one small holiday this year, but it was a good one for pausing: in a cabin on the edge of a Karri Forest in Margaret River.
This was looking at the window one morning during our holiday stay in Margaret River.
Where did I find God in all of this?
I’ve found God in little ways, new ways, this year. As my image of God becomes less “in heaven above” and more “over all and through all and in all” I’m adjusting where I expect to find God. Less often in a religious service or book. More often in people. Or in nature. Or in silence. A new little life. The night sky. Someone willing to give up their health and freedom-of-movement to be a COVID-19 chaplain. The support from family in a time of need. Nursing a newborn in the middle of the night. And then sometimes still in the services and books from before.
Most days that I prayed the Examen, I found the Spirit of God somewhere in the day. It was usually subtle.
Response
In light of my review, what is my response to the God of my life?
The big thing in my mind is 2021 will be us parenting a newborn and a two year old – we’re not sure how we’ll balance it! As well as that I’ve got some challenges and opportunities at work (some predictable, some not), I’ve got friendships I want to strengthen, I want to keep seeking spiritual community, and I want to get some counselling to work through some of my challenges mentioned above. There’s a lot to do.
But in all of that, the spirit I want to carry, is one of having space. Creating space, and expectation, waiting to find the moments where the Spirit of God might interrupt my days. To notice the places where grace appears. Or to be willing to look on the places where inequality and injustice still dominates. Leaving capacity in my days and in my task list to look beyond my own concerns and to see the need of others, and rather than looking away, finding ways to partner with the Spirit of God to bring grace into the world. To live the kind of life that brings both justice and peace.
It’s hard to do that when rushing between zoom calls and filling spare moments with social media feeds. I want space to notice where God is at work and where grace is forming, and I want space and energy to join in and be part of it. Be that in my family, in my work, in my friendships, or the wider world.
Writing a framework: web application architectures I’m inspired by
A look at recurring architectural patterns I see in both front end and back end, that have potential to tie together into a full stack framework.
In my last post I said part of my reason for wanting to write another web framework was that I’ve been exposed to similar ideas in both the front end and back end, and wanted to experiment with an architecture that ties it all together.
In this post, I’m going to explore those: Unidirectional data flow, the elm architecture, CQRS and event sourcing. And then I’ll look at the common themes I see tying them together.
State, views, and one-directional data flow
Almost every popular front end architecture I’ve encountered recently shares an idea: you have data representing the current state of your page, and you use that state to render the view that the user can see and interact with.
If you want to change something on the page, you don’t update the page directly, you update the state, and that causes the view to update.
You might have heard this described in a few ways:
Data Down, Actions Up: the data flows down from the state to the view. And the actions come up from the view to modify the state.
Model, View, Controller: Your have a data “model” layer that holds information about the current state, and a “view” layer that knows how to update it, and a “controller” that does the communication in the middle.
Unidirectional data flow: You often hear this term in the React ecosystem. Data flows from the top of your view down into it the nested components. So a component only knows about the data passed into it, and nothing else. The data always flows downwards. How do you change the data then? As well as passing down the data from the state, we also pass down a function that can be used to update the state.
Actions Up, Data Down. Every application has “State” (data for the application) and “View” (what the user sees). The view is always rendered and updated from the current state. (We call this “Data down”). And the view can trigger actions to update the state. (We call this “Actions up”).
This pattern is used in frameworks as diverse as React and Ember and Elm. Why is it so common? Here’s some of the advantages it provides:
Each function in your code has one job: turn the state into a view, or to update the state in response to an action. This makes it nice and easy to wrap your head around an individual piece of code.
The functions don’t need to know about each other. If you have a “to-do list” app, and an action that adds a new to-do item – you don’t need to know the 3 different places it’ll show up in the UI and change them all – you just update the state. Likewise, if you want to add a new view, you don’t have to touch all the places that edit the “to-do” list, you can just look at the current state, however it came to be, and use that data to render your page.
It becomes easy to debug. If there’s a bug, you can check if the state data is correct. If the state data looks correct, then the bug will be in one of your view functions. If that state data looks wrong, then the bug is probably in one of your action functions that change the state.
It makes it easier to write tests. Your action functions test simple things: if our state looks like this, and we perform this action, then the state should now look like that. That’s easy to write a unit test for. And for your view functions, you can write tests that use mocked state data to test all the different ways your view might be rendered. You can even create “stories” with Storybook, or take visual snapshots, for quick visual tests of many different ways the UI looks.
The Elm architecture
Elm takes this concept to the extreme. By making a language and a framework that are tightly integrated, they can force you to follow the good advice from “data down, action up”.
Messages – a message triggered by the UI (like clicking a button) that has information about an action the user is requesting (like attempting to mark an item as complete)
Update – a way to update your state based on “messages”
The Elm Architecture.
State. The page has some current state that is used to render the view. We use the type system to make sure the structure of this is consistent. In this example, it might have a title “My work” and a list of tasks like “Plan week” and “Check Slack”
View. Render HTML based on the current state. Following on the example above, we might have a view function that receives our state, and calls functions to render a <h1> element and a <ul> with the list of tasks, and a form for adding new to-do items.
Html. We never manually edit HTML or the DOM, we just update state, which updates the view, and the framework checks what HTML needs changing. In the example above, this would be the rendered h1, ul and form HTML / DOM produced by the framework.
Update. The only type of events we trigger from the HTML view are strictly typed and exactly what our update function is expecting. When an action happens, the framework uses the update function to consider what the new state should be based on the previous state and the action that occurred. Following on the example, an “AddTodo” action might append a new item to the list. While the “CompleteTask” action might remove an item from the list. The only way to update the state is to use the update function, one action at a time. This makes state management easy to unit test and debug!
There is also the opportunity to interact with the outside world – things like a Backend API. Elm provides a way to do this from the Update function (which can in turn trigger new actions) but it doesn’t have strong opinions on what happens in the Backend API.
And Elm will enforce this. You can only update the view of the page via your “view” function. Your “view” function only has access to the model to decide what to render. The only actions your view can trigger are the list of messages you define. And you can only update the state in the model using your update function to change things as messages come through.
And Elm has a fantastic type system and compiler to make this all work really nicely together. To show how it works, imagine you have a “to-do list” and you have a button to mark an item as complete:
In your “view” function where you render the button, you can set an “onClick” event.
The “onClick” event will trigger a message that something has happened. You decide the names of the possible messages that can happen, so we might chose a name like “MarkToDoAsComplete”.
Because we have told Elm we have a message called “MarkToDoAsComplete”, it will force us to handle this code in our “update” function.
In our “update” function we write the code that updates the model, setting the current to-do as complete.
When a user views the page they see the button. When they click the button, the message is triggered, the update function is run, the model is updated with the to-do item now being marked as complete, and the view will update in response. By the time we did all the things the compiler asks, it all just worked.
The great thing about this is that Elm knows exactly what code is needed for all the pieces of your application to work. If you’re missing anything, it will give you a nice error message showing what to fix. This means that you never get runtime errors in your Elm code.
But even nicer than that, it means you have a great workflow:
You add your button, and a “MarkToDoAsComplete” message
The compiler tells you that message needs to be added to your list of app messages. You do that.
The compiler tells you that your “update” function needs to handle the message. You do that.
It now all works.
This “chase the compiler” workflow is what originally got me excited about the Elm language, not just the architecture – you can see Kevin Yank’s talk “Developer Happiness on the Front End with Elm” for a more detailed overview.
(As a bonus, if you do spot anything wrong, the strict framework for updating state based on actions, one at a time, allows powerful debugging tools like “time travel debugging”, where you can replay events one at a time to see their effect.)
Command Query Responsibility Separation (CQRS)
On the back end, we sometimes find a similar pattern to “data down, actions up”. It’s called “Command Query Responsibility Separation”. You separate the queries (data) and the commands (actions) into separate code paths, separate API endpoints, or even separate services.
If your back end uses an SQL database, you can think of the “queries” using SELECT statements, and the commands using INSERT or UPDATE statements.
Command Query Responsibility Separation (CQRS) encourages splitting up the “queries” (ways of reading the state) from the “commands” (ways of modifying the state). This ends up with many of the same benefits as “data down, actions up”, but for back end endpoints or services.
We use separate code paths for Commands (writes) and Queries (reads). Rather than having an API return new data after a command, we have the client repeat the full query.
And you end up with similar advantages:
Each endpoint has one job.
The endpoints don’t need to know about each other.
It becomes easier to debug.
The command endpoints and the query endpoints can adopt different scaling strategies. For example caching can be applied to the “query” endpoints.
Event Sourcing
When we talked about the Elm architecture, we saw a front end framework with a strict way to update the current state: by processing one message at a time. Event sourcing brings a similar concept to our back end, and crucially, to our data and our “source of truth”.
It’s normal for the “source of truth” in a web application to be a database that represents the current state of all of your data. For a todo list, you might have a row for each todo item, and columns to set the text of the item, whether it is complete or not, and the order it appears in the list.
That table would be your source of truth.
Event Sourcing – changing the source of truth. Traditionally in a web application the “source of truth” might be a database table that represents the current state of the application. In event sourcing, the source of truth is an event log: all of the actions that occurred, one at a time. We can use this event log to build up a view or the current state.
Event sourcing is about changing the “source of truth” to be the events that occurred. Rather than caring exactly which todo items currently exist, and if they are complete, we care about when a user created a task, or marked a task as complete, or changed the order of the tasks in a list. These are the “events”, and they are our “source” of truth.
And we can process them, one event at a time, to build up a view of the data (in event sourcing these are often called “projections” of the data). Some projections might look very similar to what we had before – a database table with a row for each todo item, a column for the item text, whether it is complete, and the order in the list.
The power of event sourcing is that we can also create other views of the data. Perhaps we want to create a trend line graph showing how many open tasks we’ve had over time. If our source of truth was the current state, we wouldn’t be able to tell you how many tasks you had open last week (or this week last year!) With event sourcing, we can go back over all of the events, and build new views of the data.
Event Sourcing allows us to create different “projections” for different ways of viewing the data.
Client actions. We can start with actions that are triggered by the user. Event sourcing as a pattern has no strong opinions on how this is handled.
Command handler. A service takes the action coming in from the client (like ticking off a task) and decides if it is allowed. If it is, it adds it to the event log.
Event log. A log of all the events that have occurred. Often this is in a database table. In the diagram above, we show 4 events: “Create Task”, with id “1” and task “Draw Diagram”. Then “Create Task” with id “2” and task “Write post”. Then “Complete Task” with id “1”. (Meaning “Draw Diagram” is complete). Then “Create Task” with id “3” and task “Clean dishes”.
Here the diagram splits into two, because rather than just having the task list, we can process the events and generate other interesting data. These “projections” are different data to derived from the same events.
We have a “Your Tasks projection” that is a database table with “id”, “task” and “complete” columns. Based on the events, Task 1 “Draw diagram” is complete, while 2 “Write post” and 3 “Clean dishes” are not. This could be used to render a traditional to-do list UI.
And we have an “Open Tasks Graph projection” with two columns, “date” and “open tasks’. It shows how for any given date, we can see how many tasks were opened. We could use this t draw a trend line graph.
Similar to the front end with actions and state, this also opens up some powerful debugging options. We can replay the events and “time travel” to see exactly how our system responded, and look out for points where things may have gone astray.
Bringing it together: the common concepts Iwantmy “Small Universe” framework to draw on
You probably spotted some similar themes running through the above architectures:
Keeping code to fetch data and code to process actions separate
Having a way to get the “current state” for a page from our data
Always rendering the pages based on that current state
Allowing the views to trigger actions or “events”
These events being tracked, and considered our source of truth
Responding to one event at a time to update our application data
Following these allows us to write code which is simpler – each function is focused on either fetching data for the current view, displaying the current view, or processing an action. That makes code easier to understand, easier to test, and simpler to debug.
Making sure our data is updated one action at a time also opens up potential for time travel debugging, which is an incredibly powerful feature for you as a developer when you’re investigating how something went wrong. It also leaves the door open for new features that you can build, being able to take full advantage of all the past user actions.
Finally, by strictly defining the shape of your state, and the set of actions (or “events” or “messages”) that are possible, you can have the framework and compiler do a lot of work for you, ensuring that if a button exists, it has an action, and the action updates the state, and the view reflects the updated state.
So you can find a very productive workflow where you start adding one new line of code for your feature, and the compiler will guide you all the way to completing the feature as valid code, and you can be relatively confident it’ll work.
So, for this “Small Universe” framework I’m starting, I am taking inspiration from these architectures to try build something that leads you to write code that is easy to write, understand, test and debug. Something that uses events as a source of truth to make it easy to build new features that process previous actions into features or views we hadn’t imagined up front. And something that leads to a happy and productive workflow, with the compiler able to provide ample assistance as you build out new features.
I’ll come back to describe the architecture I’m aiming for in a future post. But I hope this helps you understand the direction from which I’m approaching this project.
Have any questions? Things that weren’t clear? Ideas you want to share? I’d love to hear from you in the comments!
This is my idea, I thought. No one knows it like I do. And it’s okay if it’s different, and weird, and maybe a little crazy. I decided to protect it, to care for it. I fed it good food. I worked with it, I played with it. But most of all, I gave it my attention.
“What do you do with an idea” by Kobi Yamaha and Mae Besom.
I’m thinking about writing a web framework. This wouldn’t be my first time.
Why?
Primarily, because I’ve got an idea, and want to explore it. The quote and photo above from “What Do You Do With An Idea” reminded me that creativity and inspiration are muscles we can train – the more we explore our ideas with curiosity, the more the ideas will keep coming.
I want to play with code more, try out things for the sake of curiosity and experimentation and be okay with it not necessarily building toward something as part of my day-job.
I’m a software engineer that enjoys building the thing to build the thing. At Culture Amp, I’m on the “Foundations” team that builds things like the design system and our common tooling, rather than working on the main products.
Every now and then I want to build a little side project, but get paralyzed – what should I build it with? None of the existing web frameworks I look at appeal to me – I want a single framework for front end and back-end, I want a language with a good compiler, and I want something I can grasp from front-to-back, if there is magic I want it to be magic I understand.
I’ve learned a lot since I last tried this. In particular, at Culture Amp I’ve been exposed to languages like Elm on the front end and concepts like Event Sourcing / CQRS on the back end. And they’re similar and interconnected and I want to see what it looks like to build a framework that builds on patterns from all of these.
I’ve enjoyed this kind of project in the past!
(Side note: I’m aware that being in a position where I have the time and money to indulge in this is a sign of incredible privilege… I’m still learning what it means to actively tear down the unfair systems that contribute to that privilege. There are more significant things I can invest my time in for certain. But I’ll save that for another blog post 😅)
What have I tried in the past?
I once was the main developer (including doing a ground-up rewrite) of a framework called Ufront. It loosely copied MVC.net on the backend, but could compile to several backend languages (thanks to Haxe). The killer feature was that you could re-use code – routing, controllers, views, models, validators – on the front end, and have seemless compiler help when calling backend APIs from the Front End.
To this day I haven’t seen another framework attempt that level of back-end front-end integration, with the possible exception of Meteor. (Admittedly, I haven’t been looking for a while). I feel this tried to be too many things – being a generally useful backend, as well as a front-end integration layer, as well as an ORM, and Auth system, and more. At the end of the day, with the majority of the development coming from me, it didn’t have momentum for such an ambitious scope. I did build two useful education apps with it though!
I also attempted a more tightly scopoed project that never got off the ground, called “Small Universe“. I started this around the time I was interviewing for Culture Amp, and it was heavily influenced by Kevin Yank’s talk “Developer Happiness on the Front End With Elm“. (I now work with Kevin at Culture Amp). The idea was to have a clear data flow for a small “Universal Web App”. The page can trigger actions. Actions get processed on the back end. The back end can generate props for a page. Then the props are used to render a view. Basically, the Elm architecture but with an integrated back end / API layer.
I liked this a lot, and built out quite a prototype, but haven’t touched it in over a year. I like this scope of “small, opinionated framework to give structure to a universal web app”.
The first prototype I built integrated with React on the client, which I think I’d skip this time. I also think I’d go further with the data flow and push for event-sourcing (I didn’t know the terminology at the time, but I’d implemented CQRS without Event Sourcing).
I also liked the name, and think I’ll reuse it! “Small Universe” spoke to it being a framework for “universal web apps”, where code is shared seamlessly between client and server. And also it being “small” – giving you all the building blocks for an entire app in a tight, coherent framework that is easy to build a mental model for.
So am I going to do this?
I think so! I’m interested in having a project, and “working out loud” with blog posts alongside PRs to explore the problems I’m trying to solve and the approaches I’m experimenting with.
I don’t think it’ll necessarily become anything – and there’s a good chance I’ll not follow through because life gets busy (my wife and I are expecting a second child next month 😅) but I’m interested in sharing my initial thoughts and seeing where it goes from there.
What am I optimizing for?
Scribbles from my iPad as I explored what I’m optimising for. (The section below is derived from this).
My own learning, curiosity and practice. (See “Why” above)
An Elm like workflow, but full stack. Elm has this great workflow where you can create a new button in your view. The compiler will ask you to define an action for the button. Once you define an action (like `onClick save`) the compiler will ask you to write an “update” handler for when that action occurs. When you do that you’ll write the code to handle the save. You start with the UI, and then the compiler guides you through every step needed to see the feature working. By the time the compiler has run out of things to say, your front end probably works. I want the compiler to provide that experience, with guidance, hints and safety to build features across the front and back end stacks.
Clear flow of data and logic. Every piece of logic in the app should have its place in the architecture, and it should be easy to find where something belongs. On the back end this looks like CQRS (Command Query Responsibility Separation) – having the code paths that fetch data for a page (Queries) be completely separate to the code paths that change data (Commands). On the front end this looks like separating out state management from the views – the page state should be parsed into a view function. There’s lots to dive into here, but I’ll save it for a future post.
Start small but keep options open. I want this for myself and side projects. I want something that can start small, and where the entire mental model can fit in my head. But which makes it easy to migrate to a more traditional framework, or a more advanced architecture, if the thing ever grows.
Keeping open the possibility for a host of technical nice-to-haves:
Event sourcing.
Offline client-side usage.
Multiple projections.
Server side rendering.
GDPR “right to be forgotten”.
Using Web Sockets for speedy interface updates.
Ability to have “branch previews” so you can see what a PR will look like.
And to call out some trade offs:
I’m not aiming for compatibility with React or other view layers. I think the idea I’m chasing handles data flow differently enough that it’s not worth trying to shoe-horn existing components.
I’m not aiming for micro services. For side projects I think a “marvelous monolith” is more sane. If the data is event sourced a future transition to micro services will be easier.
Not aiming to support multiple back end targets, or front ends. I’ll probably pick just one back end stack to focus on, and focus on the web (not native / mobile).
Not aiming for optimum performance. If I can write an API signature in a way that can be optimized and parallelized in future, I will, but I’ll probably do some naive implementations up front (such as updating all projections synchronously in the main thread).
Not aiming to be a general HTTP framework that can handle arbitrary request and response types. There are plenty of good tools for that job.
(Still some TODOs in here, but I’m posting anyway and hope to get back to them)
I first came across Diana Butler Bass on her Twitter account. I can’t remember how I came across her, but I’ve appreciated her voice, her tweet-thread-sermons, her perspective on current affairs and more.
So when a family member gave me a book voucher to a local Christian bookstore that didn’t seem likely to stock much I was interested in, I was stoked to see they could order in one of her books. And that’s how I ended up reading “Christianity After Religion”. When it arrived and I read the praise on the cover from Richard Rohr and Rob Bell, I hoped I was in for something good.
The main point
Since the 1960s the USA (and other western nations) have seen a massive change in how they’d describe their religious/faith life. A common line has been “I’m spiritual, not religious” and rather than being a thoughtless throwaway line, this actually captures a big part of what this shift is about.
Rather than viewing it purely as a move toward secularism, DBB argues this is an awakening – in the spirit of America’s past great awakenings. This is faith evolving, not faith disappearing.
By changing the way kinds of questions we ask when we approach a life of faith, and by changing the order in which we ask them, we can participate in this new awakening – an exciting evolution in what it means to be Christian, or even what it means to be human – and some would argue, an exciting movement of God.
Overview
The “spiritual vs religious” dichotomy isn’t describing two opposites, rather it’s a lense to understand how our people’s experience of their faith is changing.
We can broadly break experience of religion of spiritual life into three categories:
Belief – how we understand the world and it’s meaning
Behaviour – how we choose to live, and the habits which make up our life
Belonging – the sense of community and shared purpose
For each of these categories, DBB looks at how Christianity (and American Protestantism in particular) has approached this category, and the questions it has deemed most important to ask. These are the “religious” questions. She then offers alternative “spiritual” questions: ways of revisiting the same category with a different approach, focused on lived experience.
Belief
Often when we think of “belief” in the context of religion we think of doctrine. Belief in a god. Belief in the Christian bible as an authoritative text about God. Belief in the resurrection, or the virgin birth, or the 7-day creation. Some things are easy to believe in – we’re pretty sure a person called Jesus of Nazareth existed – but many are increasingly hard to take literally.
TODO: copy the questions asked
This chapter concluded with some amazing examples of Christian communities writing their own creeds. Creeds were written by communities at points in time – a point DBB made in this twitter thread that I found memorable. After reading this section of the book, I journal led and wrote out, for the first time in a long time, not a description of what I no longer believed, but a description of what I still believe.
Behaviour
When we think of “behaviour” in the context of religion, we often think of moral guidelines. Don’t murder, don’t steal, don’t drink, don’t look at porn, don’t charge interest on loans… Do look after the needy, do love your neighbour, do attend a religious service etc.
Beyond this though, a lively faith usually consists of habits, or spiritual practices, that make up the day-to-day of our life. When the purpose of such habits isn’t understood, they lose meaning, they become meaningless rituals. But when learned carefully, many habits and practices have a transformative impact on your life.
DBB uses floristry as an analogy. Her family were florists for generations, and she learned the craft by sitting in the workshop with her dad, gradually gaining the skills herself. This kind of gradual exposure, where an experienced practitioner shows you, guides you, and gives you increasingly challenging work until you are fully competent – is similar to many spiritual practices.
Another thing we can learn from this analogy, is that people are less like to simply do what their parents did. Where successive generations in her family had all been florists, she has chosen a different career, because these days, you have options. When it comes to our spiritual habits and practices and rituals… this is even more true.
TODO: copy the questions asked
Belonging
For a long time, belonging meant having an identity tightly linked to the religious community you are part of (and probably grew up in). “I am baptist” or “I am catholic” or “I’m part of Riverview Church”. There was an assumed stasis in this model: you’ve always been one of us, you are one of us, you will always be one of us. You’ve always been here, you are here, you will always be here.
But most stories of faith are journey stories: Abraham leaving the land he grew up in, Moses leaving Egypt, the fishermen leaving their nets to follow Jesus.
We need to craft a different identity that respects this journeying nature of faith. And a way of belonging that allows growth, change, pilgrimage and exile, and still offers community, acceptance and love.
A traditional approach to identity asks “who am I?”, and Christianity has encourage you to ask “who am I in God?” One of my favourite moments in this section was reframing the question: “who is God in me?” Where and how does God act in the world through my life? How can people I interact with experience God through my actions?
TODO: copy the questions asked
Reversal
After examining these three categories and asking how we can revisit them through a “spiritual” lense, DBB did my favourite thing in the book: she suggested we reverse the order we tackle these questions in the faith journey.
Rather than beginning with “belief” (you must believe in the trinity, and creation, and the resurrection, and the virgin birth, and whatever other doctrine is hard to literally believe), then progressing to behaviour (follow these moral guidelines and adopt these habits) and then being able to experience belonging, DBB suggests we approach it the other way.
Begin with belonging: unconditional acceptance, loving community. From there learn the way of life: the habits and the choices that shape your faith (behaviour). And from here, you will begin to find your beliefs changing. You might find you believe in the resurrection after all: but it is coming from having experienced yourself countless ways where life overturns death.
By reversing the order we no longer have as our starting point adherence to a religious doctrine. Rather, we have as our starting point an experience of love and community, and the entire faith journey now takes that approach.
And when people say “I’m spiritual, not religious” – this is part of the distinction. The starting place is experience, and the whole journey is lived experience.
Awakening
The book ended on a real message of hope.
DBB looks back at the three great awakenings of the past, and in the debate about if there was/is a fourth great awakening, she joins the group who sees the social and religious change beginning in the 1960s constitutes a new great awakening. People began exploring new ways of experiencing faith, experiencing God, and this came out of, and fed back into, massive cultural changes.
She describes her college campus in the late 1970s having multiple thriving communities and chapters of people taking their faith and discipleship seriously, resulting in a bold vision for what could be in the world. It certainly felt like a religious awakening. Something new and bold and exciting was happening, and it felt like God was very active in it.
But then she returned to the campus in the 1980s, this time as faculty, and the life was gone, the diversity was gone, the experimentation and bold visions for change were gone. Replacing it where some standard Christian groups pushing a standard political/conservative agenda.
DBB paints the growing political power of the “religious right”, the “moral majority”, Ronald Reagan and co, as a pushback against the awakening – and describes how similar pushbacks have happened in past awakenings. This time however, something that began in the 1960s is continuing over half a century later… the pushback was significant, and so the change is drawn out.
In describing past push-backs, she seems to describe the rise of Donald Trump. (The book was written while Obama was still president, but the rise of tea party conservatism was evident).
It’s interesting to frame the success of conservative evangelicalism – in political power, in megachurch attendance, in mindshare – not as the awakening, but as the pushback on the real awakening. Though it uses the language of revival, and the metaphors and service structures of past awakenings, this is actually by now the old thing, and the comfortable thing, and the thing some are trying to protect from change.
But as she describes this tension between the “old lights” and the “new lights”, she describes the new light in ways that I completely identify with: for all of the struggle I’ve had with the church and structure and faith I’ve grown up in, she describes exactly the bits that I’m still holding onto, the values I hold most dear, and the hope and vision I have for what a renewed world might look like.
In reading this, I suddenly felt less like I (and those like me) are stepping away from our faith, and more like the steps we’re taking are part of a journey of renewal. It does feel like upheaval and uncertainty, but it’s not an abandoning of faith, it’s faith finding a new form to match the world we now live in.
And the world we now live in is globally connected, and past modes of tribalism over religious dogma no longer make sense when we can see the other tribes, and see that they too are human, and we can see that despite our differences the fruit is good, and so we’re learning that our religion isn’t the only way to meet God, our tree isn’t the only tree that produces good fruit – we can learn from each other, and perhaps we can discover that God has been showing up to all people in all cultures and religions. And perhaps this acknowledgement that God can show up to anyone in any culture or religion should have been more obvious to us from the beginning:
“The God who made the world and everything in it is the Lord of heaven and earth and does not live in temples built by human hands. And he is not served by human hands, as if he needed anything. Rather, he himself gives everyone life and breath and everything else. From one man he made all the nations, that they should inhabit the whole earth; and he marked out their appointed times in history and the boundaries of their lands. God did this so that they would seek him and perhaps reach out for him and find him, though he is not far from any one of us. ‘For in him we live and move and have our being.’ As some of your own poets have said, ‘We are his offspring.’Acts 17
And so every religion worldwide seems to have up-shoots of renewal at the moment. We’re seeing up close people who we’d used to consider “other”, and discovering they’re not so different. And there’s a tribalistic pushback, but in many ways, this renewal is underway and somewhat unstoppable. Any way of faith which defines at the outset that only some experiences are “valid” and “true” is brushing up against our lived reality that we’re finding God in all aspects of life, on many different and intersecting paths.
And this is where we can join in. By joining (or forming) communities. By embracing spiritual practices that lead us to experience God, to love others, and to grow in maturity, and by allowing our beliefs to be formed by the experience of God among us – we can be part of this renewal.
It won’t be the last time humanity’s relationship with the divine God needs to adapt and evolve. It’s not the last awakening. It’s not necessarily the greatest awakening. But it’s our generation’s awakening, and our chance to be part of it.
Hi 👋 I’m Jason. I’ve been a remote worker since 2016. Full time remote since 2017, and managing a team remotely since 2018. With people across the world suddenly finding both themselves and their teams homebound, I thought it might be a good opportunity to share some of the things I’ve found helpful as a remote team lead. I work at Culture Amp, a software platform that helps organisations take action to develop their people and their culture. We have a collection of “inspirations” – ideas you can copy in your organisation to improve its culture. I’ve followed the basic format here.
Facilitating good meetings requires having a bunch of tools in the toolkit to make sure everyone gets a chance to speak, people are understood, and it is a valuable use of people’s time. The tools you’ll use for video meetings are slightly different, so it’s worth getting familiar with them.
Why?
Video meetings present slightly different challenges: there can be poor connection quality, non-verbal communication is limited, it’s more likely people will attempt to multitask, and less likely you’ll know if they are, and there’s no obvious “clockwise” direction to go around the room when seeking everyone’s input.
Instructions:
Here are some tools to add to your toolkit:
Recreate “going around the room” to let everyone have a chance to share. You can do this by having the first person to share choose who goes next. As each person shares, they choose who goes after them. This is a good technique for “stand-ups” and other similar status update meetings.
Use hand gestures to signify you would like to speak next. Because of the slight delay on video calls, when multiple people want to speak up it’s hard to not speak over each other. Rather than wait for a gap in conversation and jump in, signify you would like to speak next by raising your hand with one finger up – you’re first in line to speak. If a second person also wants to speak, they can raise their hand with two fingers up. Usually a group learns this system quickly but it’s important the facilitator respects the order.
If people have noisy surroundings, ask them to mute unless speaking. If someone on the call is in an open plan office, is working from a cafe, has children nearby or even noisy animals outside, these can all make it harder to hear the person speaking. Encouraging people to mute by default makes it easier for everyone to hear.
Encourage everyone to have video turned on. It helps with non-verbal communication, and for someone speaking to see if they are being understood. Exaggerated head nodding, thumbs up, and silent clapping are all great ways to give feedback even while muted, but only work if the video is turned on. Exceptions can be made if the connection quality is poor, or if it is a presentation rather than a meeting.
Consider screen sharing a document that serves as both the agenda and the minutes, and editing it live. Adding a visual medium alongside the conversation helps participants keep focused and can give extra context. Taking notes and recording actions in the moment is a great way to ensure people are aligned and there aren’t misunderstandings.
Be conscious of how screen-sharing impacts non-verbal communication. Often when you start screen sharing, the other participant’s screen is now dominated by the screen share, and the faces of their colleagues are reduced to thumbnail size. This reduces the bandwidth of non-verbal communication like facial gestures and body language, and can make it easier to have your tone misinterpreted. For sensitive conversations, consider turning screen sharing off.
If you have a dual monitor setup, some products like Zoom have settings that allow the screen sharing to take up one full screen while still seeing participant faces in full size on the other screen. This is worth setting up if you can!
Use “speedy meetings” to allow time for breathing and bathroom breaks. When someone has back-to-back meetings in an office, they usually have breathing space as they move from one room to another or wait for the next group to arrive. When video calls are scheduled back-to-back the calendar can be a cruel task-master. Scheduling you meetings to run for 25 or 50 minutes (rather than 30 or 60) gives everyone a chance to breathe and can drastically reduce the stressfulness of a day. Important: if you schedule a speedy meeting, respect everyone by finishing on time.
Make space for “water cooler” talk on the agenda. Make sure the first five minutes or last five minutes of the meeting have space for the people to chat casually and catch up. In an office this often happens on the way to a meeting room, or on the way out, or around an actual water cooler. When it’s a video call, you have to be more deliberate. Make sure the agenda leaves enough space for this, and start a conversation that’s not just about work.
Hi 👋 I’m Jason. I’ve been a remote worker since 2016. Full time remote since 2017, and managing a team remotely since 2018. With people across the world suddenly finding both themselves and their teams homebound, I thought it might be a good opportunity to share some of the things I’ve found helpful as a remote team lead.
I work at Culture Amp, a software platform that helps organisations take action to develop their people and their culture. We have a collection of “inspirations” – ideas you can copy in your organisation to improve its culture. I’ve followed the basic format here.
Basic idea: Book in recurring video “hangouts” where a group of people have a chance to catch up with no set agenda.
Examples:
A team “wind down” each Friday afternoon.
A monthly “remote workers lunch”.
A fortnightly “engineer hangout” for engineers from across the organisation.
These hangouts should be optional to attend.
Why?
When teams aren’t in the same physical location, a common trap is only talking to people during set meeting times, and to only talk about the current project. Having a time to chat about anything, whether or not it’s work related – like you might in an office lunch room – is a chance to build better relationships and foster a sense of belonging.
Instructions:
Pick a group of people who would benefit from a stronger sense of community and belonging. It might be a team, a demographic, or a group with a particular role.
Find the appetite for how often people would like to meet, and for how long. In general, a range between once a week and once a month works for most groups, meeting more often the more important the relationships are. Meeting times can vary between 30 minutes and 2 hours, depending on how much of a “drop in / drop out” vibe you want.
Schedule a time! Try to find a time that is unlikely to be interrupted by other meetings, and unlikely to be highly focused time. Make sure it is within regular office hours to show that you value this type of connection enough to dedicate company time to it. For some groups it may be appropriate to book over lunch
Send an invite! Make sure attendance is optional.
During the hangout:
As the facilitator, make sure you’re online the entire time.
Greet people as they join, and introduce people who might not know each other.
It’s okay if people talk about work. It’s okay if people talk about life outside of work. It’s okay if people don’t talk and seem to be doing work on their laptops.
Ensure there is only one conversation going on at a time. If people want to start a splinter-conversation, they can start a separate video call.
It’s a line often sung in churches, and often prayed. But for people who believe in an omnipresent God – present everywhere at once – what does it mean? What’s the point in welcoming someone who is already here?
Well, there’s a difference between being present, and being welcomed. It’s an attitude thing. Are you acknowledging the person who has come, or ignoring them? Are you engaging with a defensive attitude, a judging attitude, a cautious attitude, an open attitude? Open to them being who they are, which might be different to what you hoped. Open to their thoughts, which might be different to your thoughts. Open hearted to ways their story might change you… that’s vulnerability. And the hospitality of welcome does require vulnerability. You might just come out of the encounter different.
So when you pause in a worship service to “welcome” God, it’s not about letting Holy Spirit in… that’s already happened. It’s about preparing the state of your inner world so that you’re actually open to genuine connection, even if it pushes you and changes you.
“You are welcome here”
“Whoever welcomes you welcomes me”
“Whatever you did for the least of these, you did for me”
And perhaps, we can’t welcome God unless we also welcome all God’s children. You soften your heart towards the Spirit when you soften your heart towards the people near you.
Welcome them, even if they’re not who you hoped, even if they think completely differently to you, even if it means making yourself vulnerable to connection and to change.
And don’t claim to welcome God if you’re not willing to welcome fellow humans.
This week at the UX Perth meetup I shared this talk about the human side of building design systems – how your team culture affects the design system you are building, and how the design system can affect the team culture you are building.
At Culture Amp, we operate on a “team of teams” model. We currently have about 200 staff, with about half of those contributing to the product as engineers, designers, product managers, QAs etc. Each product feature has a team responsible for it, and this team is “cross-functional” – so rather than a single infrastructure team, each team should have its own infrastructure specialist. Rather than there being a single design team, each team should have a designer.
The idea is that each team should be able to move to its own priorities without being blocked by other teams. But as you can imagine, this can lead to people being out of sync.
Designers on different teams might be making simultaneous decisions about the styling of a button, and reach two different conclusions, resulting in two button styles.
In other disciplines, like Front End Engineering, you have people from across different teams working on different products with different code-styles (and even different languages!) How do we make sure that people on different teams can produce work that is consistent, high quality, fast to build and easy to maintain?
And then within a team, how can we make sure designers, engineers, product managers and everyone else is speaking the same language, and making decisions from the same framework?
Can we avoid designers saying things like “Use Ideal Sans, size 12px, line height 18px, all caps, and maybe some tighter letter-spacing?” and instead say “Use the Label style”.
Establishing sensible defaults, and giving names to them, enables your team members to talk to each other with less confusion and ambiguity – and that clear communication helps lead to less mistakes and faster work. It also helps product managers know which styles already exist and can be used, and which ones the team needs to invest in creating from scratch.
Across the business, we want to align everyone, so that our product looks and feels consistent, no matter which team built it. And we want to speed up people in all roles on all teams, so that they can spend less effort recreating yet-another-button-component, and focus more on delivering real features that benefit our customers.
This is where design systems really shine: they give a common language that designers, PMs and engineers can use to all be on the same page. They help bring consistency in fonts, colors, styles and components to people on different teams who don’t interact often. And they give us a platform to build common, re-usable designs that can be shared across teams, enabling all the teams to build things faster and with more consistency.
How our company values interplay with our style guide efforts
So building a design system was the right call for us at Culture Amp. But how does that play out with the actual people, each with a specific role on a specific team? How does it affect our approach to work, and more importantly, to team work? How does the design system interplay with our team culture?
At Culture Amp we spend a lot of time talking about our company values, because our aim is to be “Culture First“, to focus on having an amazing work culture, working and living according to a shared set of values, and to let achievement and success arise from that culture.
So we have four values:
Have the courage to be vulnerable
Trust people to make decisions
Learn faster through feedback
Amplify others
How do these values impact our implementation of the design system? And how does our design system feed back into these values? Let’s take a look.
Trusting people to make decisions can be hard. There is a reason micro-managing is such a problem in so many workplaces. And when it comes to design systems, you often hear companies talk about introducing them precisely because they don’t trust people to make decisions. They don’t trust them to use the logo correctly, they don’t trust them to choose an appropriate header type style – so they codify the “correct” way in the style guide and make sure everyone follows it.
Dictatorial decision making doesn’t leave any space for creativity and innovation. I personally believe the most inventive things happen on the edge of a group – not in the center – and you don’t want to squash that by rigid enforcement of a system that takes away a team member’s ability to make a decision.
But more importantly – if you remove all freedom from your team, limiting the ability of your designers to design, and of your engineers to engineer better components, never allowing them to build anything new and better – they’re going to resent it, they won’t enjoy their jobs, and you won’t see their best work – their talents will be wasted.
So how do we balance the desire for consistency with the desire for freedom? Let’s take a look at some examples.
We ask everyone to trust us and stick to the palette. Meanwhile we trust them to make good decisions with how to use that palette, and don’t try to micro-manage through design reviews.
With our brand colors, we have a predefined palette of 3 primary colors (“Coral”, “Paper” and “Ink”), 6 secondary colors (“Ocean”, “Seedling”, “Wisteria”, “Yuzu”, “Lapis” and “Peach”) as well as a small number of tertiary special use colors. These base colors were decided on by designers from across the organisation coming together – it wasn’t an edict from on-high, it was a collaborative effort to unearth the color patterns already in use, and choose and standardise on those that most identified with our brand.
From those colors, we tint them (add white) and shade them (add black) to come up with nearly 300 variations you can use and still be on brand.
With defining this palette, the designers are asking us to trust them – for any text or button or border on the site, we should be able to use one of these colors.
And trust is a two way street.
In return, they can trust us engineers to make sensible choices within the palette. I know the system suggests we use “Ocean” blue for links, and I can choose the appropriate shade of Ocean depending on accessibility requirements, and make the decision myself, without needing to consult a designer.
We trust them to define a palette, they trust us to use it wisely.
We ask people to trust us and stick to these type styles wherever possible. We trust them if they say they need to deviate.
We did a similar thing for type styles, defining a range of headers, paragraph styles, labels and more that could cover most of the usages on a page. (Click here to see our type styles).
While I was giving this talk on Tuesday night I had Slack messages coming in from designers and product managers on one team talking to designers and product managers from our team – how much freedom would their team have to do what they needed for the visualisation they were designing – would they be free to explore or would they be limited to only a small palette of avialable styles?
Again, it comes down to trust. Those building the design system need to trust teams to know when and how to use it, and to know when to step outside it and try something new. If you trust that they share the same goal of great design and consistent design, then you can trust them to make the right call about when to experiment outside of the system. The work this team does may well bubble back up into the design system and become a standard for other teams to share.
One of our other values is “Have the courage to be vulnerable”.
One way this shows up in building a design system is fighting any tendancy towards perfectionism, which is common for many designers and engineers – we want it to be perfect before we share it with the world. We want it to be just right before other teams start using it.
But sometimes sharing it early, even when you still aren’t proud of it yet, or are maybe even ashamed of how it looks or how it’s built, is still a good thing, and can help someone else, even in the early and rough state.
We have a really great mock-up for our design system website with a very pretty way to demo components. But we have to be okay with sharing the ugly version so people can start using it now.
This showed up with launching our design system website, www.cultureamp.design. Parts of it look nice, but no where near as nice as the mock ups. There are designs so beautiful and so on-brand that we really wanted to share them with the world. But perfect can be the enemy of good, and at the end of the day, we had to share this with out team rather than keep it a private secret. We got over our insecurity, and started sharing it, and people have found it useful, even if there’s so much we wish we could improve.
Moving fast and not waiting for perfection means making mistakes, like me needing to make a breaking API change because of a spelling mistake.
This has applied to the components we build as well as the website we use to showcase them. In the interest of moving faster and being less precious, I got excited and shipped a new dropdown component, including the ability to add a “seperator” to the menu. Not a “separator”. Yes I shipped a version of our design system with a spelling mistake, and fixing that was a breaking change, immortalised forever as a version bump in our CHANGELOG.
Putting yourself out there isn’t only about sharing your work early. It’s also about opening up the possibility for them to criticise the work you’ve done. Sometimes asking for feedback gives you feedback you didn’t want to hear.
We did this when our team, who are the main drivers of the design system, asked designers and front-end engineers from across the company for feedback on how we’re going.
A visualization of the comments we received when we asked for feedback on how our team was going
Often we talk about user experience and user centered design, but with design systems, we have two classes of users: the end users of our product, and our colleagues who use the design system to build the product. Taking the time to listen to this second group, our colleagues and team-mates, is crucial.
And it ties into one of our other company values: Learn faster through feedback.
One key thing we learned through this survey was that we’d been over-investing in the base level styles (typography, color, icons) and underinvesting in the mid-level components (for example drop down menus, tabs, and select boxes).
We spent all our time on Styles, but the feedback showed we would be more helpful if we built more ready-to-use components.
Our team had been focusing on bringing consistency at the low level – changing typefaces and background colors and icons across the app, which was an enormous amount of effort on our part. But what would have helped the other teams more is if we built components that helped them deliver their designs faster. It might mean it would take longer to bring consistency to some of these fundamental styles, but it would mean that these teams are delivering valuable features to customers sooner.
That message came through our survey, loud and clear.
And at the end of the day, that ties into our fourth value:
Amplifying others. That’s the reason we’re building a design system in the first place – it allows us to amplify each of the product teams in our company, allowing them to move faster, stay in sync, spend less time sweating the fine details – and deliver a higher quality and more consistent experience to our customers.
That’s what it’s all about – and if we keep this in mind while we build out our system, it can help keep the work grounded, practical, and more likely to make an impact.
It isn’t about having the prettiest showcase of components. It isn’t about the elegance of your solutions, or the way you ship new components to your teams. At the end of the day, it’s about the people in your teams, and how you can amplify them, so they can build better products, faster, and with less stress.
And if amplifying your workmates does not motivate you, then you might have bigger team culture issues that a design system is not going to fix!
Have any questions? Feedback? Other observations on how team culture and design systems interplay? I’d love to hear them!
Adding the `filter: grayscale(1)` CSS rule is an easy way to notice places your design is too dependent on colour
This is the blog post version of a talk I gave at the Perth Web Accessibility Conference. I also repeated the talk at a “BrownBag” team lunch at Culture Amp, which you can watch here, or you can read the blog-post version below. I’ve got a live example (open source! try it yourself!) at the end of the post.
On the front-end team at Culture Amp, we’ve been working on documenting and demonstrating the way we think about design, with a design system – a style-guide and matching component library for our designers and developers to use to make our app more consistently good looking, and more consistently accessible.
But first, a story.
Here’s a photo of me, my older sister, and younger brother:
Me at the back, my sister and brother in the front
Me and my brother are both red-green color blind. Most of the time color-blindness isn’t a big deal and compared to other physical limitations, it doesn’t usually make life difficult in any significant way.
But growing up, my brother Aaron really wanted to be a pilot. Preferably an air-force pilot, like in Top Gun. But for a generation that grew up with every TV show telling us “you can be anything if you try hard enough”, there was a footnote: anything except a pilot. He couldn’t be a pilot, because he was red / green color blind. The air-force won’t even consider recruiting you for that track. They’ll write you off before your old enough to join the air cadets.
Why? Because the engineers who designed the cockpits half a century ago made it so that the only way you could tell if something changed from safe to dangerous was if an LED changed from green to red. So people with red-green color-blindness were out, and my brother was told he couldn’t be a pilot.
Cockpits have lots of small controls, and some of them rely purely on red/green color distinction to be read accurately.
Now, becoming an air-force pilot is super-competitive, and he might not have made it anyway, but to have your dream crushed at the age of 10, because an engineer built a thing without thinking about the 8% of males who are red/green color blind, is pretty heartbreaking.
Luckily, as web professionals we’ve got a chance to create a digital world that is accessible to more people, and is a more pleasant experience, than much of the real world. We just have to make sure it’s something designers and developers are thinking about, and something they care about.
So, design systems
One of the big lessons we’ve learned in the web industry over the last few years is that if you want your site, product or service to leave a lasting impression, it’s not enough to do something new and shiny and different. What’s important to a lasting impression is consistency: consistency builds trust, and inconsistency leads your users into confusion and frustration and disappointment.
It’s true of your branding, it’s true of your language and tone, it’s true of your information architecture, and it’s especially true of your commitment to creating accessible products and services. For example if your landing page is screen-reader friendly but your product is not, you’re going to leave screen-reader users disappointed. Consistency matters.
But as a company grow, consistency gets harder. It’s easy to have a consistent design when you have a landing page and a contact form. It’s harder when you have a team of 100 people contributing to a complex product.
The Culture Amp team has experienced those growing pains – we’ve grown from 20 employees three years ago to over 200 today, almost half of them contributing to the product – and it’s easy to lose consistency as users navigate from page to page and product to product. The UI built by one team might feel different and act differently to the UI built by another team.
So we started looking into design systems.
The Salesforce “Lightning Design System” showed how a strong design system can bring consistency to a whole platform, even with 3rd party developers
Design systems are a great way to bring consistency. By documenting the way we make design decisions, and demonstrating how they work in practice, we can help our whole team come together and make a product that looks and feels consistent – and that consistency is the key to a great experience for our users.
As we codify our design thinking we are lifting the consistency of our app – not just of our branding and visual aesthetics, but of our approach to building an accessible product.
Culture Amp’s approach to color
So we’re a start-up, with three overlapping product offerings build across half a dozen teams. And we want to make that consistent.
One way to do that would be to have a design dictator who approves all decisions about color usage, making sure they’re on-brand and meet the WCAG contrast guidelines. But one of our company values is to “Trust people to make decisions”, and that means trusting the designers and front-end engineers in each team to make the right call when it comes to picking colors for the screens they are in.
How do we let them make the call, but still ensure consistency?
Well, as a group our designers worked together to define the palette they would agree to use. They consisted of three primary colors (Coral, Paper and Ink), six secondary colors (Seedling, Ocean, Lapis, Wisteria, Peach, Yuzu), as well as Stone for our standard background.
Our color system starts with 3 primary colors and 6 secondary colors. I have no idea how the team picked the color names…
Every color on the page should be one of the colors on the palette.
But what about when you need it slightly lighter or slightly darker? When you need more contrast, or want just a slight variation? We allow designers to use a color that is derived from the original palette, but with a tint (white mixed in) or a shade (black mixed in).
We can actually figure these tints and shades out programmatically, using SASS or Javascript:
(The embed here demonstrating programmatically generating colour palettes no longer works, sorry)
(Note: the SASS code is even easier. You can use the lighten() or darken() functions, or the custom mix() function if you’d prefer to tint or shade with a custom color. All three of these functions are built in.
So now we have three primary colours, and six secondary colours, and computationally generated tints and shades for each in 10% increments, resulting in 171 colour variations, which all fit with our brand. Woo!
By adding tints and shades to our base colors, we can generate a flexible but consistent color palette
This range gives enough freedom and variety to meet individual teams needs on a page-by-page basis, while still bringing consistency. Designers are free to move within this system and make the right decision for their team.
So what about color contrast?
Currently Culture Amp has committed to complying with WCAG AA standard contrast ratios. This means the contrast between the text color and the background color must be at least 4.5 for small text, and at least 3.0 for large text. (If we wanted to go for WCAG AAA standard contrast ratios, those values 7.0 and 4.5 respectively).
How do we get the designers and developers on our team thinking about this from the very beginning of their designs? We could audit after the designs after-the-fact, but this would be frustrating for designers who have to revisit their design and re-do their work. Making people re-do their work is not a way to win friends and advocates for your color contrast cause.
<Note: I had an embed here, that demonstrated auto-generated colour palettes, but it no longer works>
So we can actually check whether our colors will be able to hold white or black text with a sufficient contrast ratio. And because we derive our color values programmatically, we can check if all 171 of our derived color values are accessible with large text or small text, black text or white text, and display all of that information at a glance:
We can programmatically check contrast, and show at a glance which colors support white text or black text at small and large sizes.
Now our designers can come to this page, explore every color within our palette, and at a glance know which of these colors will be able to display text with sufficient contrast to be considered accessible.
For bonus points, we can also programmatically determine if a background color would be better suited to have text colored white or black:
<Note: I had an embed here, that demonstrated auto-generated colour palettes, but it no longer works>
If you build it, they probably won’t come
So we’ve made a great page where designers can explore our palette colors, and at a glance gain an understanding of which combinations will have sufficient contrast. But by this point everyone in the software industry should hopefully know that “if you build it, they will come” is simply not true. If you want people to engage with your design system – or with anything you’ve built – you need to offer something of value, you need to solve a real problem for them.
So how do we get the designers and developers across our different teams to care enough to come look at this page? We need to offer them some convenience or solve a problem they have.
What are the most common things our team needs help with when thinking about our brand colors? They usually want to explore the range of the palette, and then find a HEX code or a SASS variable to start use that color.
People on the team need to know what the brand colors are. Now we can send them to this page, and they’ll see the accessibility info as a bonus.
We have a dropdown that lets our team copy/paste the colour values so they can use them in their design tools or their code
So we tried to make our design system colors page as helpful as possible, providing a way to explore the colors, see the shades and tints, see what colored text it best pairs with, and copy color values to your clipboard.
Next time someone needs to reference our brand colors, this feature set means they’ll come to our design system page first, because they know they can explore the colors, and get the correct codes in whatever format they need. We’re solving a problem for them, and, while we have their attention, using the opportunity to inform get them thinking about color contrast and accessibility.
What else?
So we’re just getting started on our journey of using design systems to improve the consistency of our design and our accessibility. But color contrast is a great place to start, and it’s already making me think about how we can use the design system project to put accessibility front-and-center in the design culture of our team.
The web’s most popular component library, Bootstrap, solves a problem for designers and developers by allowing fast prototyping of common website elements, but by offering components with accessibility concerns baked in, and by encouraging good accessibility practice in their documentation, they’ve used their design system to lift the level of accessibility on millions of websites.
Bootstrap was one of the first open source component libraries, and works hard in its documentation to encourage accessible use of its components.
If you have other ideas on how design systems could be used to bake accessibility into your team culture and product design, I’d love to hear about it! It’s an exciting project to be part of, raising the design consistency and the accessibility consistency across the various products offered at Culture Amp.
If you’d like to join us, Culture Amp is hiring front end developers – either in Melbourne, or remote within Australia. It’s an amazing place to work, I’d encourage you to apply. See the Culture Amp Careers page for more info.
Bonus #1:
Our whole Color Showcase component is now available open source. You can view the Color System Showcase repo on Github or even try embed it online by entering JSON code on this page. (Sorry, this link no longer works).
Here’s a live iframe preview with Culture Amp colors inserted:
Bonus #2:
If you want to test how your site would look to a completely color-blind person, you can type this into the browser console:
document.body.style.filter="grayscale(1)";
Try it!
Adding the `filter: grayscale(1)` CSS rule is an easy way to notice places your design is too dependent on colour
I’ve been using Haxe for a long while, and for about 2-3 years I was using Haxe full time, building web applications in Haxe, so I know how important managing your dependencies is, and I know how painful it was with Haxelib, especially if you had a lot of dependencies, a lot of projects, or needed to collaborate with people on different computers.
Haxelib is okay when you’re just installing one or two libraries, and they’re libraries with stable releases where you don’t change versions often, and if you don’t need to come back to your code after long gaps in time. Basically, haxelib is fine if you’re doing weekend hackathons or contests like Ludum Dare where your projects probably aren’t too complex, you’re not collaborating with too many other people, you’re using existing frameworks, and you don’t have to worry about if it will still work fine in 4 months time. Otherwise, it can be quite painful.
I tried to help with Haxelib at one point in time (I still am in the top 4 contributors on Github, most of that was back in 2013 though), but it proved pretty unruley – even skilled developers were afraid of changing too much or refactoring in a way that might break things for thousands of developers. And some changes were impossible to make without first changing the Haxe compiler. So it’s largely sat in the “too hard” basket and has not had many meaningful improvement since it first became it’s own project in 2013.
(No offense to anyone who has been working on it – you are a braver soul than I! But I think we all agree it’s not as good as it needs to be.)
Since mid 2016, I have been working in other jobs where I don’t use Haxe full time, instead spending more time with JS: using tools like NPM, Yarn, Webpack. And they’re certainly not perfect when it comes to dependency management, but there are a few things that they do right (Yarn especially).
Part 2: What the JS ecosystem gets right.
In Node JS land (and eventually normal JS land), there was a package manager called NPM – Node Package Manager. It had a registry of packages you could install. It would also let you install a package from Github or somewhere else. The basic things.
Here’s what I think it did right:
Used a standard format (package.json) to describe which packages a project uses.
Put all of the libraries in a standard location (node_modules/${my_cool_lib}/)
NodeJS didn’t care if you used NPM or not. As long as your stuff was in node_modules, it would be happy.
Why was this a good move? Because it allowed some talented people to build a competitor to NPM, called Yarn. By having simple expectations, you can have two competing package managers, and innovation can happen. Woo!
Yarn is what I use at work on a big project with 119 dependencies (and about 1000 sub-depedencies). Here’s what yarn did right:
Reproducible builds. While package.json has information about which version I want (say, React 16.* or above), Yarn would keep information in a file called yarn.lock which says exactly which version I ended up using (say, React 16.0.1). This was when my friend joins the project and tries to install things she won’t accidentally end up on a newer or older version than me – Yarn makes sure we’re all using exactly the same version, and all of our dependencies and sub-dependencies are also exactly the same.
A global cache. When Yarn came out, it was several times faster than NPM on our project because it kept a cache of dependencies and was able to resolve them quickly when switching between projects and branches. NPM has caught up now – but that’s the benefit of competition!
Part 3: Introducing lix (and its friends: switchx and haxeshim)
In 2015 I remember chatting to my friend Juraj Kirchheim (also one of the key contributors who just kind of gave up) about what an alternative might be, and he described something that sounded great, a futuristic utopian alternative to haxelib.
2 years later, and it turns out, it’s been built! And it’s called “lix”.
(What’s with the name? I’m guessing it is short for “LIbraries in haXe”, a leftover from when every Haxe project needed an X in it for cool-ness, and Haxe was spelt as haXe. That, and the lix.pm domain name must have been available).
Lix also depends on two other projects: haxeshim and switchx. The names aren’t super obvious, so here is my understanding of how it all works:
Haxe Shim intercepts calls to Haxe and does some magic. The Haxe compiler on it’s own explicitly calls haxelib, so you literally can’t replace haxelib without intercepting all calls to the compiler and getting rid of -lib arguments. So haxeshim is a shim that intercepts Haxe calls and sorts out -lib arguments so that haxelib is never needed.
As a bonus, it also supports switching to the right version of Haxe for the current project. But for that, we also need “switchx”.
SwitchX lets you pick the Haxe version you need for your project, and automatically switches Haxe versions for whatever project you’re in. If you change between project A, on Haxe 3.4.3, and project B, in a different folder and running Haxe 4, it will always use the correct one.
How?
When you start a project you run switchx scope create. This makes a .haxerc file which says that this folder is a specific project, or “scope”, and should use the Haxe version defined in the .haxerc file.
How do you change the version?
You run switchx use latestor switchx use stable or switchx use nightly or switchx use 3.4.3 etc. It lets you instantly switch between different versions, and for the correct version to always be used while you’re in your project folder.
Nice!
Lix is a package manager that you use to install packages. It is made to work with Haxe Shim, and creates a “haxe_libraries” folder, with a new hxml file for each dependency you install. It’s super fast because it uses a global cache (like yarn) and it makes sure you always have the correct version installed (like yarn). It supports installing dependencies from Haxelib, Github, Gitlab or HTTP (zip file). Anytime you update or change a dependency, one of the haxe_libraries/*.hxml files will be updated, you commit this change to Git, and it will update for all of your coworkers as well. Magic.
These tools are (for now) built on top of NodeJS, so you can install them with NPM or Yarn.
If you want to install each of these, you basically run these commands (warning: these will replace your current Haxe installation):
# Install all 3 tools and make their commands available.
yarn global add haxeshim switchx lix.pm
# Create a ".haxerc" in the current directory, informing haxeshim that
# this project should use a specific version of Haxe and specific
# `haxe_libraries` dependencies
switchx scope create
# Use the latest stable version of Haxe in this project.
switchx install stable
Part 4: What lix can do that haxelib cannot do (well).
With this setup, here’s what I can do that I couldn’t do before:
Be certain that I always have the exact right version installed, even if the project is being set up on someone else’s machine. Even if I pulled from a custom branch, using something like lix install github:haxetink/tink_web#pure (install the latest version of tink_web from the “pure” branch), when I run this on a different machine, it will use not only the same branch, but the exact same commit that it used on my machine, so we will be compiling the exact same code.
Easily get up and running on a machine where they don’t even have haxe installed. I tried this today – took a project on Linux, and set up its dependencies in Lix. It used a combination of Haxelib, Github, Gitlab, and custom branches. It was a nightmare with Haxelib. I also added haxeshim, switchx and lix.pm as “devDependencies” so they would be installed locally when I ran yarn intall. I opened a Windows machine that had Git installed, but not haxe, cloned the repo, and yarn install. It installed all of the yarn dependencies, including haxeshim, switchx, and lix, and then running lix download installed all of the correct “haxe_libraries”, and then everything compiled. Amazing!
Know if I’ve changed a dependency Today I was working on a change for haxe-react. In the past I would have used haxelib dev react /my/path/to/react-fork/. Now I edit haxe_libraries/react.hxml and change the class path to point to the folder my fork lives in. The great thing about doing this is, Git notices that I’ve changed it. And so when I go to commit the work on my project, git lets me know I’ve got a change to “react.hxml”, I’ve changed that dependency. In this case, I knew what to do: push my fork to Github, and then run lix install gh:jasononeil/haxe-react#react16 to get Lix to properly register my fork in a way that will work with my project going forward. I then commit the change, and people who use my project will get the up-to-date fork.
Start a competing package manager The great thing about all of this, is that “lix” has some great features, but if I want to write better ones, I can. Because of the way “haxeshim” just expects dependencies to haxe a “haxe_libraries/*.hxml” file, I could write my own package manager, that does things in my own way, and just places the right hxml file in the right place, and I’m good to go. This makes it possible to have multiple, competing package managers. Or even multiple, co-operating package managers.
Part 5: Vote on the future
So, I think Lix has learnt from a lot of what has gone “right” in the NodeJS ecosystem, and built a great tool for the Haxe ecosystem. I love it, and will definitely be using it in my Haxe projects going forward.
The question is, do we really need “haxeshim” and “switchx” and other such tools just in order to have a competing package manager? For now sadly, because of the way haxe and haxelibare tied at the hip, you do need a hack like this. But there’s a discussion to change that. (See here and here).
If you care about Haxe projects having maintainable dependency management, you can help by voting up comments in a discussion that’s happening right now. Here are the comments that I think will help Haxe support something like Lix, and more competing package managers, as first class citizen going forward. Feel free to upvote with a thumbs up emoji:
Feel free to have a look and contribute to the discussion. For now though – if you don’t mind installing haxeshim and switchx, there is a very good solution for managing your haxelibs and dependencies in a reliable, consistent, but still flexible way. And it’s called Lix.