Songwriting in the A.I. Age

I’m a member of the 12 Song Challenge community, a bunch of people all over the world who help support each other in the art and craft of writing songs for use in our local churches. It’s run by the people at Resound Worship, and I’ve found it to be a wonderful source of inspiration, friendship, and challenge.

Literally a challenge. Each month a songwriting challenge is set, based on a broad theme such as “Songs from the book of Acts” or “Happy Songs”. In November 2024 we were challenged to write songs with the assistance of “Artificial Intelligence”.

Hmm.

I have two problems with this.

I Don’t Believe A.I. Means What You Think It Means

While there’s a lively ongoing debate about what Artificial Intelligence (A.I.) even is, the term is incredibly popular at the moment. However, half the words in it (i.e. “intelligence”) are – at best – misleading. A.I. proper covers a wide range of computer-based systems, but most of the time on The Internet people use it to refer to systems that generate stuff from prompts – images, text, audio, or even – as we shall see – music. My gut feeling is A.I. has become popular as a term because a more specific term – for example A.G.S.P.O. (“Artifical Generation of Statisically Probable Outcomes”) – isn’t as easy to say.

The Cloud Is On The Ground

Second, people interact with A.I. systems through websites, often whimsically designed. It’s fun! Easy! And all in The Cloud. Except the cloud isn’t some abstract idea. It is real data centres, running real computers, containing real graphics processors, which require real energy to run, and real water to cool. The explosion in the popularity of A.I. tools – so much so that GPU manufacturer Nvidea became the world’s most valuable company in June 2024.

This reality is a problem. First, there is the mining of materials to produce the chips needed. Secondly, the emissions produced during the manufacture of these chips. Third, the emissions produced by the data centres themselves while running A.I. workloads. And fourthly, the use of water to cool these cips which run very hot. All of that is a problem because at the time we need to drasically reduce manufacturing, consumption, and emissions to help limit the man-made rise in global temperatures, we’re running gleefully into an A.I. future. And for what? Will the price that future generations pay be considered worth it?

Gerry McGovern has been writing about this stuff for years.

So, what do we do?

There’s no putting the A.I. genie back in the bottle. As A.I. tools become more prevalent I hope that more efficient ways are found to generate the energy and perform the cooling required. But I’m not hopeful that will happen fast enough to make a difference to the rapidy rising global temperature.

As Gerry McGovern [almost] says: we don’t have an [energy] production problem, we have an [energy] consumption problem.

The A.I. Challenge

With all that said, I had a songwriting challenge to do. Rather than boycott the entire thing (which was an option I considered) I wanted to use A.I. but keep my use of it to a minimum. I’d heard before that these tools work best when incorporated as part of a human-driven workflow.

As I’ve always found lyrics more challenging than music, I thought I’d start there.

Using ChatGPT for lyrics

I had already decided I wanted to write a song about the wisdom of God being infinetely better than the wisdom of man. Partly because I wasn’t aware of any songs specifically about that, but mostly because I wanted to make a small protest. So my initial prompt for ChatGPT was:

Write a modern worship song about the wisdom of god compared with the wisdom of man. Include descriptions of wisdom as being a voice crying out. Include the idea of wisdom being patient and gentle.

The response from ChatGPT was predictably naff, but was a starting point:

Title: The Voice of Wisdom

Verse 1
In the stillness, I can hear,
A gentle whisper drawing near.
The wisdom of the world so loud,
But Yours, O Lord, it stands unbowed.

Chorus
Wisdom, crying out in the night,
Patient and gentle, guiding with light.
While the shadows of man may sway,
Your truth, O God, will lead the way.

Verse 2
In the clamor, I find my peace,
Your voice, my heart, it will release.
The fleeting thoughts of human pride,
Fade away when You abide.

Chorus
Wisdom, crying out in the night,
Patient and gentle, guiding with light.
While the shadows of man may sway,
Your truth, O God, will lead the way.

Bridge
So I’ll lean on Your understanding,
In the quiet, Your grace expanding.
Teach me patience, teach me grace,
To find my strength in Your embrace.

