In this post:
- I make a test that is not very good.
- I start using software personas as a medium for shitposting.
- I derive useful tests and design insights from my deliberately absurd simulacra.
I'll be honest, the details of what I was working on kind of fell out of my head, because I was so into algebraic data type stuff. But fortunately, I can just look at last week's post, and, oh yeah, the idea was to start writing tests to prove out the workflows for this app.
I added a basic test.
def test_app(main, models, db_session): """Test app functionality.""" app = main.App(db_session) event = models.Event(name='test') db_session.add(event) event_window = app.canonicalize(main.EventWindow(app, event)) assert event_window.contained_by assert event_window.preceded_by assert event_window.followed_by assert event_window.contains assert event_window.topics
The big win from writing this test was realizing that I had the fields on EventWindow the wrong way around, so I switched them to have app first. That way, every one of these classes is parent, then relevant database object(s).
I tried to write more tests, but thinking about content-free names, like I was at first, was a total drag. I need to have something that resembles real data. I don't feel like using Linked Seas (remember that?) stuff in the test code, so I'm going to do some user persona-y stuff.
Brian is a numinous data-being perfectly in harmony with whatever interface I happen to have slapped together this week, and xie wishes to write up the background of the various bardic songs that will be written out in full in xer upcoming fantasy pentadecalogy, The Lost Secrets of the Hidden Kingdom of the Seven Songs of Um. Brian decides to first create a Teller, Friodemus the Wise. The astute reader of the project's source code (I actually can't remember if I've pasted the relevant bits) will realize that there's no interface for managing Tellers, specifically.
I also have no specific idea how to organize the creation functionality within the interface. Let's make a persona with different priorities. Ace Slipstream is a time-displaced refugee from a future dystopia. She uses Conworld Codex version 99.8.7rc18 to chronicle the confusing tangle of events leading to the mysterious Omicron Inception, which converted most of Cymerica to computronium slag, and also to write her weekly shopping list. Let's have a look at her incredibly polished interface. It must somehow reflect the underlying database model, in which there are three basic types, that relate to each other in various ways:
- Events are the simplest, consisting of just a name.
- Topics and Tellers are almost as simple, consisting of a name, but also an optional one-to-one connection between the two.
- In other words, some Tellers are Topics, and some Tellers are not Topics, and some Topics are Tellers, and some Topics are not Tellers, but no Teller is more than one Topic, and no Topic is more than one Teller.
Looking at this, I kind of wonder if the Topic-Teller relation should be instead represented in a table with a pair of unique FKs, but I'll have to put that on the back burner until I have a better idea what difference it would make.
I'll try to address the Events first, because that should be a strict subset of the issues that Tellers and Topics will present. Without applying some form of heuristic to the connecting data, there's no obvious way to organize Events beyond key functions of the numeric id and the name.
One possible way that Ace's GUI could look is something like current MediaWiki, with a front page and a search box. I'm not quite sure what the front page should look like, but it seems to me there should be some way to represent or visualize the scope of a codex. Statistics, perhaps? Do I want, in Wx terminology, multiple Frames, or do I want to have one Frame per open Codex?
Thinking over this, it is clear that, for now, I want to put the functionality at the level of the App (which I might rename to Codex). So, let's add a test for Brian's functionality. Given an App (constructed by the test), Brian creates Friodemus the Wise, and gets back a TellerWindow that describes Friodemus.
Here's the flow I went with: there's a new_window method on the App object (which probably should be Codex), which creates a TellerWindow with no associated name. The write only gets queued after the name gets set by a method on the TellerWindow.
I'm really, really liking how SQLAlchemy is designed. I'm not doing great at navigating the documentation all the time, but it seems like there's a good chance I can get things to work, pretty much just by thinking really hard about what would make sense.
Brian's and Ace's personas gave me a good way forward for designing the App/Codex, but before I get too far, I want to think about how to handle the lifetimes of these auxiliary classes I'm tossing around.
Next week, I revisit the logic of when the support classes are live and reachable, and then start working on growing the interfaces outwards.