Wednesday, December 09, 2015
I lost my best friend today.
Since I was 17, my best friend has been the amazing cat that you see above the post. He's the best cat I've ever known. He was smart, brave, sweet, and a very good kitty. He was also very much daddy's guy. He was always there to greet me when I woke up in the morning and when I got home from work.
We've been through a lot together, we've taken care of each other, and we've always tried to be there for each other.
Unfortunately, today he passed away at the admirable age of 18. The vet was with us in hoping that he could make it much, much longer for a number of reasons, but it seems that that wasn't meant to be. Yesterday, we got word that he wasn't going to be around for much longer, so we did what we could – we bought him fried chicken (which he loved, but didn't often get because it wasn't very good for him), gave him his holiday gifts early and spent yesterday and today with him, showing him how loved he is. He ate a large amount of the chicken and enjoyed all of the cuddles.
We were both there for him when he passed away, petting and cuddling him while telling him what a good kitty he has always been and how much we love him. He's now having a well deserved rest and isn't suffering anymore. We laid him to rest next to Karyl's cat, Simba, who passed away a couple of years ago and whom he adored basically since he met her.
I will miss him greatly. Karyl and I both will, to be honest. The house will feel very empty without him in it.
To share our love for him with the world, at least a little bit, here are a few links involving him:
I will miss you very much, fuzzy buddy. You will always have a big place in my heart
Current mood: SadCurrent music: Craig Ferguson's series finale – Bang Your Drum
Sunday, August 30, 2015
TDD is a very useful tool. Done well, it offers assurance that your code does what it is supposed to do, provides a set of baked in regression tests, allows you to refactor code without worrying that you will break something in the process and acts as a sort of living design document.
It is not, however, a silver bullet. If done poorly, it can cause code to become rigid. This generally happens when people test the implementation details rather than the behavior. In a language like Python, where there are no truly private methods, it can be even easier to test implementation rather than behavior if you aren't cautious. I'll also say that it can be really difficult to effectively test Android code because TDD isn't a first class citizen in that ecosystem.
In my opinion, the possible downsides of TDD are generally far outweighed by the bonuses – especially since the downsides are usually able to be mitigated by exercising some self-discipline.
That's not to say that every piece of code you ever write has to be done with TDD. There are some small, usually one-liner style programs, that I write which I don't test drive. If I'm going to be using something once and tossing it, provided that there isn't really a danger of permanent damage if the code doesn't do what I want the first time, I may decide that it isn't worth the effort to set up a testing harness.
Now that we've got my opinions on the topic out of the way, I have to say that I don't get the hate that some developers have for TDD. I can understand a non-technical manager not understanding how writing tests (more code) isn't a drawback, but people who write software for a living are another story.
If I had to guess, I'd say it was probably some combination of fear of the unknown, a previous bad experience (whether because of lackluster tools, lack of guidance, or inexperience), or posturing on the part of the developer (after all, we are often not known for a lack of ego).
There are occasionally reasons to not test something (few and far between), but as a general rule, having the tests will only help you now as well as helping future you when you have to dig back into the code in 6 months. Not wanting all of the tools that could help you is just crazy.
This whole post was inspired by a tweet that a friend of mine re-tweeted (and its associated tweets), so let's take a little time to critique the conversation.
Shocked by the number of jobs proposed to me whose ads list "TDD" as a requirement. Are we really still doing this?— Bodil Stokke (@bodil) August 30, 2015
Yes. Because it works. I've already covered that above, so I'm not going to repeat myself.
TDD works really well for a lot of people, and that's great. Others have different ways of thinking about programming. Don't exclude them!— Bodil Stokke (@bodil) August 30, 2015
If you are working in a shop that doesn't do test driving (I'd be tempted to ask why not, but just for the sake of argument), then yes, a person who doesn't do TDD will be fine. If you are in a shop that does TDD and the person is willing and able to learn TDD, then consider helping them get up to speed. If they refuse, then they're probably not a good fit for your team/company. Sorry, but that's the way it is.
If your team all does TDD, but one person refuses to do so, you lose a lot of the benefits. The baked in set of regression tests is no longer complete. The living documentation is no longer complete. Refactoring becomes trickier. Bugs can become harder to track down. These are problems.
@makmanalp @jasonpbecker Yes, I think this is a matter of individual neurology. My architectures definitely get _less_ simple with TDD.— Bodil Stokke (@bodil) August 30, 2015
Then you're probably doing TDD wrong. In all likelihood, you are testing implementation instead of behavior. This is actually a pretty common mistake for people who aren't used to TDD and it takes some experience to get over. Heck, even people who have been doing it for a while can slip up sometimes. None of us are perfect. That doesn't change the fact that you're probably using the tool wrong.
@makmanalp @jasonpbecker If I'm TDDing with unit tests, it helps me a lot. If I'm TDDing with integration tests, I lose the big picture.— Bodil Stokke (@bodil) August 30, 2015
You don't TDD with Integration Tests, or at least not only with integration tests. You use Unit Tests to test functions (given input, check output for example). Integration Tests are used to test a series of Units (kind of like checking to see that a bunch of legos you put together actually build a wall).
@jasonpbecker TDD literally gets in the way of my thinking properly about my code in some cases.— Bodil Stokke (@bodil) August 30, 2015
Then you're looking at it wrong. Each unit test should be a condition that your function should fulfil. You only test the criteria that your code is supposed to fulfill. That's not to say that you can't spike out something you're not sure of (especially if you're working with a new language), but before that code actually makes it into your codebase, it needs to be under test, and that test needs to fail first.
@jasonpbecker In my case, striving to always do TDD would have a negative impact on the quality of my code.— Bodil Stokke (@bodil) August 30, 2015
I can sort of get behind this for one very simple reason – some things are just ridiculously difficult (if not damned near impossible) to test. These cases don't come up often, but they do occasionally come up. Other than that, test your code. For everyone's sake.
@MaggieL "You must know what TDD is" is still a bad requirement. And no, "we do TDD here and so will you" is something I get a lot.— Bodil Stokke (@bodil) August 30, 2015
I disagree. If the entire team (or company) does TDD, then yes, it is a valid requirement for the job. If you refuse to use TDD, then you don't have a place on the team for reasons that I've already outlined. In fact, I'm glad more places are making it a requirement (provided that their people write good tests).
The sad thing is that I hear these sorts of arguments a lot. Thankfully, however, I seem to be hearing them less lately. I honestly welcome constructive criticism of practices because it helps people grow. You need to be prepared to have others respond to that criticism though.
Just complaining about a methodology you don't like without valid reasons doesn't help anyone (and that's exactly what that last tweet was).
Current mood: Calm
Current music: INXS – The Stairs
Friday, April 24, 2015
I've recently started learning how to write apps for the Android platform and, since the company I work for does all of our development in a Test Driven (TDD) fashion, I'm writing my first app using the same methodologies.
Unfortunately, the Android platform apparently wasn't designed with TDD in mind. Automated Unit and UI testing currently seem to be second class citizens because there isn't a lot of good information on testing in android. There are now decent tools, but not a lot of documentation on how to use them or avoid pitfalls.
I think it's time that we work to improve that shortcoming, so my plan is to walk you through the process of creating an app from scratch while pointing out the pitfalls and gotchas that I come across on the way so you will have a better chance of avoiding them. This entry represents the end result of my Sprint 0 (setup) phase for the app. It took about a week and a half of going through online documentation and talking with co-workers to get to this point. With this, you should be able to do it in an afternoon.
Pocket Bartender. This should be a relatively simple app since it's just going to be a fairly basic CRUD app. It will take a drink name or ingredient and give you a recipe or list of recipes for that drink or the drinks that use that ingredient. I'll also probably add functionality to favorite and hide drinks.
Phone: Samsung Galaxy s5 (sprint) running Android 5.0 (Lollipop)
Tablet: Samsung Galaxy Tab 4 (sprint) running Android 4.4.2 (KitKat)
IDE: Android Studio 1.0.1
Emulator (phone): Nexus 5 API 21 x86
Before you start, you'll need to have the Java 1.8 JDK installed and configured properly since coding for Android is done in Java (I am told that Groovy also works, but I haven't looked into seeing what's required to be able to code for Android in it).
Next, you'l want to install Android Studio. Since I was working through the Udacity Android course before starting this project, I had Android Studio installed already.
Run the Android SDK Manager (Tools > Android > SDK Manager) and install the following packages:
These two packages will be required by the tools we'll install later.
Now that your IDE is installed, you'll need to enable developer mode on your phone and/or tablet (assuming that you want to test on hardware as well as in the emulator). How to do this may vary by phone maker/model, so I'll leave that portion of the exercise to you. It should just take a quick google search.
When you have enabled Developer Mode, go into Settings > Developer Options and make the following changes:
USB Debugging – ENABLED
Window Animation Scale – OFF
Transition Animation Scale – OFF
Animator Duration Scale – OFF
According to documentation, the last three settings can be manipulated via code, but it's easier to just turn them off in the Developer Options menu.
Open Android Studio and make a dummy project with a blank activity. We will be using this project later, so don't delete it after you're done with this step. When the project is created, follow the directions outlined in Step 3 under “Setting up a Device for Development” to set up your phone to be able to receive files from Studio. The steps required to do this vary by operating system.
When you plug your phone into your computer, it may not immediately show the dialog asking if you want to allow your phone to communicate via USB. If you don't see the window, don't worry. Just lock and unlock your phone a couple of times until it gives you the dialog.
You'll need to do this for each device you want to connect to your computer.
I've been told by one of my co-workers that his phone occasionally disables USB Debugging, so if you are having problems transferring your program from Android Studio to your phone or tablet, make sure the setting is enabled. Also, Android Studio occasionally fails to load the program properly, so you may just have to make sure the program is uninstalled on your phone and re-try (this happens to me on a somewhat regular basis).
Robolectric and Espresso:
While you can write unit tests for android in JUnit, the tests tend to run pretty slowly. Robolectric is considerably faster. Additionally, you can run UI tests using Espresso. Getting this set up manually is not a trivial task, but thankfully there is a project on github that will help alleviate a lot of the pain.
Download the Deckard project and follow the instructions on the page in order to get the project imported into Android Studio. The Deckard project comes with a Robolectric test file and an Espresso test file, both of which should run from the IDE as well as the command line. You may need to plug your phone into your computer in order to get the Espresso tests to run from the command line.
If you've ever done android development before, you will notice that the Deckard project is missing a lot of things. It is literally about as bare bones as a TDD android project can be and still function. We'll be fixing that later, but for now, what we have is fine.
Go ahead and change your package names to something that makes sense for your project and make sure the tests still pass. Just make sure that everything is in the same package.
At this point, the screen you get on your phone should look like this:
Dagger is a dependency injection (DI) tool for android. According to all accounts, it is considerably faster than Roboguice (which was being used heavily before).
Setting up Dagger is fairly simple. Open your build.gradle file and, make it look like this version from my git repo.
Most of the changes are pretty self explanatory since they're just adding gradle entries for dagger and dagger-compiler. However, there are a couple of changes that require a little explanation.
compile 'com.squareup:javawriter:2.5.0' is used in order to resolve a dependency conflict between Dagger and Espresso. Both tools use javawriter, but they call for different versions. This, along with the exclude calls in dagger, dagger-compiler, and espresso-core forces the application to use a version that works with both.
At this point, most of the main tools for doing TDD in android are installed. We'll probably install Mockito for using mocks later, but we don't need it right now, so we'll do that when it comes up.
Before we write our first code example of DI with Dagger, let's make a small change to the app in order to convince ourselves that it's really working (this will be the basis of the code we're injecting in a minute, so bear with me).
Open DeckardActivity.java and add the following lines to onCreate:
TextView t = new TextView(this);
t = (TextView)findViewById(R.id.text);
Running your Espresso tests should now cause them to fail (that's a good sign in this case). Open DeckardEspressoTest.java and change the .check(matches()) statement to look for “foo” instead of “Hello Espresso”, run the tests to make sure they pass and then run the application in either your emulator or phone. The resulting screen should look like this:
Now that we know that we can change the message on the screen programmatically and the UI tests will still pass with the new string on the screen, we can write our first DI module. Make a Foo interface file as well as a FooObject class file with the contents of the files linked to on my github account. This is what we will be injecting.
You'll also need to make a module file in order to handle the actual injection. In this case, the file is DummyModule. Go ahead and copy the contents of the file from my github. Note that the injects line states the classes that the module will be injected into.
Open your DeckardApplication.java file and make the changes needed to make it look like the linked file on my github. At this point, I need to point out a couple of things that will save you future headaches.
First, while you can build the ObjectGraph by using DummyModule as an argument directly, I am told that you will want to build it using the getModules method for ease of testing later.
Second, in this example, getModules returns a List of type DummyModule. If you are using more than one module, it will return a List of type Object. Logically speaking, you should be able to make the example in this file return a List of type Object, but if you try, you get the incredibly weird error that your program can't cast type DummyModule as type Object (which makes no sense considering that, as a class, DummyModule inherits from Object). I have no idea why this is the case, but it is.
Now for the step that brings together everything we've done so far. Alter your DeckardActivity to look like the one linked to in my github repo. The changes from the last time that we touched the file (to make the screen read “foo”) are using @Inject to inject an instance of FooObject, to set a string equal to fooObject's provideText return value and to set the text on the screen equal to that string.
Your Espresso test should now be red. You'll need to change the DeckardEspressoTest.java file to check for “injected foo” instead of “foo” in order to make it green again.
Now, if everything works the way it should, your tests will pass and, when you run the program on either your phone or in the emulator, you should see the following:
You're now set up to do TDD in android (minus the mocking tools, which we'll get to later). The program as it stands needs a great deal of work to get where we're going, but we're off to a good start.
In the next entry in this series, we'll start Sprint 1 tasks.
Current mood: Even
Current music: The Guess Who – No Time
Friday, April 10, 2015
Recently, some of the people where I work have started a weekly writing prompt in order to get people to blog more often. This week's topic is “How do we involve the next generation of young minds?” and was inspired by two of my co-workers building quadcopters with a group of students in the northern part of the state.
This is a very open topic and very difficult to cover in a way that is less wordy than a copy or War and Peace (or at least your average work by Stephen King). However, I think it can be approached by breaking it down into a number of subjects which need to be addressed.
That being said, let's begin.
Start Them Early
The truth is that the earlier you start to instill curiosity and creativity in people, the easier it is to get them to continue on that path. There are a number of ways to do this, but if you're looking for ways to get a small child started, Legos, Lincoln Logs, Tinker Toys, etc are really a wonderful way to get the ball rolling. They offer nearly endless ways to combine pieces creatively, are tactile (which helps a lot of people, children or not. Never underestimate the value of physically building and handling something), and are generally fairly affordable.
Realize that not everything has to involve circuitry and code. Even things like basic woodworking projects can help instill creativity and the engineering mindset. I've built everything from birdhouses and toolboxes to actual buildings while I was growing up and I learned something valuable from every project.
As they get a little older, introduce them to things like crystal radio kits, 130-in-1 experiments kits (yes, they still make those), snap circuits and even simple programming languages like Scratch and Logo. A little later still get them involved in writing code on something like a RaspberryPi (it's fairly inexpensive and if you somehow manage to botch the os, just re-flash the SD card and start over. You can even extend it in order to interact with hardware). Tangoes are also a wonderful, inexpensive tool for teaching spatially related problem solving.
You want things that are simple to get a beginner's grasp of yet versatile enough to keep their attention after they master the basics and, most importantly, make them want to learn even more.
“A mind all logic is like a knife all blade. It makes the hand bleed that uses it.”
- Rabindranath Tagore
Logic is a very important part of being successful in technology fields. However, there is another part of the equation that is often overlooked – creativity. You really do need both the ability to think your way through a problem as well as the ability to look at a problem from a completely different angle than other people at times.
We need to foster not only logical thought, but also appreciation of and involvement in the arts. I would almost argue that the type of art doesn't matter nearly as much as being involved. Painting, drawing, writing, music, theater, and countless others – all of these things exercise your brain in ways that simple logic based problem solving doesn't.
On the logical side, we need to encourage the next generation of technical people to cultivate the skills to look at situations objectively, come up with a set of possible answers, and then evaluate or work through them (revising their general assumptions as they uncover more information) until they reach a conclusion. This is the time for measured experimentation instead of just wildly poking at a problem until something happens (though, admittedly, sometimes poking at the problem is necessary in order to uncover behavior).
Encourage the next generation to ask questions. That's not to say that you should spoon feed them the answers since guiding them through the discovery process is both an extremely effective way of teaching and often fun for everyone involved. However you do it, you should encourage them to ask the “whys” and “what ifs”.
Continuing in the vein of asking questions, foster the questioning of authority. If someone says “You can't do that” they should ask WHY. If it's because doing that thing is dangerous, that's one thing. If it's just because they don't think it can be done or because of other foolish reasons (“getting above your station”, “that's not something that proper girls/boys do”, etc), they should be encouraged to CHALLENGE IT.
We are, among other things, professional troublemakers. We create and change current reality as a part of our jobs. It's what we do. Innovation is inherently disruptive. Embrace that; don't try to stomp it out of the next generation.
Encourage reading. I can't stress this enough. Fiction, non fiction, philosophy – just read. It exposes you to different voices and approaches from your own. It's literally a different view on the world, and being exposed to that will help you grow.
Quick Feedback, Small Victories
Make initial victories easy to attain. This is especially true for younger children. Defeat is frequently demoralizing. Starting off with a victory encourages people to continue. It doesn't matter if it's just making a ball bounce on the screen. Give them something that provides near instant feedback that they have done something with a real, visible result.
As they progress, keep feedback loops tight even though the difficulty of what they are doing increases with time. Yes, I realize that this sounds a lot like Agile practices.
Make it Safe to Fail
“I have not failed. I've just found 10,000 ways that won't work.”
- Thomas A. Edison
Failure, both professionally and personally, is an occasional fact of life. No matter what we try or how hard we work, there are times when things just won't happen the way we want them to.
The problem is that we have stigmatized failure to such a degree in this society that some people are afraid to even try because they might fail. This needs to stop.
Teach people that it's okay to fail on occasion. That's not to say that we should excuse laziness, but re-enforce the idea that failure occasionally happens, treat it as a learning experience, and teach others not to fear making a mistake.
Access to Tools
It may not occur to a lot of us in this field that not everyone is as well off as we are from an economic standpoint. Not everyone has ready access to the equipment needed to learn various technical skills. This is especially true in both poorer urban and rural areas.
Access to programing tools (IDEs, etc) has become considerably cheaper thanks to open source tools and educational/community licenses offered by companies like JetBrains and Microsoft. However, for some people, computers are still an expense that they can't justify (even if they are much cheaper than when I started learning to program).
That's not to mention the expense of things like quadcopter kits. Some of the things that you need access to for some projects are simply out of reach for a number of individuals as well as some school districts without outside help.
Access to Mentors
When I started out, I didn't have any mentors to help me learn how to code. The internet wasn't an option (yes, dinosaurs roamed the Earth and we had to walk to school uphill both ways). I had never even met or spoken to a professional software developer until I was in college. In fact, the only other people I knew who wrote code were a few friends in basically the same situation as myself.
It would have been much easier and a lot less discouraging if I had had access to mentors (even online) instead of having my only resources when I started out be the manual for a TRS-80 color computer and the occasional code sample in magazines borrowed from our very small public library (I told you that dinosaurs roamed the Earth at the time).
If you want to encourage the growth of a new generation of creative and technical people, you have to literally be there to encourage and guide them. Answer questions on the internet, make yourself available to schools/after school clubs and programs, and generally be a good community member.
This is the really difficult one. In order to encourage young people to go into technology based careers, their parents have to be positively involved. They can't just treat the computer as a way to babysit their child or, possibly even worse, view everything that their child does, no matter what it is, as simply “playing on the computer” like my parents did (which, I might add, included programming homework in college).
Keeping up momentum when it feels like nobody cares or you are being actively discouraged is extremely difficult. Not everyone is as hard headed as I am.
Parents don't even have to be experts in the field. They just have to be positive influences. Be curious about what your child is doing, encourage them, have them show off what they're doing to you a bit. Be a cheerleader. It's important.
Show Me The Money
Show people that there is a (generally) fun, well paying job doing work in this field and that it doesn't matter if they're a girl or a boy or even what socio-economic background they come from as long as they work at it. After all, it's important to be able to do things like pay your bills, go on vacation, and buy sandwiches.
As I said, this is by no means an easy problem, and this is only the short list of things that can be done to help, but it's a start and even if you can only manage a few of them that's better than the alternative.
Current mood: calm
Current music: Murray Head – One Night in Bangkok