Hunger Tracker 1.0

It’s out.  I made some UI tweaks and got the release build working, so you’re not including a bunch of debug code.  Here’s how I envision people using it:

1.  Install manually.  I’m working on getting it in the app store.

2. You should see something that looks like

hunger_tracker_screenshot

3.  To store your hunger:  enter the number in the upper text box and hit “store”

4.  Set an alarm for the next time you wish to track your hunger.

5.  A notification with a quiet beep and short vibrate will remind you at that time.

6.  When you want to retrieve your data, hit retrieve.

7.  When you’re done, hit clear.  This will erase all data, not just clear the screen.

Enjoy.

Hunger Tracker 0.3

I had this great essay written in my head about how good testing was great when you were learning, because you can’t copy paste tests like you can product code.  Then it turned out that it was impossible to test notifications.  Not difficult, literally impossible. The ability to test directly has been deliberately blocked for security reasons, and you can’t mock it because the relevant class doesn’t have a default constructor.  The most direct path I see right now is extending EasyMock to work on classes without default constructors, and I assume if that were easy someone would have done it already.

So here’s Hunger Tracker version 0.3, sans Aesop.  It has all the features I promised in 1.0, but there’s some UX work I want to do before calling it done.

How Tests Improve Code Structure pt 2

I’ve always admired Test Driven Development and longed for it from afar, but never had a chance to use it until I was on my own project.  Most times when you crave something this intently it’s a let down, but no, this is every bit as fun as I thought it would be and more.  It’s so relaxing, and it takes so much less mental RAM.  I won’t go back to any other way.

I keep trying to explain why it is better and exactly how it made it obvious what I needed to do, but everything I write comes out boring and I don’t think it explained it anyway.  Let’s try an analogy.  You know how when you attempt a big cleaning project the middle looks worse than if you’d never started?  And if you misjudge your energy level it stays that way, and then gets worse because you’re still living your life?  Or maybe you misjudged the amount of space something required and your plan becomes unworkable, at which point you can improvise or revert?  That’s what regular coding feels like to me.  You don’t know if something’s working until it’s all working.

I’ve been cleaning up my apartment lately, including getting rid of things I don’t want and rearranging things I have so they are more accessible/easier to find/take less space.  And I am being very careful not to do that.  I pick tasks that can be done incrementally.  If I want to move things from cabinet A to cabinet B, things in cabinet B get moved to cabinet C first.  But cabinet C doesn’t have to be their permanent home, just a pareto improvement over the old one.  I have consolidated three dressers into 1 + some other storage bins.  I will probably rearrange those storage bins and the remaining dresser as I learn more about how the current arrangement works, but I was never going to be able to plan that out ahead of time anyway.    This way I never get stuck halfway through, out of energy or realizing my plan is unworkable.

That is what TDD feels like to me.  You might technically be writing and erasing a lot more code, but the mental effort is so much less.  Every step leaves you a little bit better off, and you can concentrate your efforts on one problem at a time.

I was really unimpressed with the android tutorials I saw.  I did Udacity’s, which is officially recommended by Google, but didn’t provide reference code or a way to check your project, so if something didn’t work you didn’t know where the error was. That’s bad enough when it’s a technology you’re well versed in, but with a new tech you don’t have any debugging tools.  It’s like trying to learn a foreign grammar by having it explained to you in its own language, when you don’t even have any vocabulary yet, except your brain hasn’t been crafted by millions of years of evolution to do it.  There are other tutorials, but most of them were written for the now-deprecated Eclipse IDE.  Translating from one IDE or build system is not a big deal when you’re familiar with at least one of them, but at the beginning you don’t even know what to Google.  That’s why you’re doing a tutorial. It’s even more fun with Android because it uses a bunch of very common Java tools but requires slightly different usage than everything else.

So what I actually did was do Udacity long enough to know how to make baby’s first project, come up with a concept that I was pretty sure I could subdivide into google-able problems, and then did so, one at a time.  I learned testing basically from scratch, because the two tutorials that covered it required me to know a ton of abstract android architecture, and none of it was explained well enough to mean anything unless you had already coded.  “Make minor changes until you understand the permutations” is how every programmer I know learns, and yet no class teaches this way.

