Header text

EssayTagger is a web-based tool to help teachers grade essays faster.
But it is not an auto-grader.

This blog will cover EssayTagger's latest feature updates as well as musings on
education, policy, innovation, and preserving teachers' sanity.

Monday, November 28, 2011

Latest update: Rubric quality level direction

This was another feature that was requested at NCTE.

You can now specify if your rubric quality levels progress from best-to-worst or from worst-to-best. You'll find the setting on the Create Rubric screen under the first quality level input field

When you click on it you'll see the two simple options:

The direction determines which end of the rubric gets tagged with green (best) markers or red (worst) markers in the grading app and in the aggregate results grid.

The worst-to-best direction opens up the possibility of using massive year-long rubrics that have way more than five quality columns. We spoke to one publisher at NCTE whose system uses 14 quality levels. Sounds intense, but each individual assignment only targeted a sub-range within those 14 levels. An early assignment's rubric might only go from level 1 to 5 whereas an end-of-year assignment's rubric might range from columns 10 through 14.

Friday, November 25, 2011

Latest update: Student uploads!

Update 12/16/2011: This process has changed slightly and a new video has been recorded to cover the latest version of the student upload process.


At NCTE a lot of teachers asked us if we could have students upload their own essays. At the time - last weekend - the only option was to have teachers collect and upload the documents themselves. Not ideal.

I began telling people that my goal was to support student uploads by this Friday (today!). I said it to enough people that I realized it was now a promise!

So I made good on that promise.

In the Detailed Assignment View you'll now see a student upload URL:
The upload URL contains a five-character code that is unique for each assignment. Simply provide this link to your students and they'll be able to hand in their assignments online themselves. You can also still upload documents for the assignment yourself.

Here's what they'll see:
No student login is required; the link goes straight to the upload page.

We ask for their first and last name so that you can identify whose work belongs to whom once it's uploaded. They also must specify the class section they belong to so you don't have to sort through them later.

I also added a checkbox that basically says "I swear this is my work." It won't stop plagiarists, but it's one more piece of leverage you'll have over them.

All fields are required and they cannot submit until they have been completed.

I also built in a lot of safeguards against bad document files and incorrect file formats. I had a lot of problems with this on moodle when I'd go to open a kid's document and it was all garbled or in a format I couldn't open (e.g. ".pages"). I didn't want to relive that here.

For starters the "select document" button will only allow students to select a DOCX, DOC, RTF, or TXT file. These are the only formats we are currently able to support.

When they hit "Submit" their document is uploaded and they are forwarded to a status page:

Once the processing is complete they'll see their document embedded in a confirmation page:

At this point they can see their document and confirm that there weren't any errors along the way. Each essay is also timestamped with a submission date/time so you can see who was on time (due dates are configured in the Assignment setup). Submit time is set by our server - not the student's computer - to guarantee consistency and integrity.

Students can upload their document multiple times if they have revisions - you'll just see multiple copies listed under their name with different submit times.

I recommend that you try out the process yourself and demo it for your students in class. You can easily delete the test documents you upload.


As with everything on the site, I tried to make this as foolproof as possible - which is an added challenge when you're talking about asking students to follow instructions!

**Note: We attach the students' first and last names to the document filename but we don't yet support full student integration into the site. That'll take a bit more work but is a high priority on my to-do list.


Key takeaways:
  • Each assignment has a different, unique upload link.
  • Tell your students to wait for the confirmation screen.
  • You can still upload documents yourself if you need to.
  • The site supports DOCX, DOC, RTF, and TXT files.

Tuesday, November 22, 2011

Latest Update: Rubric aggregate performance data!

I've been promising this one from the start!

You can now see how your class as a whole performed on a particular assignment!


Each grid position tells you the incidence rates of each rubric element over the possible quality levels. The tiny number in the bottom right is the actual number of comments that counted towards the total from that grid position.

the full report
It's such a simple calculation for the database to do that I was able to write it in one straightforward request. This is the power of databases!! Yay!!

I've also experimented with adding some color coding. In the version that's now on the website (but not pictured here) the grid cell with the highest percentage is outlined in its quality level's associated color  - green for best, red for worst, yellow for in-between. We'll see if folks find the color border useful or not.

And this is just the beginning. We can pull so much more out of the database! Just tell me what you want to see!

