As a computer science professor, I have naturally encountered the challenges of teaching basic programming. This is, of course, a vast topic within the field of education, directing attention to how students learn, react, their attitudes, and strategies for engaging them. My department colleague professor Rocky Chang uses to say to students at the start of the semester: “programming is fun, exciting and frustrating”. Yes, all at the same time. So, there is a lot to think about here.
In the midst of this, I believe that one aspect that often goes unnoticed is that, as we teach programming, we are also immersing students into what philosopher Alasdair MacIntyre describes as a social practice. His definition is:
"A coherent and complex form of socially established cooperative activity that has its own internal standards of excellence and that enables participants to achieve goods that are intrinsic to that activity." (After Virtue)
While I do not intend to delve deeply into this concept here, my main point is simply this: as we teach programming, we are also inserting students into a broader programming culture. It is easy to forget that, and perhaps we need to be more intentional in making this more explicit. As I usually like to put, programming should not just be about writing correct and functional code, but also about the ability to write code that is good and relevant (or, I would add: directed toward human flourishing), and, even more, being part of a practice that is permeated with beauty and enjoyment. All of this requires us to notice the inherently social and cultural embeddedness of the practice. Not only we need to acknowledge it, but also know how to move inside it.
So, because of that, in recent years, I have trying to read some material on this broader culture of programming. Entire fields of study have been established in recent years, such as Software Studies and Critical Code Studies, providing valuable perspectives on the broader settings of programming.
A proposal that recently called my attention was Kevin Brock’s book on code as a form of rhetoric. Brock notices that, indeed, this is not a new idea, since other reflections have been already been developed to understand other forms of technical communication (such as engineering schematics or even mathematics) as forms of communication, dialogue and persuasion. When technicians write these products, they are not just thinking about constructing something that works, but also laying out how a certain technical goal is being achieved through the many small steps and decisions — and, for that, they need to be understandable and convincing, both for himself (which may forget the procedure later and want to come back) and for his broader community (inside his social practice).
If we consider that view on programs and algorithms as basically series of steps to be taken to achieve a goal, we can discern a special type of rhetoric that they try to embody — a form of rhetoric of instrumentality, in which we try to convince an audience that, by doing certain actions and procedures, we are able to achieve a certain objective. Even the metaphor “step” here is indicative: by posing a series of steps, you are guiding someone towards some place. And, for that, you need to be convincing.
(Also, it must be said that, by framing programming as a form of rhetoric, we also connect it closely to a liberal arts approach, which is something pursued in lots of educational institutions today.)
Algorithmic persuasion in history
Paying attention to the rhetorical role of algorithms helps us even to look back at history and discern other instances of this special type of rhetoric.
Kevin Brock notices, for example, how some classical rhetorical devices actually involve a procedural form: one example he gives is the enthymeme, a logical argument in which the speaker asks the audience to infer one of the premises on their own (in programming vocabulary: “run the code in your own head and get the result”). Classical logic, in the way it is structures sequences of arguments in forms of syllogisms, modus ponens, modus tollens, and others, can also be understood as “algorithmic” in the broader sense we are using here.
Even more interesting than that, however, is the way that we can extend this notion of algorithmic persuasion to an analysis of rituals in cultures. What if rituals are algorithms with rhetorical functions? Matteo Pasquinelli has been one of the many scholars today to suggest this connection, as he puts in the first chapter of his book The Eye of the Master: the Agnicayana ritual of the Ancient Vedic tradition, for example, depicts an interesting and intricated algorithm of incremental approximation of numbers. Furthermore:
Beyond religious symbolism, the Agnicayana ritual and the Shulba Sutras in general had, in fact, the function of transmitting useful techniques for the society of the time, such as how to plan a construction and to enlarge existing buildings while maintaining their original proportions. Agnicayana exemplifies the originary social materiality of mathematical knowledge but also the each while reciting dedicated mantra and following step-by-step instructions. Solving a riddle that is the key to the ritual, each layer must maintain the same area and shape but a different configuration. — Matteo Pasquinelli, The Eye of the Master, chapter 1.
Now, if you are reader of the Bible, this may surprise you: what if the Bible itself has some algorithms, expressed in form of ritual stipulations and descriptions, trying to argue about something? (Think about those long passages describing the Levites’ tasks in Israel’s worship). That is indeed very close to what Dru Johnson tries to argue when he says that Hebraic thinking has a ritualized epistemology. Yes, algorithms, as well as rituals, can be arguments. They can even be religious arguments. Let’s even say that: the book of Leviticus could be ancient Israel’s “religious Github repository”. (And that could be an interesting direction to be pursued further in historical and biblical studies!)
The rhetorical situations of computer programming
Now, of course you may think, at this point, that the computer programs we develop in an introductory programming class are much simpler. The student is just trying to find an algorithm count the occurrences of a letter in a phrase, or sort a list of numbers in ascending order. No big “existential” issues here, right? Well, in a sense, yes, but, if you start to pay attention to the very setting where you are doing this, you will notice that a lot of things that doesn’t seem to matter actually matter.
This is better expressed with the notion of a rhetorical situation. Programming is never done outside of those. Brock mentions that a rhetorical situation is has many components, pertaining to different questions you may ask yourself:
The exigence: “what am I trying to achieve with this argumentation?” In programming terms: “what is the problem I’m trying to solve through this code?”
The constraints: “what can I use to achieve this goal?” In programming, it means acknowledging your language, API, data, and even hardware constraints. A good part of the difficulty of learning how to express yourself, be it via a human language, or a programming language, is learning how to translate your intentions into the terms that make sense in the target language’s “system of rules” (i.e., vocabulary, grammar, etc.). As some students usually say: “wow, when writing this code, I started to notice that even simple things may involve a lot of steps”. Yes: this happens because you are communicating to a machine, which can be very limited in terms of the actions that it can handle. You need to be very specific and detailed. But this, after all, can be very beautiful, like the playing a game: you submit yourself to some constraints and then do something incredible and/or elegant inside these constraints. Moreover, this also could be training you to be precise and rigorous when thinking about what it takes to do something — in the same way that philosophers of mathematics argue for the goodness of math in forming intellectual virtue. Computational thinking can also be seen as a way of practicing virtue.
The audience: “who will be reading and engaging my code?” Here, you start noticing the profoundly social nature of what you are doing. If you are in a computer science class, you are probably sending this to a professor or grader to read. And, since this context is education, what you probably want to argue is that you understand what you are doing. Did you just “hard code” the solution to satisfy the autograder? Well, maybe you forgot that your audience is your professor, not the autograder. Did you just generate everything with AI, put it to run and it worked? Well, maybe you forgot that the objective here is showing your understanding of the solution, not just getting the answer to whatever problem the professor gave you. (OK, I touched a nerve here — but I will leave reflections on coding with AI for next posts). But this audience may change. When you go to industry, or even in hobby programming communities, the situation is different, and so are the expectations. You start inhabiting a slightly different social practice — and, with it, comes also its norms and standards of excellence (be them explicit or implicit).
The rhetor: “who am I? What is my role in communicating this?” Or, in programming: “what is my role in, for example, this software project? What can I actually do, perform and change in this project?” Kevin Brock’s book, for example, has a highly detailed study on the community of developers around Mozilla Firefox, and notice how hierarchies, roles and responsibilities are constantly appearing and being negotiated even in the context of open source software. “Knowing your place” when you communicate leads you to think a lot about what you choose to say and not say.
The context: you can extend the social questions to a “third person” in the process of communication, and ask about all the cultural, social, historical and political factors around your act of communication — in this case, programming. These affect decisions, too. Even a joke made as a comment while you write a line of code — making a funny reference, for example, to a popular movie quote — is already indicative of the “mood” of the social practice you are inhabiting.
The message: finally, this can be understood as composed of three parts, leading to questions like:
Logos: “does my code make sense?”
Ethos: “is my code credible? Can people trust what I am doing here?”
Pathos: “is my code pleasant or frustrating to deal with?”
Let’s finish this by saying that all these questions will lead to decisions that set your programming style (in the same way that literary studies talk about writing style). One of the first things we learn in programming classes is that there are multiple ways to write a program — you can use lots of variable and function names, different structures and logic flows, etc. What we usually don’t notice, however, is that, among these multiple ways of writing, some are better than others in depending on the rhetorical situation. This means that we probably need a good repertoire of styles in order to communicate well. (If you want to explore lots of these programming styles or even “genres”, Cristina Videira Lopes’ Exercises in Programming Style is an amazing book).
Programming language developers already recommend some style guides (for example, Python) to help you to communicate better. Communities formed around open source projects sometimes even impose rigid style guidelines in order to guarantee the overall comprehensibility of the code among the many people involved in it. And you may see those as mere attempts to make the process of communication more efficient and less error-prone, however, I want to insist that there is something much bigger going on here.
Going back to MacIntyre: his idea of “social practice” is actually there in order to drive home a very important point: there is inevitably a moral dimension in these social practices. And, by that, we don’t mean simply “doing right or wrong” (i.e., the common target of “computing ethics” classes). It means something broader, about living a fruitful and fulfilling human life inside a society. Good communication, or rhetoric, has a crucial role in virtuous and flourishing communities. And that includes computer programming.
Hospitable programming rhetoric
Professor Victor Norman, a friend and colleague from Calvin University, wrote in 2011 an interesting article calling attention to an important virtue to be reflected in the way we code: hospitality. Hospitality, after all, is broadly discussed in the area of rhetorics, as we can always ask: am I being welcoming, gracious and attuned to the audience’s needs while I communicate? Victor Norman makes a similar point, using the house metaphor:
“Hospitable code welcomes the reader to come in and be comfortable, to enjoy the cleanliness of the code, to feel at home, and to see that the space has been carefully prepared with guests in mind.”
If you are a professional programmer reading this, there is no doubt how, in many situations in your career, you miss this attitude when dealing with a lot of people’s code — so badly written and organized, taking you so much time and effort to figure out what is actually being done. This situation could reflect closeminded “final results oriented” behavior which translates into a lack of care for our neighbors.
(By the way, James J. Brown has published, in 2018, a book making a very similar point: Ethical Programs: Hospitality and the Rhetorics of Software — and with specific focus on the areas of networks and databases. We will surely comment some of his ideas in coming posts.)
As a Christian, Victor Norman urges us to the pursuit of this virtue of hospitality, as it is explicitly advocated by the Christian moral framework. And this makes me think what other Christian virtues should be reflect in the way we communicate and write programs. After all, hospitality may be thought as a specific case of love (caritas), another virtue. Would there be other ways to manifest caritas in our programming rhetoric? And, more broadly, what about the seven virtues — the four cardinal virtues of prudence, justice, temperance, and fortitude, and the three theological virtues of faith, hope, and love?
Programming and communicating with virtue is no small issue. As the book of Proverbs would repeatedly put:
To make an apt answer is a joy to a man, and a word in season, how good it is! Proverbs 15:23
The heart of the wise makes his speech judicious and adds persuasiveness to his lips. Gracious words are like a honeycomb, sweetness to the soul and health to the body. Proverbs 16:23,24
A word fitly spoken is like apples of gold in a setting of silver. Proverbs 25:11