All of which leads me to believe a test-driven tutorial could be really useful.  I’m picturing a project with a few very simple UI elements, and a series of commented out tests.  Users would uncomment the tests one at a time, in order.  The test would fail. The error message would be informative, maybe there would be a few suggestions for how to solve it.  Then they would research on their own until they found a solution.  They would know they had done it right because the test would be passing. Plus they’d learn testing tools at the same time, and those are extremely useful.  This may be my next project.

TDD got me all of the features I wanted in HungerTracker 0.2 except notifications.  I’m still poking at it, but notifications require a deep understanding of several concepts I’ve entirely ignored until now, and need several moving parts to work together to verify any of them.  So here’s version 0.2, which has a greatly improved button layout and a scrollable list that shows as many or as few entries as actually exist.

How Tests Improve Code Structure pt 1

Hunger Tracker needs to persist data past the closing of the app.  Knowing nothing about Android I googled “android write to file” and used the first reasonable looking thing that came up.  This was sufficient to let me write to and read a file, which was good enough for a first try and powerful enough for me to release version 0.1.  But as I planned the next step I ran into problems.  The read function I found required me to specify the number of chars I wanted in advance.  I couldn’t spot the end of the file so I grabbed a fixed number of entries every time.  I could extract the data as strings but couldn’t figure out how to make a proper scrolling list (even though I’d done one in the Udacity tutorial).  Attempts at fixes felt muddled and high friction, which is usually a sign I’m afraid of losing data, either to a hard drive failure or to a introducing a bug and failing to detect it.

Step 1 in fixing this was setting up my github account so I had proper version control.  Step 2 was testing.  I spent a long while figuring how to properly test the kind of android class I was using (“android unit testing” being a surprisingly unhelpful search term), and then some basic tests of “The text fields that should be there, are they there?”.

The next step was to test the data storage.  But I couldn’t figure out how to unit test that.  If I tested whether the app was writing to the correct file I needed to look for the exact same file.  But that means updating the test every time I change the name of the file, which I didn’t want to do.  Plus seeing if the correct thing is written to it is ugly.  Tests should be atomic (meaning it doesn’t matter what order you run them in), but the file is persistent, meaning I either need to clear it every time or factor in what previous tests have done.  Plus I would have to shape the test around the exact storage format the app was using, but again that means making the test dependent on an implementation detail.  I could trigger writing and then reading and make sure the display element was correct, but that’s testing two different things and a unit test should only test one.

What I finally worked out was that the handling of persistent data was not actually a core function of HungerTracker’s MainActivity.  What I needed to do was separate out those functions into a separate class, and then use mock objects to make sure the expected calls were made.  E.g. instead of the app writing to a file and the test looking at the exact file and verifying the writing, the app calls the HungerTrackerWriter object.  The test swaps out the real HungerTrackerWriter with a fake one, and monitors that the expected call is made.  This leaves the HungerWriter proper tests blissfully unaware of the implementation details while still verifying that the app is doing what was expected.

[Technical details: somewhere I read that the android junit framework handled mocks easily. This was something of an exaggeration. It has built in mocking for a lot of Android specific classes, but nothing for user created classes. There are many well regarded Java mocking libraries, none of which provided comprehensive instructions that worked for me. Apparently they integrate weirdly with Android? My first round of mocking was hand-written, just so I could work on test code. I never did get the best regarded library, Mockito, working, but I eventually cobbled together a set of build instructions that made EasyMock work]

You might think that making that big a change in order to make something more testable is the tail wagging the dog, but as I was doing it something magic happened.  Those problems with reading exactly as many entries as there were and putting them in a list (as opposed to reading exactly 10 and dumping them in a string) were suddenly much easier to conceptualize.  What seemed so muddled when it was part of HungerTracker was suddenly easy to think about when it was part of HungerTrackerWriter.

If you are super curious, here is the code before the refactor, here is the code after, and here is the test code with mocks.

Testing Android Software

Dear frantic and desperate programmers: if you are looking for an example of a populated android activity test file, go here.