Chorus
Wisdom, crying out in the night,
Patient and gentle, guiding with light.
While the shadows of man may sway,
Your truth, O God, will lead the way.

Outro
In every choice, in every sigh,
I’ll follow Your voice, I’ll lift my eyes.
For the wisdom of man may come and go,
But Your steadfast love will always grow.

I felt it could do better, so said:

Amend the song to include references about God’s ways being higher than human ways, and his understanding far beyond ours. Use analogies from nature.

And I got this:

Title: The Voice of Wisdom

Verse 1
In the stillness, I can hear,
A gentle whisper drawing near.
The wisdom of the world so loud,
But Yours, O Lord, it stands unbowed.

Chorus
Wisdom, crying out in the night,
Patient and gentle, guiding with light.
Your ways are higher, like mountains soar,
Your understanding opens every door.

Verse 2
In the clamor, I find my peace,
Your voice, my heart, it will release.
As rivers flow beneath the sky,
Your wisdom, Lord, will never die.

Chorus
Wisdom, crying out in the night,
Patient and gentle, guiding with light.
Your ways are higher, like mountains soar,
Your understanding opens every door.

Bridge
So I’ll lean on Your understanding,
In the quiet, Your grace expanding.
Teach me patience, teach me grace,
To find my strength in Your embrace.

Chorus
Wisdom, crying out in the night,
Patient and gentle, guiding with light.
Your ways are higher, like mountains soar,
Your understanding opens every door.

Outro
In every choice, in every sigh,
I’ll follow Your voice, I’ll lift my eyes.
For the wisdom of man may come and go,
But Your steadfast love will always grow.

OK, better, but not quite there yet. I wanted to make it sound a little less formal and hymn-like, as many modern worship songs have a more fluid syllable structure. So I said:

Make the number of syllables for each line in the verse different.

But ChatGPT seemed to latch on to “number of syllables” and added those to the end of each line while making minimal changes:

Title: The Voice of Wisdom

Verse 1
In the stillness, I can hear, (8)
A gentle whisper drawing near. (8)
The world’s loud wisdom, oh so proud, (9)
Yet Yours, O Lord, stands unbowed. (7)

Chorus
Wisdom, crying out in the night, (8)
Patient and gentle, guiding with light. (9)
Your ways are higher, like mountains soar, (9)
Your understanding opens every door. (9)

Verse 2
In the clamor, I find my peace, (8)
Your voice, my heart, it will release. (8)
As rivers flow beneath the sky, (8)
Your wisdom, Lord, will never die. (7)

Chorus
Wisdom, crying out in the night, (8)
Patient and gentle, guiding with light. (9)
Your ways are higher, like mountains soar, (9)
Your understanding opens every door. (9)

Bridge
So I’ll lean on Your understanding, (9)
In the quiet, Your grace expanding. (9)
Teach me patience, teach me grace, (8)
To find my strength in Your embrace. (8)

Chorus
Wisdom, crying out in the night, (8)
Patient and gentle, guiding with light. (9)
Your ways are higher, like mountains soar, (9)
Your understanding opens every door. (9)

Outro
In every choice, in every sigh, (8)
I’ll follow Your voice, I’ll lift my eyes. (9)
For the wisdom of man may come and go, (10)
But Your steadfast love will always grow. (9)

I tried a couple more times, but ChatGPT wasn’t going to improve this, and my A.I. prompt skills are minimal, so I took the lyrics above and used them as a starting point. These are the lyrics I actually wrote, you can see the similarities with what ChatGPT generated.

Verse 1
When the inner voice is loud
And vain desires are shouting out
I think that I can do it all myself
After striving to the end
I find I’m at the start again
I know I need your wisdom and your help

Chorus
Your wisdom is calling
Your wisdom will guide us
Your words like a friend who walks close beside us
Your ways are far higher
Your love beyond measure
We’ll trust in your goodness forever

Verse 2
In the stillness I can hear
A gentle whisper drawing near
It speaks of love too vast to comprehend
In Your mercy I find peace
Your grace will bring my soul release
You know me better than I know myself

