I fixed my memory!

Yesterday evening I said to myself “I’m going to tackle adding crosswords as an available review activity for dynamic-efl.com.”

It was an activity that I’d been postponing since I got the whole thing web-based. To be honest, I don’t know why anymore. I just remember the feeling that it seemed like a lot of work and, hey, wordsearches were working, so why rush, right? But, whenever I listed everything that the website could do, I’d find myself tagging on “and I hope to add crosswords, soon, too.”

Which was ridiculous because they worked in the desktop version, so whatever I needed to get done to make them work on the web version was probably just a matter of a careful reading of the code.

So, yesterday I resolved to get them done, and I did. Easy as that.

I was almost surprised how easily it all worked. And, to be honest, it’s a bigger accomplishment than updating the memory activities, but who could pass up the opportunity to write a blog post titled “I updated my memory.”

 

crossword
Funnily, this one still includes multi-word vocabulary. I decided to exclude them from crossword activities in order to make things easier on the learners.

 

Inspired by that, I decided to tackle something else that’s been outstanding on my list: fixing the memory activities. The memory activities worked fine, of course, but there were two different activities: translation memory and, if a group had enough vocabulary with associated pictures, picture memory. It seemed most logical to make a single memory activity that would use pictures where they were available, and translations where they were not.

What’s more, the translation-only memory tacked a ‘cheat sheet’ on at the end for the teacher, in case I forget how I translated a certain word (it happens to me, and I wrote the translations. I guess it happens to others, too). Why not do the same thing, but with pictures and translations. In case one of the pictures isn’t clear.

So, this evening, I fired up the IDE and I got it done. There were a few hiccoughs along the way, but it was done in less time than it took for the kids to watch a movie I didn’t like. So, hooray for that, right?

It’s nice to feel productive. In fact, so nice that I’m not even excited about now getting to work on preparing for classes next week.

Advertisements

Adding Mailchimp actions to a Django model

As I get ready to try a second time to attract users, I decided to use MailChimp mailing lists to keep in touch with these users, as well as setting up some ‘tutorial’ emails at regular intervals. (I’m imagining something like “You’ve been using dynamic-efl.com for a week now, did you know you can do this to get more out of it?”)

To do this, I’d have to have code in Django that automatically signed members up. That means that this is my first attempt to work with an API, even by way of a library.

I decided to go with the mailchimp3 library and installed it in my virtualenv according to the instructions and set up some variables in my settings.py file.

# Mailchimp stuff
# Authentication
MAILCHIMP_LOGIN = 'login'
MAILCHIMP_KEY = '===>SECRET<==='

# The lists
MAILCHIMP_LISTS = {'welcome': 'listID',
                   'germany': 'listID',
                   'beta-testers': 'listID'}<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

The idea here is that I’ll be able to iterate over the keys in the lists, if I ever need to check that the user is in all the lists (for example, removing a user should include removing him from all lists).

To that end, I added a function at the beginning of my models.py file. (This probably isn’t good form).

def mailchimp_get():
    """ Returns a logged-in mailchimp client """
    return MailChimp(settings.MAILCHIMP_LOGIN, settings.MAILCHIMP_KEY)<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

It seemed like the easiest way to only write the login once.