Dear everyone else: you may wonder why that was necessary.  Let me explain.  There are five billion tutorials on how to build android apps and two on how to test them.  Both are full lessons requiring a lot of knowledge of android to make sense of them and are based on Eclipse (deprecated) and not Android Studio, neither provides a decent sample file for steal-and-mutate learning.  For those of us who want to write tests because we are learning to program for android and are worried a new technique might break our lovingly created app in ways we don’t know enough to fix, this is frustrating.

[For the slightly more advanced among you: yes, you could try searching github for the name of the class you know must be involved in your testing.  Unfortunately the push for testing means that 95% of what you find are stubs with no actual tests.]

To be fair, I’m pretty weird in wanting to write tests so early.  I complained to a stranger at a party that work on Hunger Tracker had stopped because I couldn’t find an android testing tutorial and he expressed surprised, because he’d watched people release much more complicated apps without a single automated test.  I know that works for some people, but it would drive me absolutely nuts.

The point of testing isn’t to make the product work.  The product is going to work, or you’ve failed.  The point of testing is to make your work on the project faster and less stressful.  Every time you change anything, and sometimes even when you’re sure you’ve changed nothing, you risk breaking something. The more time or changes that pass between you breaking something and you noticing it is broken, the more effort it takes to fix.  You could manually test every time you change every little thing, but it’s boring, time consuming and prone to error.  Computer science selects for the opposite of people who are good at doing the same thing over and over again.

So you do the programmer thing and write a program to do it for you.  It’s just that the program is tests of the software.  You can run this new program as often as paranoia or check in rules compel you.  This frees up your time from manual testing, your mind from tracking your changes and worrying what might possibly have broken, and decreases the time to notice breaks. The mere act of writing the tests often encourages good code structure by making you think about it rigorously, the same way writing a program makes you define your problem until you practically don’t need a computer to do it.  And in my particular case, when the project is as much about learning as it is producing anything, it’s good practice.

Good testing is especially critical in my case, because I’m working on this project in little bits at a time.  If I break something and don’t notice it until two CLs later, I might as well be debugging someone else’s code.  I know what people about the devs whose code they are forced to debug without tests or documentation, because I’ve said it, loudly, and at length.  I may have expressed a wish for weapons.  I would hate for someone to think that about me, especially myself, and testing is the cheapest way out of it.

Hunger Tracker 0.1

When I started this blog I intended to leave programming for medicine fairly soon.  After a long medical leave that let me recover from burnout, I realized that programming is actually a really valuable skill and before I throw it away and spend several years in school, I should see how far it can take me towards my goals.  My goals are unchanged (mostly around nutrition and mental health, but with some bonus input from Effective Altruism), but maybe there’s a better way I can contribute.

Eventually this means founding or joining a company working on something I care about, but I’m still not capable of consistently working sufficient hours to work with other people.  But I can play on my own projects with no coordination costs, so I started learning to program for android.  Meanwhile on the health end, my nutritionist informs me there are states of hunger between “unpleasantly bloated” and “would shank an infant for juice” that are useful to experience, and that the first step to achieving that is tracking my hunger consciously.  She meant with pen and paper, but I am an engineer, so I wanted something on my magic pocket computer to do it for me.  I’m sure something exists on android that would do this, but I couldn’t find it, so I did the logical thing and started developing my own.

Thus was born the Hunger Tracker app.  Here is my dream feature list for Hunger Tracker:

  • Alarm goes off at pre-set or random times (your choice), to shut it off you enter a number between 0 and 9, representing your fullness level.
  • Timestamp + fullness level data is dumped…somewhere, I don’t know.  A google docs spreadsheet would work for me but there’s probably other services I should integrate with.
  • UI not actively offensive

Here’s what version 0.1 does

  • No alarm, user must manually call up app.
  • User enters number in ugly ass UI.  Actually user can enter any arbitrary string, but don’t, it will break the retrieval.
  • User can retrieve first 10 numbers entered.  Any further entries are skipped, if there are too few entries the last one is repeated.
  • It’s a debug build rather than a release build because Android Studio won’t produce a working release build and fixing that is not at the top of my priority list.

If you are interested, you can download version 0.1 here and install it the usual way for non-market apps.  If you are spectacularly interested, you can check out the source code at github.  Comments are extremely welcome

My next step is not actually features, but testing, which I will explain in the next entry.