Bridge
So I’ll lean on Your understanding
Your ways are higher than I could imagine
Teach me patience, teach me grace
Help me always walk your ways

These lyrics aren’t going to win any awards (I told you I wasn’t good at them) but I have to admit I wouldn’t have got this far so quickly without a kick-start by ChatGPT. So maybe that’s something I can use in the future.

Using Suno for music

One of the most astounding pieces of technology I saw this year was Suno. This A.I. tool takes prompts – you can select musical styles or other prompts, and optionally give it lyrics – and it will generate music, with vocals. The recording quality is pretty terrible, but you do get a fully-produced track. Guitars, drums, bass, keyboards, synths, melodic bits, vocal, the lot. Pretty incredible.

So, I posted my lyrics in, along with the prompt:

Contemporary worship, medium tempo, big build, compressed piano, toms, male vocal

And after a few seconds wait I got this:

Actually, I got two songs – Suno always gives you two options. This was the one I liked better, but interestingly, the verse sounds like it’s ripped off a song by David Brackenbury (another 12 Song Challenger). That’s either a huge coincidence, or there’s something really freaky going on.

The melody isn’t great, there are some things I’d change immediately, and the chords are too predictable for me. But as a start, this is really good.

Conclusions

Clearly this A.I. stuff is amazing technology. And as a tool to give me a creative kick-start it seems very useful. I still have serious reservations about the ecological impact of A.I., but I do think I’ll start to use ChatGPT (or a similar text generation tool) to help me with lyric writing.

A Sprinkling of JavaScript

Over the last few months there has been a surge of prominent web people – designers, developers, thinkers – questioning the current obsession with complex “web app” style frameworks. Perhaps this was prompted by Jeffrey Zeldman’s ‘The Cult of the Complex’ article from June 2018, or perhaps this is a natural reaction from people who deeply understand the web.

The ‘backendification of front-end development’ is causing a lot of different questions to be asked. From Bridget questioning the usage of a JavaScript framework to Michelle building a dependency-free site. There are designers learning about semantic HTML and calls to consider limiting JavaScript usage. And reminders to developers that you probably don’t need a single-page application.

The theme perhaps culminates in this instant-classic article by Jeremy Wagner on A List Apart: Responsible JavaScript. This pared-down approach is closely aligned with accessibility – it’s about using the most suitable technology for the job.

Which brings me on to horses. But first, web apps.

What is a ‘web app’? Wikipedia helpfully has a definition – of sorts. But there’s a certain amount of bet-hedging:

The general distinction between a dynamic web page of any kind and a “web application” is unclear.

https://en.wikipedia.org/wiki/Web_application

Which chimes with my experience when I ask peers for a definition. They all but cry “You just need to feel the difference, man!”

After all, it’s not like we’ve not had interactivity in web pages before the advent of the current crop of JavaScript frameworks. Gmail, considered by many the poster-boy for a modern web app, was launched this very day in 2004. Fifteen years ago!

Single horse in a mountain field

So, horses. Back when the early automobile engineers were putting together the first cars, there was a clear distinction between the mode of transport widely used before – the horse – and what they were building. There was no confusion, no perplexed on-lookers asking “is that a horse, or an automobile?” There was a world of difference between the ‘old’ and the ‘new’.

1907 Franklin Model D roadster automobile

A world of difference, but still much the same. The problem that horses and automobiles were solving was, essentially, the same: getting people from point A to point B. But the mechanism – the technology – used to achieve that goal was entirely different.

Not so with ‘web apps’. The technology is pretty much the same as before: HTML, CSS and JavaScript. The application of that technology has a few extra bells and whistles, and there are newer browser APIs we can take advantage of – Service Workers being a prime example. But, essentially, what we build for the web hasn’t changed all that much.

Except it has, or so the framework-fanboys would have you believe. I’ve heard developers talk about the more traditional ways of building websites to be akin to riding a horse, while using a Single Page Application framework is like driving a sports car.

Red sports car on a racing track

I have bad news. A sports car works great in the circumstances for which it was designed. But take it out of its natural environment – take it off the track and onto a mountain pass, for example, and you’re in trouble. For harsh terrain you’ll need a horse, not a sports car.