Friday, November 18, 2011

Hello NCTE 2011!!


As evidenced by the many blog posts here that I don't understand, Keith has been coding like a madman since we started this thing in June. But it's now time for our public unveiling at NCTE 2011 in Chicago!

For those of you who don't know, NCTE is the National Council of Teachers of English and their annual conference just happens to be in Chicago this year and timed perfectly for our launch. So we knew we couldn't miss it, as it represents the single greatest gathering of the target audience for EssayTagger - and it's right in our home town!

Things are just getting started here, but armed with a couple of banners, laptops, and an awesome gift basket giveaway (more on that later), we're ready to show off our hard work to English teachers!

Friday, November 4, 2011

Avoiding Session conflicts on save() due to Hibernate lazy loading

With Java Reflection we can force Hibernate to instantiate lazily-loaded (aka proxy) member objects before we attempt to save the containing entity.

Yesterday I posted my Spring + Hibernate + Cloud SQL sample project code to help other developers get up and running with Hibernate and App Engine.

Today I had to make some DB changes and slightly rearchitected my code. That uncovered a problem. I'm using Spring's OpenSessionInViewFilter to support lazy loading in the view layer. It's dang convenient. And it's currently configured for singleSession=false. That means that it'll use a read-only Session for gets but a separate save/update Session for writes.

Calling getHibernateTemplate().save() had been working fine until my code reshuffling exposed a problem. If an entity has any member objects that have not yet been initialized (due to lazy loading), the save() call will throw a session conflict exception. Specifically:
org.springframework.orm.hibernate3.HibernateSystemException: illegally attempted to associate a proxy with two open Sessions

Here's a simple example:

The problem is that the read-only Session created the lazy-loading proxy Owner within oldCat but hasn't been asked to initialize the proxy yet. Then the save/update Session gets the newCat and tries to access its Owner and now both Sessions are trying to handle the non-initialized proxy, thus the "two open Sessions" complaint.

So folks will generally do something lame like this to get around it:

I'm not judging. I've done it in the past too. But it's clearly a crappy solution. If that chunk of code doesn't need to access any fields in Owner, it shouldn't have to just to make the DAO/ORM layers happy.

So here's my new solution: programmatically search for non-initialized proxies and call getHibernateTemplate().initialize() on them before we try to save.

This requires Reflection to inspect the Cat and look for fields that might need initialization.

Unfortunately my DAO doesn't have permission to access Cat's private member variables. So instead we scan for the public getters and look at their return types. If the return type is a domain object that is mapped by Hibernate, then we "get" it and initialize as needed.

How do we know it's mapped by Hibernate? I'm just filtering on the return type's package name; I only care about DTOs from com.essaytagger.model. The proxies that need initialization are easy to spot--they return true to (obj instanceof HibernateProxy) tests.

Here's the new version of my _GenericDaoHibernateImpl's save() method (my GenericDAO approach is kind of complicated. Track back through the Spring+Hibernate+CloudSQL post first and then see the more in-depth discussion of the original Objectify-based version that was adapted from David Chandler):

This GenericDAO work is getting me more and more into Java Reflection. It's pretty dang cool! But I'm not completely confident in this approach just yet. We'll see if any other odd use cases popup before we call this a win.

What do you think? See any problems down the road?

Wednesday, November 2, 2011

Spring + Hibernate on Google App Engine's new Cloud SQL!

Full project code for a Spring + Hibernate version of Google's "guestbook" sample webapp that accesses Cloud SQL!

Download the project code!

UPDATE: See the new version of my GenericDAO's save() method to avoid Session conflicts due to lazily-loaded member objects.

I was super-thrilled that Google approved my application to be part of the Cloud SQL limited preview. In gratitude I wanted to share the sample code that I used to do my proof-of-concept tests for accessing a SQL DB in App Engine.

I'm accustomed to using Hibernate with annotations for my ORM layer and was excited to be able to go back to that world in App Engine. But annotations won't work with App Engine as long as they limit the JPA spec to v1.x (I tried and failed to get around the limitation). So that means we're back to using Hibernate Tools and reveng.xml to generate the Hibernate *.hbm.xml mapping files. It's a pain and it feels like it's 2003 again, but whatever. Once you dust off that part of your memory it's not so bad.