I’ve been co-hosting a speaking group about polyamory in Paris for the past few years, in which we used to organize the debate by writing down speech requests on a piece of paper, and distributing them in order. The groups were between 60 and 100 people in average.
However, you have probably noticed that there’s a tiny pandemic going on. Those meetups had thus to stop without notice, leaving a big void in our social activities. Quickly enough, some of the co-hosts migrated online, on a videoconferencing system that I will not name but which starts with a Z… I don’t know if you have ever attended a videocall with 50 people, but with the latency and the background noises it’s impossible to just have an informal chat. So we tried to recreate the structure we had in our goups, since it worked well for us: speech requests, written down on a list, distributed in order.
We soon had to face a few issues: asking for a turn in this piece of software is not as easy at it sounds. At first we had to watch everybody’s thumbnails to check if somebody was raising their hand, but on large videocalls there can be several pages of thumbnails. Then we told attendees that they could ask for a turn in the text chat, and it just added one more place to look at for us 😉 Then the feature to « raise hand » by clicking a button was added, which works well when you can find it, so not everybody uses it. Once the request has been noticed, we write it down on a Google doc shared between hosts, then we announce the turn and remove the line from the doc. And on top of that, we checked our speaking time counter to avoid monologues.
It works, but it’s quite a bit of work, it requires many pairs of eyes looking at screens and the text chat, etc.
Making life simpler
I thought there was an opportunity to simplify all that with software. The goal would be to allow participants to request a speaking turn, that would automatically be added to a list that hosts could see and reorder. And it would be removed when the turn is over. Oh, and also manage the issue of speech duration, so that we don’t have to handle the counter on the side. And since our counter produces statistics relative to gender, we want to keep that feature in the new app.
Alright, we know what we need to do, we just have to do it. I started writing at the end of year 2020, and after a failed start I’m happy to say that we’ve been using it for 3 meetings, and that it works rather well 🙂
The app is at https://speakinglist.net. You can go create an event, and to simulate participants you can for example open a private browser window or test with other co-hosts. There’s also a how-to page that you can look at.
The admin interface that you’ll end up on when creating an event has been designed to be displayed on a computer, while the participant interface has been designed to be used on a phone. This way the participants can have the videocall on their computer, and in hand a button to request speaking turns. It is also possible to display the participant interface on the computer of course, it’ll work identically.
The fact that participants declare their social categories (gender and race for now, optional and selectable by organizers) allows for the generation of interesting statistics on the distribution of speech between sides of the power structure. It also lets organizers reorder the waiting list to make sure it’s not always the same group of people who speak (hello white males, we see you). By objectively measuring the speaking time, we can realize there’s an issue, which is the first step to solving it. For example, in our groups we have found that even though there are less men present, they usually speak more often and longer than women and non-binary folks in proportion to their number. I have also noticed that when we tell them at the beginning of the event that we measure it and that we’d like them to make an effort, there is less difference. As we say in engineering, « you can’t optimize what you can’t measure ».
It’s Geeky time
For me, writing a program for a non-profit organization is always an opportunity to learn new tech and software libraries that I don’t know yet. Here, the main challenge is real-time. When we give a turn to someone, it has to be instantly reflected in their interface. For that we prefer a push method to a poll method, heavier in resources but more importantly much slower.
In the world of the web, this means websocket, that I never got to play with yet. Yay! 🙂 I took this opportunity to learn a backend framework that natively handles asynchronous operations. I started with FastAPI, that I’ve been wanting to test for a while, and we’ll see later why I didn’t keep it.
I don’t have so many opportunities to test new tech, so I try to cram as many interesting things as I can in them. I’ve also tried GraphQL as the API protocol and I must say I’m very happy with it. On top of it, GraphQL already contains a push mechanism, called subscriptions, which is a very good fit for me. However, FastAPI uses a version of Starlette that does not handle GraphQL’s subscriptions, so I dropped FastAPI to use Starlette directly.
Async is beautiful when it works, but not everything is ready for native async just yet in the Python world. I wanted to use the SQLAlchemy ORM, because the database library that Starlette offers does not do ORM and I do like it. Unfortunately, SQLAlchemy does not handle async yet (it should arrive in the next version, 1.4). So I used it in normal blocking mode, thinking that database connections are pretty fast since they are on the same server. It should all work fiiiiine.
It didn’t. Well, it did until there were more than 5 simultaneous connections, at which point we exhausted SQLAlchemy’s connection pool, which thus blocked the request until connections were freed. And this, in an async mode, never happens: when it’s blocked it’s blocked 🙂 To sum it up, on the first real-world use, the program fell over like a big sea lion drunk on bavarian beer. Should I have stress tested the app? Absolutely.
I more or less worked around it by raising the connection pool to 50 and crossing my fingers hoping there there is never more than 50 simultaneous database requests. I stress-tested it, it works fine with several hundreds of simultaneous users. If we ever do meetups that big, I think we’ll have other problems first. But yeah, I’d be happier when SQLAlchemy handles async natively. Until 1.4 is released, it’ll have to do.
On the frontend side, it’s only classics. React with Customize-CRA, Material-UI and Apollo for GraphQL, all written in Typescript. I must say that I am very pleasantly surprised with Apollo, it allowed me to entirely avoid Redux!
The app is obviously under a Free Software license, the AGPL. The documentation isn’t very detailed but it’s basically composed of an SQL server, the Python web app server Uvicorn (for async), Nginx in front of it all, and Redis in the backend to handle message queuing. The source code is here, and I provide a few configuration examples for deployment.
It now works rather well. Everybody does not use the app during events, but we can manually add reluctant participants and handle their requests like the others on the waiting list. The group seems happy about it, I’m happy about it, I think it’s mature enough to be used by others.
Feel free to tell me what you think of it, here in the comments or by email. If you want to help, I think that the app could use a graphic designer’s skills for a new logo, colors, fonts, etc. It’s currently translated into French and English, but I’m sure the English translation could really be improved. You can also add other languages if you feel like it. I accept contributions in the form of code too, of course, if you can make sense of mine 😉
I am looking for feedback, please tell me if you use it, with which group sizes, and what you think of it. I wish you good videocalls!