Riders and horses on a mountain

You see, a horse might not be as quick on a flat race track. It might not have a heads-up 3D display to show you the turns ahead. It probably isn’t equipped with intelligent side impact protection systems. But you know what it does have? The ability to do the job in less-than-ideal conditions.

Because that is how the web is experienced by most people, most of the time. Poor bandwidth, slow latency, underpowered devices – these are the bumps, potholes and rocks in the road which will stop your JavaScript sports car in its tracks.

So, like the luminaries of the web I mentioned above, I add my voice to the growing cry: consider your JavaScript use carefully. You may not need as much of it as you think.

Technical Credit

There’s a well-known concept in programming that refers to the negative effects poorly-made decisions can have on the quality of software over time: Technical Debt. The Wikipedia article gives some examples of the causes and the consequences of technical debt.

This financial analogy is a useful one, as it nicely describes the long-term impact of debt – the longer you have it, the worse the problem becomes. Conversely you can have credit (e.g. savings) in your account for a long time, waiting for the proverbial “rainy day” to take advantage of your good planning. Want to splash out on a new pair of sparkly galoshes? No problem!

At the An Event Apart conference in Orlando in October 2016, Jeremy Keith spoke about "Resilience: Building a Robust Web That Lasts" which was a talk about progressive enhancement cleverly disguised as it didn’t use the phrase ‘progressive enhancement’. In that talk Jeremy dropped a knowledge bomb, calling building sofware using the principles of progressive enhancement like building ‘technical credit’.

This, in my opinion, is genius. It’s a gloriously positive spin on technical debt, which is too often seen as the product of bad developers. It’s saying “you, developer, can make a better future”. I love that.

It appears there is little online which talks about this “technical credit” concept. In fact, the only decent resource I could find is a 2014 paper from the Conference on Systems Engineering Research entitled ‘On Technical Credit’. The author, Brian Berenbach, gives a brief but eloquent introduction to the idea that we should concentrate on what should be done, rather than what shouldn’t be done to make a system better.

From the abstract:

"Technical Debt" … refers to the accruing debt or downstream cost that happens when short term priorities trump long term lifecycle costs… technical debt is discussed mostly in the context of bad practices; the author contends that the focus should be on system principles that preclude the introduction, either anticipated or unanticipated, of negative lifecycle impacts.

Sounds great; let’s stop bad things happening. How? The abstract continues:

A set of heuristics is presented that describes what should be done rather than what should not be done. From these heuristics, some emergent trends will be identified. Such trends may be leveraged to design systems with reduced long term lifecycle costs and, on occasion, unexpected benefits.

Emphasis mine. I’ll wait here while you to read the rest of the document.

At this point hopefully you can see the clear link to the principles of progressive enhancement. Let’s look at a few examples emergent trends – which I’ll call ‘properties’ as the paper uses this term – and the (un)expected benefits that progressive enhancement may give. But first, a quick refresher on what progressive enhancement is.

The principles of progressive enhancement

I can’t put progressive enhancement in a neater nutshell than Jeremy does in his talk ‘Enhance!’:

  1. Identify the core functionality
  2. Implement it using the simplest technology possible
  3. Enhance!

For websites this boils down to practical principles like these:

But there’s no hard-and-fast set of rules for progressive enhancement, because every site has different functionality. That’s why it’s considered a philosophy rather than a checklist. As Christian Heilmann said, progressive enhancement is about asking "if" a lot.

Emergent properties

Someone once said words to the effect of "the only constant is change", meaning that the only thing you can rely on is that things will not stay the same. That’s good! Progress is positive and brings with it new opportunities.

These opportunities can be seen as emergent properties – new or existing attributes of things which emerge as time goes on. For example, the increasing uses of mobile computing devices and fast home connection speeds are emerging properties leading to opportunities for new types of business. Likewise, the prevalent use of social media and its unprecedented bulk collection of data about its users is allowing new models for advertising – and, unfortunately, more nefarious uses – to emerge.