Finally, I had to create a few methods in the Model in question (in my case, this is my teacher model, as my users are called ‘Teachers’ in this bit.

def mailchimp_add_teacher_to_list(self, listname):
    """ Takes a listname, checks that the teacher is not a member of the list, then adds it. """
    client = mailchimp_get()
    listid = settings.MAILCHIMP_LISTS[listname]
    if not self.mailchimp_teacher_in_list(listname):
        data = {
            'email_address': self.user.email,
            'status': 'subscribed',
            'merge_fields': {
                'FNAME': self.user.first_name
            }
        }
        client.lists.members.create(listid, data)

def mailchimp_lists_get(self):
    """ TEMPORARY - Returns a list of all mailchimp lists """
    client = mailchimp_get()
    return client.lists.all(get_all=True, fields="lists.name,lists.id")

def mailchimp_teacher_in_list(self, listname):
    """ Returns a bool indicating if this teacher's email address is in the list """
    email = self.user.email
    client = mailchimp_get()
    results = client.lists.members.all(settings.MAILCHIMP_LISTS[listname], get_all=True, fields="members.email_address")
    members = results['members']
    addresses = []
    for m in members:
        addresses.append(m['email_address'])

    return email in addresses

I think the names should be pretty self-explanatory. The mailchimp_lists_get() method was just an experiment based on following the instructions in the documents.

Lastly, I created a view and a URL just to test these functions by printing to the console and looking at the (currently empty) lists in mailchimp.

Summary

It was my first time sitting down and thinking critically about what I wanted and how to do it and I have to say that mailchimp and the library basically made it painless. I have other project ideas that will require more API integration, and it’s made me hopeful.

It’s easier to expand than to fix…

I feel like everything I learn about coding is already a well-known software truism. But, I wanted to report in on my progress with the EFL worksheet software by saying that it’s moved back to the top of the priorities list and I’m working on it, but slowly.

There was a bug where the gap fill sentences created for capitalized vocabulary (‘Baltic Sea’ and ‘Vienna’ are examples) didn’t work correctly.

I immediately realized that the code put the entire sentence into lowercase (with Python’s .lower() method) before looking for the word. No problem, I thought, I’ll just find where the word is searched for and have it search for the lowercase text of the word. Problem solved.

I genuinely thought that was something I could do quickly, by way of getting back into the coding game…

More than an hour later, I found the spot where I forgot the extra .lower() call and everything was fixed. But I needed a full hour to figure out where in my code that happened.

A full hour.

I’m discouraged that I had such a hard time finding my way through my own code.

Updating the Interface

I have been busy, and frustrated, as I work on the worksheet generation app. And, unfortunately, I haven’t been adding new functionality or improving the existing functionality. At least, I haven’t been improving it from the point of view of how the worksheets are made. I’ve been working on how people make the worksheets.

This is what the app interface used to look like:

old-formattingIt really isn’t bad, it’s just very basic. I knew I’d change it at some point — I use this site more than anyone else, and I have an idea how I want it to look — but I wanted to focus on features.

Then, recently, I invited friends and colleagues to try the website out. And nobody seemed to understand what it did. I told them (in emails, in person) and they loved the idea, but the interface that seems obvious to me… well, it obviously isn’t.

I had an idea: I’ll make a sort of tour you take, before you can sign up, that will explain the functionality with screen-grabs. 

But, there are so many things on my plate, I know the chances of me making the same tour twice are not great. At least, not in the same year. So, logically, the interface should be changed.

CSS is hard!

The thing about CSS is this: you can  download templates (like I did for the landing page, from a great resource called Start Bootstrap), and I figured I could easily adapt the rest of my page to match it.

Wrong!

To be fair, I haven’t yet come across a CSS problem that, once I figured out how to articulate it correctly, didn’t have a clear answer somewhere. (Also, I love the resources provided by W3Schools, but hate their search functionality. Are they trying to make money there?) But, every step felt like an uphill battle.

Eventually, I got to a point where I was starting to be satisfied with the result.

Hosting static files on django is poorly explained!

I’m starting a list of things that were hard for me to learn about django, to eventually explain when I feel like I understand them. One thing would be the deployment to linode (remember that?) and another would be hosting static files.

After a lot of googling and basically blindly trying things, I’ve stumbled into a configuration that worked. But, for a while, it only worked on the linode site and not locally and I was too frustrated to change it. So, every change I made had to be pushed to the site to be tested, which was also frustrating.

Then, I got around to working out my development file hosting and was able to test changes more quickly (and without feeling like I’d have ‘broken’ the site just then when a friend would try to use it), but when I pushed my changes to the linode server, I realized that I’d broken hosting there!

Now, things seem to be working both locally and on the server, and I’m going to not play around with it. But, I have other projects cooking, and I’ll need to wrap my head around this.

So, what does it look like now?

Obviously, after all that drama, you’d expect something amazing, right? Well, it turns out that I can fix individual problems, but I don’t really have much of a vision of an overall design. So, while the layout is basically the same, the new formatting is something I’d rather spend my time looking at:

new-formatting

It has a title bar that remains fixed as you scroll, and functions are presented as buttons (because they seem to suggest action) and, rather than telling you “there is enough vocabulary to make a memory activity,” it simply doesn’t show you the option unless there is sufficient memory.

I can live with this for the rest of the academic year, I think. Now, I just have to clean up all the pages and make a tour, as well as finishing up my ‘minimum functionality…’

Preparing for Clowns, or what I learned from a Twitter-fight

The CodeNewbie chat last night was about dealing with bullies, and, since that dovetailed so well with what I’m working on right now, I thought I’d try to be a bit more active in blogging about what I’m doing.

You see, I think my app is 90% finished, but I’m taking a break from features to get ready for the public. Which, really, means, to get ready for the jerks. You see, the worksheet generation app isn’t a social app. The user’s interaction with it is basically all centered on the user and their own groups and classroom resources for their groups.

But, contributions are shared. That is to say, if you need a translation for the word ‘web app’ for one of your groups and there isn’t one in the system, the system just asks you for one. But then, the next guy profits by the translation you added. And you’re profiting from the resources added by others.

The Twitter Fight

But then, I got in a bit of a fight on Twitter. I’ll post sometime on the idea of ‘defending the ancestors,’ and why I don’t like the term ‘the ancestors’ being used as a dog-whistle for racism (racist dogs!) but that was what it was about. And it wasn’t nice.

While I’m a middle-child and can handle Internet strangers being mean to me, I realized that the guy I was fighting with had the advantage: his Twitter handle was only for his trolling. My Twitter handle connected to all my life, and he could see that, use it in a fight. And, because I tend to fear the worst, he could start being a jerk in other parts of my life.

I realized that, when I start posting about the worksheet generation app by name, with links, anybody who felt like they didn’t like me (and there have been a lot of those people in my life) could create a free account, and just throw a wrench in the works by adding terrible resources.

Imagine if a legitimate user — maybe even one paying for the service — wanted that aforementioned translation of ‘web app’ and got something like ‘where we see the naked photos of your mom.’ Even worse, what if that person — like I often do — didn’t proofread that worksheet before handing it out to students. (At some point, worksheets will be emailed with a mouse-click.) What a nightmare.

Worse than paranoia

I talked myself back down from “Twitter people will be mean.” After all, the solution could easily be ‘just charge everyone.’ Who’d pay me money for the privilege of trolling me?

Then I realized I shouldn’t worry about Twitter trolls making accounts and being jerks. I should worry about people just like me thinking that they’re being funny. Or, even worse, thinking that the resource they’re making is appropriate for their students. After all, we teach adults, whose to say that we can’t include “your mom” jokes?

My real  nightmare is someone either testing out the system, playing around, and putting random crap in… Just to see if it really appears in a worksheet.

Of course there’s a solution

I can deal with it. Of course I can. There’s not a problem without a solution.

My interim solution is, for now, giving users the opportunity to explicitly say “this is part of an inside joke with this group.” You can easily add resources that will only be used for a single group. Easy.

The other thing is pretty simple: all resources are immediately available to the person who creates it. Everything else has to be approved, first. As users are added, it will be possible to say “the resources added by user_x will be automatically available,” but, until then, it means that I’ve invested a lot of time already (all morning today was spent creating the interface and the backend that will enable this level of moderation) into the project of investing a lot of extra time in this project.

And that kinda stinks. It makes me like people, as a group, just a little bit less.

Working with Working Code

This is a tales of pros and cons. I set myself the goal of creating my worksheets this (academic) year using my worksheet generator. The results have been mostly positive — the students don’t know it, but I’m proud as hell of the worksheets I hand out, the students are benefitting from the way vocabulary is repeated, and even the errors are room for good, spontaneous discussion — but mixed.

Basically, I’m leaving PyCharm open all the time, because if I’m at my computer, it’s either to improve the code (i.e., do some coding) or to use the code for its intended purpose. Somehow, I feel like I’m a one man example of the idea of producing “banana software,” developing features as I need them, often under a deadline which, though it may be self-imposed, feels ominous. (Right now, I’m taking a break from coding a new type of exercise which is called for in next week’s lesson plans — sure, I could just cancel it [I have a great relationship with the customer], but that would mean admitting defeat.)

The pros:

Basically, what’s great about what I’m doing now is that I keep realizing that my planning was incomplete. It’s in the usage of the software that I realize  how much more it could do. Some changes are just inserted as TODO comments in the code like “It would be great if this worked with that” others I implement immediately, because I realize it makes no sense to code the rest of the features if these basic things are going to change.

Even more, it keeps me at coding. Knowing that this stuff has to be finished by next week keeps me at my keyboard when maybe I’d like to be in a hot bath. And that keeps everything fresh in my mind. Great.

The cons:

Obviously, the pressure is a double-edged sword, but I generally embrace it. However, it does mean that I feel this pressure to code forwards, rather than backwards.

I don’t know if coding has directions. What I basically mean is that I feel the need to add the features, rather than improve how past features work. An example is from the exercise I’m coding. It’s being coded as an object and I’m copying and pasting so much from other exercises that, even though there is a base class that they all inherit from, there should be a second base class for this category of objects.

And I could get that done in less than an hour, probably. But I don’t have that hour.

The thing is this: I know me. I’m proud of accomplishments that I can see. I don’t know that I’ll ever come back to this once everything is working, because cleaning up code doesn’t feel like an accomplishment the way that writing code does.

Maybe, I need to work on myself as much as on the code.

 

What my App does

I had an inspiration last night. I realized — after working on it for the better part of two years, including several reboots — what it is that my app does. I’m talking about the worksheet generator, which seems closer to becoming something now than it ever has before.

First, I think I have to mention what it isn’t.

What the worksheet generator isn’t

It isn’t just another application or website that promises to relieve you of the burden of preparing for your classes. I pay for such websites, and I think they have their place, but I’m not going to be able to compete with them, even by doing the job marginally better.

The worksheet generator will not be just one more place that you can go because you didn’t prepare a lesson and you want to print something out for that class that is starting soon.

Working just as much – or more – for more results

I realized that, if I had to tell another ESL/EFL teacher what it was that my app did, it would be to say that it does a lot of the ‘stupid work,’ so that the energy I invest in prep goes farther. There are a couple of ways that this manifests itself.

  • Organization: Never my strong point, this is what the project originally was supposed to help me with. The idea is to have a virtual record of what you’ve done with each group, in terms of grammar and vocabulary. The strength of this organization will be in helping to review regularly. And that brings me to the second thing:
  • Permanence: Maybe this is just one aspect of organization, but it’s something I’ve known that I’m bad at. I’m great at creating a single, excellent, engaging lesson. I’m not so great at tying them together into a series that makes sense in a meaningful way. The extent of my understanding of ‘permanence’ has been to say that, if we’re working on the simple past, I can do a series of lessons about the past.

    What I’d like to do in the future is to have a more clear sense of repetition, by which vocabulary that came up once is reviewed again and again in the exercises of the following week. Even more, I want to say “hey, we practiced this structure three weeks ago, let’s do it again with the vocabulary from last week.” And that brings me to the last main point:

  • Modularity: I don’t know if it’s just me, or if every teacher is lazy, but I suspect it’s the latter. If you’ve ever had a teacher, you probably know what I’m talking about. I’m talking about teachers who create one set of PowerPoint slides and then teach them forever. Or,  in my case, who prepare an exercise for one class and then modify it only slightly for another (generally to realize that I overlooked an inside joke meant for the first class and completely without meaning for the second).

    The thing is this: Most of the worksheets I create in OpenOffice are great for the class they’re created for, and only the top half of page two is really great for the next class. So, I could just copy and paste but, inevitably, searching through everything I’ve made to get enough material feels like more work than creating a wholly new worksheet.

    When I talk about modularity, I’m talking about defining — in XML or in code — the basic structure of some exercises and stringing them together (simple past is comprised of these 10 or so modules, some are text explaining regular, irregular and the ‘be’ verbs in the past, others are exercises practicing them…) and then just saying to my app “hey, we’re starting this block on the simple past” and it adding one module to each worksheet until the block has run its course.

    It’s important to note here that this is going to be in addition to the other ‘modules’ in each lesson’s worksheet — whether they’re vocabulary review or a reading text to take home as homework. And, further, that a module is going to define how the exercise is created, but I’ll still be prompted to generate new content for it (“Enter a sentence in the simple past using word ‘ginormous’.”) (Fun fact: I’ve never taught that word in my lesson.)

Looking at what I’ve written, I’m beginning to think that maybe the unordered list might not have been the best way to get that done. Still, I think that summarizes what will eventually make the worksheet generator different from the “we do the work so you don’t have to” websites.