These emerging properties are often very difficult if not impossible to predict. Progress can lead to unexpected outcomes. Technology in particular is often put to unanticipated uses and exhibits unexpected behaviour when used at scale.

Who, for example, could have predicted the explosion of new devices and form factors just a few years ago. Devices once the domain of science fiction are now commonplace, and the range of new input types – notably touch and voice – is revolutionising how people interact with technology.

While fixed line download speeds are increasing many in developing nations, who arguably are the ones who could benefit the most from widespread Internet access, are stuck with very slow speeds, if any at all. Clearly we have a long way to go to achieve parity in global access to the Internet.

(Un)expected benefits

With such a wide array of both expected and unexpected properties of the current technological revolution, building our systems in such a way to both be resilient to potential failures and benefit from unanticipated events surely is a no-brainer. The ‘On Technical Credit’ paper defines this approach as Technical Credit:

Technical Credit is the investment in the engineering, designing and constructing of software or systems over and above the minimum necessary effort, in anticipation of emergent properties paying dividends at a later date.

This is Progressive Enhancement. It’s about putting some thought in up-front to ask those tricky "what if" questions. Questions such as:

Thinking about these, and many other, potential problems leads you to follow the recipe given by Jeremy which I quoted above:

  1. Identify the core functionality
  2. Implement it using the simplest technology possible
  3. Enhance!

Implementing core functionality using the simplest technology possible – in the case of a website by using well-structured semantic HTML markup generated on the server – gives some expected benefits:

Plus it provides a strong foundation to take advantage of unexpected occurrences; those emerging properties mentioned earlier.

From brand new browsers to old browsers working in a new way, your well-structured HTML will deliver your content even if everything else fails. Support for new input types on a myriad of unimagined devices will be taken care of by the browser – rather than you having to find Yet Another JavaScript Component™ that adds the support you need. And as new APIs are added you can layer on support for these knowing the foundation of your site is rock solid.

Spending Technical Credit

So you’ve built your system carefully, thinking about the many ways in which it could fail. You’ve done ‘over and above the minimum necessary effort’ and can now sit back, confident in the hope that should a rainy day come you’ve accrued enough technical credit to weather the storm.

Bad, good and great programmers

A recent tweet by Cory House started my brain a-twitching:

One of my new favourite interview questions: What is the difference between a bad, good and great programmer? Which are you and why?

I’ve worked with all three kinds, and thinking about the question of what the differences are I realised (not for the first time) that pure coding skill is nowhere near all the story. This blog post explores what else may put you in one category or another. First some assumptions:

  • As this is an interview question I took “programmer” to mean “one who works in a software development team”
  • The basics of being a decent employee – turning up on time, dressed appropriately and at least partially sober – are a given
  • The programmer can actually code to a decent level, “decent” being whatever is appropriate to fulfil the job requirements
  • The employer doesn’t just want a code monkey. I hope and trust that there are very few companies who want programmers to just “shut up and write the code”, and if you find yourself working for one of those then get out as soon as you can.
  • I’m talking to traditional programmers (C#, PHP, Python, Ruby, JavaScript etc) rather than front-end (HTML, CSS) but many of the points are applicable for any type of developer

Bad programmers

Generally, bad programmers are easy to spot. They write code that generally works (if they didn’t they’d be out of a job), but suffer from many or all of these issues:

  • They have a bad attitude towards non-geeks, whether non-technical colleagues or users
  • They have a bad attitude towards other programmers whose views don’t closely match their own
  • They know it all, or at least everything that matters
  • They are opinionated about tech; either wanting to use cutting edge stuff because it’s cool (whether or not it gets the job done) or they only trust very established things and refuse to look at new tech
  • Their communication skills are poor, and they have little desire to improve
  • They may fulfil specification requirements but don’t go any further than coding for exactly what is written
  • Their sense of humour is non-existent, or is harsh and rude
  • They don’t ask questions, and don’t make suggestions

It’s important to take all these points on balance. Some people may be shy, which could mean they don’t ask questions or make suggestions. But a good manager or lead developer will help staff to fulfil their potential, for example by encouraging the quieter members of the team to contribute.

The code from a bad programmer may also have these hallmarks:

  • Lack of comments, or comments that state the obvious and don’t tell you *why* they coded something a particular way
  • Obtuse, gnarly, over-abstracted, over-complicated architecture (at any level: method, class, subsystem or app)
  • Inconsistent or otherwise poorly-considered naming of variables, methods and classes
  • Lack of attention to detail, such as proper sanitisation of inputs for security
  • Copy-and-paste-itis. Bonus points if it’s clear they didn’t understand how the copied code works.

You get the picture. We’ve all written code like this at some point and we should be careful not to think of a programmer with less experience, or one who is struggling with a complex task, as a bad programmer. Bad programmers have a bad attitude, and even if they can mask that attitude for a while, eventually the mask will slip.

Good programmers

Good programmers, like bad, are known by their attitude as well as their technical skill. Note that a good programmer may not have as powerful code-fu as a bad programmer, but their attitude and “soft” skills more than make up for any technical shortcoming. (This is not to say that someone who doesn’t know XML from XTC can be classed as a good programmer; the basics mentioned above still apply.)

You’ll know a good programmer because:

  • They have a good, helpful and professional attitude towards colleagues and customers/users
  • They have respect for other programmers and are willing to listen – and when necessary respectfully disagree – to other points of view
  • They have a good sense of humour and contribute to a good atmosphere in the team
  • They exhibit attention to detail, and can spot the holes and inconsistencies in a specification
  • They are respected and liked by other members of the team
  • They don’t make rash decisions and have learned to weigh the pros and cons of different technologies
  • They can put themselves into the users’ shoes and make good decisions about how their code affects the user interface and experience
  • They have good communication skills, and avoid jargon wherever possible when communicating non-technical people

These kind of people make a team better, and so help an organisation to be better. But it’s not just soft skills, they also have a good grasp of technology:

  • Their code is readable and well-formatted, adhering to any coding standards adopted by the team
  • They choose sensible, descriptive and unambiguous names for classes, methods, properties etc
  • Their comments are actually useful: not just telling you what a method does, but why it is used – and any non-obvious things you may need to watch out for
  • Their architecture choices (at method, class, subsystem or any other app level) are clear, well-abstracted and only as complicated as it needs to be. My rule of thumb for “good” architecture: either you would have written it the same way, or you see why they did it their way and don’t need to change it much.

No doubt anyone with a bit of experience working in a development team can think of several more hallmarks of good and bad programmers. But what about great programmers?

Great programmers

While many people would roughly agree what makes a programmer good or bad, deciding what criteria to use to distinguish the greats ones is much more subjective. Here are a few points I can think of that, in addition to everything I noted for a good programmer, would class a programmer as great:

  • They are aware not just of the users’ needs and the specification, but the organisational environment. They can guide the development of an application so that it serves wider organisational purposes: in the case of a business to serve users and be commercially successful.
  • Their communication and “people” skills are highly developed; for example they can explain complex technical concepts to non-geeks in an understandable, even entertaining, way
  • They are known in the team as the person who will help you out with a problem: partly because they have the experience and knowledge, but also because they make themselves available to help others
  • They keep themselves up to date with technology – not just their own area of expertise but the wider world of development, UI, UX, project management and business
  • Their thinking in terms of abstracting code takes into consideration not just the next 3 months but the next 3 years (that *almost* means they can tell the future)

In short a great programmer has an expansive view of technology, of people, of the future of the organisation and applications they work on. They are part psychologist, part entrepreneur, part designer, part storyteller.

A couple of years or so experience and taking pride in what you do will take you from being a bad programmer to being a good one. But to be a great programmer takes a special kind of person. The kind that, eventually, will do something really special. Like write a great book, start a great company, write an amazing Open Source project.

There’s lots I haven’t mentioned here (such as writing testable code).For more on this subject check out these links: some are articles and essays, some are great programmers.

Blog highlights

I enjoyed myself with this trip through my blogging history, but I guess something you’d like to see is some highlights of what I’ve written about. Here’s the greatest hits of stillbreathing.co.uk (in my opinion, of course).

*Sniff*. Good times.