066: Let’s talk Immutability, Value Types and AutoValue with Ryan Harter

In this episode, we talk to our good friend and immutability champ Ryan Harter. We start off talking about the benefits and disadvantages of immutability, then we dive into Value types and the subtle difference with Value types. Finally we close out by talking about AutoValue and how you can extend it using the super nifty auto-value extension system for functionality like Parcelability, Json parsing etc.

Download directly

Show Notes

About Ryan

References

AutoValue

AutoValue extensions

Misc

Contact

Transcript

Donn Felker: Kaushik, we’re back again, my friend.

Kaushik Gopal: Yes, we are. It’s another morning. What’s the time there?

DF: It’s 9:45 in the morning. It’s pretty early for you, right?

KG: Yes, it’s 6:45 here.

DF: Thank you so much for getting up that early. I know it’s difficult, especially when you’re working all hours of the night for a startup.

KG: Well, it’s enjoyable, especially when we have great guests on the show and great topics to talk about. So, who do we have on today?

DF: We have a close friend of the show, who we’ve spoken to before and know through various other channels. Today, this individual is an expert in the area of value objects, and so forth. He’s another Android GDE and an instructor on Castor.io, and is very active in the community. With that said, I’d like to welcome Ryan Harter to the show. Welcome to the show, Ryan!

Ryan Harter: Thank you! It’s great to be here.

DF: For folks who aren’t familiar with who you are, can you give us some information about your background, where you work, and how you got into Android?

RH: Sure. Let me start with how I got into Android. While I was in college, I was a Mac desktop developer. In fact, I managed all the Macs on campus. When I graduated, the iPhone was really big, so I went into mobile development. Android was still in its really early stages then, and the consulting firm I was at just didn’t have anyone who programmed for Android. So, I took up that role and became the Android lead there in 2009 or so.

Since then, I’ve struck out on my own. For the last four years or so, I’ve been a freelancer. I work with a lot of different companies on a lot of really cool projects. It’s been really good. One of my personal projects is working with five other guys in San Diego. We do graphics and entertainment apps, and one that we’re just about to release for the holiday season is called Pigment. It’s an adult coloring book app that we’re really excited about.

DF: I saw that (I think you tweeted about it or something), and it looked super interesting.

RH: It’s really fun. I wasn’t into adult coloring before, but since writing that app, I’ve been spending a lot of my free time coloring in artwork, which is also a lot of fun.

KG: For folks who’ve listened to this show for some time now, you made a guest appearance in our last IO episode. You told us some of the interesting things that you had to say, and you mentioned an app. Was that also Pigment, at the time?

RH: One of the other apps that we do is called Fragment.

DF: That’s a great name!

RH: So I hear! Fragment is sort of for the Instagram crowd. It lets you do artistic edits to your photos. You basically get to put what we call “prismatic shapes” over your photos, and they add some really cool effects and let you do some really artistic stuff.

KG: We definitely will add links in the show notes to both of these apps.

Donn and I have been really excited about this show, specifically because we wanted to talk to you about something we thought was very interesting—a topic that we’ve spent hours and hours talking about: the world of immutability, AutoValue, value types, and value objects. All of these things are super interesting, and we’ve heard that you know a thing or two about them.

RH: That sounds great. I’ve been working really closely with immutability, value types, and all of those things over the last two years or so, so it’s a topic near and dear to my heart.

KG: Let’s start off with the concept of immutability. The graybeards of our industry love this topic. They’re like, “Oh my God, immutability is the best thing. We should try to add it in, because it adds simplicity and purity.” But for those of us who don’t know what immutability is, can you tell us why we should use it?

RH: Absolutely! Simply put, an immutable object is one that can’t be changed once it’s created. It’s a really simple idea, but think about a lot of the code that you normally write. I think when most of us initially write a class, we think of it as “mutable”, or changeable—something we can set properties on. But that adds a lot of complexity that we don’t initially think about, or which may be unintuitive.

By making things immutable, or unchangeable, you need to make an entirely new copy of them if you want to get a slightly different object. There are a lot of benefits. Like I said, simplicity is a huge benefit. The reason that immutable objects are so simple is clear if you think of an object like a credit card transaction. If you can always change all of the properties of a transaction (the transaction time, the customer ID, etc.), it’s really easy for that object to get into an invalid state, because there are so many ways it can change. Immutability offers simplicity, in that you know it’s always valid once you create it. That’s one of the really big benefits of immutability.

The other big benefit (in my mind) is that immutable objects are thread safe by default. If properties can’t change, you never have to worry about another thread changing the properties of a class out from under you.

DF: Let’s take a step back. When we’re talking about how objects can’t be changed, someone who is looking at immutability as a beginner may be thinking: “Well, I can just create an object—but how do I make a particular object immutable, so that it can’t be changed?” What does it look like if I were to build this by hand? How would someone go about making an object immutable?

RH: There’s actually more complexity to this than you might initially think. If you follow the normal, plain old Java object path, you create an object which has private members (that’s important), and then use getters and setters. The most obvious (and simplest) step is to just remove the setters. That’s step 1: remove setters from these classes, because you can’t set values once they’re created.

But then we move into the things that people tend to not think about. First of all, Java classes can be subclassed by default. You need to make the class final, so that it can’t be subclassed. If you don’t, you can end up in a situation where, say, you have this credit card transaction which you thought was immutable, but some malicious programmer or developer who’s not paying attention is going to subclass that and make it mutable. So you want to make the class final.

The final thing to do is to make all the member variables final. That means that once they are created, you can’t change them.

DF: Quick question making member variables final: if the member variable is final, does that mean that I have to provide that value through the constructor?

RH: You have to provide the value at creation time, which means (depending on how closely you follow Effective Java) that it could be in the constructor or in static factory methods.

I may be getting ahead of myself, but speaking of static factory methods, one of the challenges of immutable types is that you sometimes want to slightly modify something. Maybe you want to copy something and change just one property. Static factory methods give you a really easy way to do that. You can either make either static factory methods that make another credit card transaction object (or whatever this object might be), or you can make copy methods that will return a new object, with all of the same properties (or a few changed), without changing the original object. You do have to set all of your member variables at creation time, but using things like static factory methods makes that really flexible.

DF: I’m sure someone who’s listening right now is thinking, “Well, what about reflection? Can I change these value types with reflection?”

RH: That’s one of the questions which we get in the AutoValue community quite a bit, and it’s one of the downsides. As far as I know, there isn’t a way to prevent changing these values via reflection, since you can change the modifiers by using reflection, so you can remove the final modifier.

KG: A quick follow-up question: specifically in the world of Android, immutability was initially seen as a negative thing. Why is that?

RH: One of the challenges of immutability is overhead. Since you can’t change the values of object properties, you need to make a new copy if you want to modify anything. That adds overhead for the garbage collector (and for memory management in general). That’s a challenge.

For instance, on my app Fragment, you can modify all of these settings on photos using your fingers, by brushing rotating, and all of that. Initially, I tried to use an immutable state object to record an Undo stack. That’s a pretty straightforward approach. But when you rotate, there are so many settings that are changing all the time. That adds a lot of overhead—a lot of new objects being created, and a lot of letting the garbage collector collect old objects. So, there are some cases (depending on how frequently your properties need to change) that immutability might not be for you.

KG: Basically, if you have a requirement in your application where you have a ton of objects being generated because of immutability, that may be a case where you have to rethink its applicability. In other words, are you actually getting the benefits of immutability?

Do you think that’s a fair summary?

RH: Absolutely. In the case of Fragment, I made the state objects mutable.

KG: I think I now have a decent understanding of immutability and its benefits and disadvantages.

Earlier, you referenced “AutoValue”. I know that (for all practical purposes) AutoValue is something which helps with the concept of immutability. But what exactly are these things that people also talk about called “value objects” and “value types”?

RH: A value type is an object whose equality (when you’re comparing two of them) is dependent on the values of the properties, not the actual object instance. Going back to credit card transactions, if we were to compare transactions, comparing whether they are the same instance (i.e. in the same memory space in the JVM) is unimportant. Instead, we care about whether they both represent the same transaction. I like to think of a value object as something whose importance is determined by what it represents, not its actual instance.

KG: Recently, I saw a tweet by Martin Fowler. As we all know, he’s one of the graybeards in our industry. Usually, if he publishes something, you should go back and read it, because he has some very interesting and intelligent things to say. He recently updated his article on value objects, and folks who are interested in learning more about value types and value objects, and really want to dive deep into the nitty-gritty details, should take a look at that.

I know that you’ve done some amazing work with AutoValue. So, now that we have an understand of immutability, value types, and value objects, where does AutoValue fit in? Is it basically a library that helps us with immutability? Is that its sole purpose?

RH: AutoValue is an annotation processor that basically helps you generate a lot of the boilerplate which goes into writing immutable value types.

KG: What is the additional boilerplate? If I remember right, you said it’s only setters and getters, but is there anything else that’s involved? I’m trying to understand what the benefit of AutoValue is. Where does it come into that picture?

RH: We talked about how we need to finalize everything and remove our setters for immutable types. For value types, specifically, there’s a little bit more to do. We have to override equals(), toString(), hashCode(), and all of that. We have to make sure that when we do compare objects (since this is a value object), equals() is true if the property values are equal, and that sort of thing. AutoValue will generate all of that really tedious boilerplate for you.

KG: You brought up a great point. It just hit me now. You mentioned the difference between value objects and immutable objects. I think there’s an interesting point to be made there. Immutable objects are purely about the fact that they don’t have direct references, and you cannot change the values in them. But with value objects, there is this concept of overriding equals(), toString(), and that stuff. Why would I need to do that again, just to refresh our memory? Why would I need to override equals()? If I just compare two Java objects, doesn’t that work? Shouldn’t the equals() method work, or is there something else to this?

RH: This touches on the heart of value types. The way that Java compares objects in the default equals() method is by the memory addresses of the objects. A really good way to see this is by looking in the debugger. If you set a break point somewhere in the debugger and look at a variable that you have, you’ll notice that there will be a string attached to it made up of nonsensical numbers and letters.

KG: Like a hash code, right?

RH: Exactly. That’s the memory address. Anyway, the way that Java compares objects is by comparing the memory addresses. If objects 1 and 2 both point to the same object in memory space in the JVM, then they’re considered equal.

But that’s not what a value type is. A value type says that if object 1 represents the user “Kaushik Gopal” and object 2 (a different object in memory space) represents the same user, they’re both equal. What AutoValue does is it makes that comparison by saying, “Does Object 1 match Object 2’s first name, last name, User ID, and whatever else there might be?”

KG: Interesting. So it actually goes through the fields, looks at their “values”, and then establishes that relationship if they’re actually equal, versus just asking if the “x456” reference is equal to “x123”.

RH: One of the things that makes this very important is that if you want to compare objects for both hashCode() and equals(), you want to make sure that two objects representing the same thing are considered equal. equals() is obvious, but a lot of us don’t think about hashCode(). The reason that’s really important is because if you want to use the object in a set, sets can only have one of each object. Equality is really important there and it uses hashCode() to determine that. And if you want to use it as the key in a map…when I update the values of Kaushik’s favorite things, and use “Kaushik Gopal” as the key in that map, it’s going to use the hash code to determine if it’s updating the right objects.

KG: Wow, there are a lot of details that go into these things.

DF: If folks really want to dig into equals() and hashCode() a little bit deeper, that’s in Effective Java, by Joshua Bloch. We’ve also done two episodes on that. Back in episode 31, we talked about overriding equals(); and in episode 34, we talked about overriding hashCode(). We have some content there if folks are interested.

This AutoValue stuff is super interesting, and I want to go use it immediately. How do I get it? How do I use it? How do I install it? Is it a JAR? What does it look like, in practice?

RH: As I mentioned, AutoValue is a compile time annotation processor. That means that it’s distributed as a JAR. You can use Gradle, Maven, or whatever you use to add it. One of the important things to note (especially for Android with Gradle) is that we put usually most of our dependencies in the compile configuration. For instance, you might write:

dependencies {

compile "[name of support library package]"
}

You don’t want to do that with AutoValue, because it’s an annotation processor that runs at compile time. It doesn’t actually add its dependencies into your compiled APK. The reason that’s important is that when you go on something like methodscount.com and look at how many methods are in there (since you don’t want to go over the DEX limit), it doesn’t make a difference, because AutoValue doesn’t get included in your final app.

The way to do it in Gradle, then, is to use the annotation processing tool (APT) configuration. That makes sure that the tool is available at compile time for annotation processing, but is not bundled into your final app. AutoValue (which is a Google project on Github, by the way) specifically points out in both the documentation there and the documentation for all of the extensions: “Use the APT or provided scopes for this sort of thing.”

Once you have it added as a dependency, you need to add the AutoValue annotation to an abstract class. The way that AutoValue works is that you write an abstract class as your value object, using abstract methods for the properties, and you simply add the AutoValue annotation. The next time that you compile, AutoValue will generate an implementation of that abstract class for you.

So the reason that it does this is because one of the ideals of AutoValue is that it should be a transparent API. Your users (if you’re writing a library) or other developers on your team should never need to know or care that you used AutoValue to make these value objects. When you create an abstract class, you’re effectively writing the API for your value object, and that’s what users are going to interact with is your class. The fact that it is implemented by AutoValue is unimportant to users.

One of the drawbacks to this is that you can’t use constructors. Because this is an abstract class, we don’t have constructors. But that’s actually a benefit, because it allows us to follow effective Java item #1: “Use static factory methods”. With AutoValue classes, your users will simply call a static factory method to provide whatever properties they want. Then the static factory method is going to internally construct the AutoValue generated object.

KG: So this is a feature, not a bug.

RH: Exactly.

DF: If this gets built at compile time, do I check these files into source code?

RH: No, not the generated files.

DF: I guess those are put in the “Generated” folder in the build output somewhere.

RH: Exactly. Those are going to be inside your build folder. Just like you don’t check in compiled class files, you wouldn’t check in these.

KG: That makes sense.

You mentioned that I have to use abstract classes, which means I can’t use constructors, which means I’d have to build my object. In that case, do I have to use builder methods? Also, since we’re on a roll with reducing boilerplate through AutoValue, is there some alternative that I can use to doing that?

RH: I’ve mentioned static factory methods, which are great if you have value objects that only have a few properties—but, as we all know, that never lasts very long. So, AutoValue also has support for builders. Basically, this ends up being another abstract class which you annotate with AutoValue builder annotation, and it generates a builder class for you. This builder, if you’re unfamiliar with the pattern, basically allows you to set all of the properties via methods, and then (once those are all set) actually build the final object.

There are other languages out there that use named parameters when you call a method. Java isn’t like that, right? You don’t say, “Create User. First name: ‘This’. Second Name: ‘This’.” You just list them in order, which gets really confusing when you require a whole bunch of strings, or something like that. A builder lets you set those properties by name, so it’s really fluent and easy to read.

AutoValue can generate that for you. Just like the AutoValue classes, the fact that you used it to generate the builder is unimportant to your users. It’s another abstract class that you simply write the API for, and AutoValue generates the code backing it.

KG: That’s a very interesting design goal. Technically speaking, because it’s an abstract class, I could come back tomorrow and say, “Actually, I don’t want to use AutoValue”, and swap it out for something else, but my API has not necessarily changed.

RH: Exactly. That’s one of the core tenets (and benefits) of AutoValue. For one of my clients, I wrote an SDK that customers were using. We used AutoValue to create these immutable value types, and our customers never knew or cared. If at some point we needed some functionality—say we needed them to be mutable instead of immutable—and AutoValue no longer fit, they were abstract classes, so we could just create our own implementation and the customer never knew.

KG: That’s pretty slick. One last question I had about the implementation of AutoValue. I haven’t used AutoValue as much as I would like to, but I have noticed that generated classes have this “autoValue_” prefix. What’s the deal with that?

RH: The autoValue_ prefix is for the classes that AutoValue generates behind the scenes. But as we mentioned, given this ideal of a transparent API, your users will never use that; and you, when you use that class elsewhere, won’t use the prefix. You’ll use it internally in your static factory methods; and when you want to construct the actual implementation of your abstract class or builder, you use the autoValue_ prefix. But outside of your implementation and the AutoValue annotated abstract class, you wouldn’t use that.

Actually, you can’t. The classes that AutoValue generates are package private. This is part of their transparent API. If you distribute a library that uses AutoValue to generate its immutable model value types, users are never going to see the implementation because they’re package private.

DF: You talked about a couple of the benefits—mainly about the compile time only dependencies, the invisible API, and that users never know that you’re using AutoValue. What are some other benefits? I’ve been an IntelliJ user for a long time, and I wondered right away: “Why don’t I just use IntelliJ templates? What’s the difference?”

RH: IntelliJ does a really good job of creating templates and generating all of this for you, but here’s the challenge: suppose you’ve made an immutable value type. You used IntelliJ to generate getters, setters, equals(), hashCode(), toString(), constructors, and whatever. Then, six months later, you need to add a property. Now you have to add that member variable into the class, and you need to remember to delete and recreate the existing toString(), hashCode(), equals(), etc. The challenge is that it’s really on the developer to remember that they need to regenerate all that any time they update anything in the class. The AutoValue ideal is that that’s a waste of developer energy. If we can generate all of this stuff, we can do it every time we compile. That way, it’s always up to date. You never have to worry about forgetting to update the equals() method.

DF: Oh man, I can imagine how many times that would come back to bite you.

KG: Yeah, I didn’t think about that, but you’re totally right. If you change that object later on, it’s going to be a pain.

While we are on a roll with these benefits, what are some other benefits? I know we briefly touched on the thread safety thing. Are there any other points you want to add in respect to thread safety?

RH: Just to reiterate, now that multi-threading is so easy, thread safety is a big concern. Suppose you have a value type (say the credit card transaction), and some other thread (say a service thread, or something like that) changes properties on that instance. Then you run into issues. You can never be certain that the value you’re showing in the UI is current. But since AutoValue creates immutable value types, it gives you thread safety for free. You know that if you have an instance of an AutoValue type, it’s always going to be valid. It will never be out of date.

DF: That’s true. It comes back to immutability.

In a blog post last year, you announced AutoValue extensions. What are AutoValue extensions, how do I use them, and why are they useful?

RH: AutoValue by itself is super useful, and I’ve been using it for a long time. But it does one job (which it does it very well): generating immutable value types. As an Android developer, that’s difficult for me, because I want lot of the value types that I’m interested in to be Parcelable, for instance. That was the big driver behind extensions. I can get into some of the details about that a little bit more, but the basic idea is that I wanted more from these implementations. I wanted to be able to customize them to fit my needs.

About two years ago, I went to the AutoValue project, which (as I mentioned before) is a Google project that’s hosted on GitHub. I noticed that there were other people asking for extensions, so that they could extend AutoValue and what it can do. The alternatives of the time were forks of the project—other projects that copied the implementation of AutoValue and extended it to different needs. But the problem is that that’s not mix and match. If I want Gson support and Parcel support, I have to pick one or the other, because these are forks. They don’t work together.

KG: It’s extending vs. implementing.

RH: Exactly. So one summer, I ended up working on AutoValue, writing extension support into it. The idea here is that there are other annotation processors which you can add on to AutoValue. AutoValue does a lot of stuff internally that’s really unimportant if you’re a user. It doesn’t matter what you name the methods, since it figures out if there is a builder present. All of that stuff is done really well internally, so it’s very flexible.

What these extensions do is hook into AutoValue, after it’s already figured out all the details about your annotated classes, and provide added functionality. A good example of this (actually, the first extension that was written) is the AutoValue Parcel extension. What this did, like I said, was add Parcelable support to AutoValue.

One of the things that I wanted to do with this was to make it super easy for developers. If you want Parcelable and Gson in addition to AutoValue, I didn’t want you to have a 180 character long line of annotation that you’re adding. Basically, since this ties directly into AutoValue, all you have to do to make an AutoValue class Parcelable, using the AutoValue Parcel extension, is add “implements Parcelable”. That’s it. The extension is will know when that’s processed that it needs the Parcelable bits generated too, and it’s will do that automatically behind the scenes. You’ve literally added two words to your class, and you get it all for free.

KG: That’s pretty slick.

DF: That’s like magic.

RH: That’s certainly the goal.

DF: I’ve used AutoValue Parcel, so thank you for that. It works fantastically well. What other extensions are available?

RH: When I wrote extension support, it was prompted by Parcelable, but that’s not the only thing it covers. It was meant to be flexible. One of the things I did right off the bat—not only to make it useful for me, but also to demonstrate this flexibility—was to write extensions for Gson and Moshi. If you haven’t used them, they’re two JSON serializers. If you work with any sort of Web API, you’ve likely worked with JSON, and probably even used one of these already. What those extensions do is generate type adapters, so that you have a type-safe way, without reflection, to serialize and de-serialize your value types in Gson or Moshi. That’s a really useful extension.

Another extension is for Firebase Datastore. I’ve been using it on my latest Firebase projects, and it’s really useful. It lets you easily get your value types from and put them into the Firebase Datastore. If you use SQLite instead of Firebase, as many of us do, there’s also AutoValue Cursor. It helps you read value types out of cursors and write them to content values objects, so you can write them into your database.

Lastly, there’s an extension by Square called AutoValue Redacted. Since Square works with finances, if they log or print objects using the toString(), they have a need to exclude certain values, like account numbers and things like that. Redacted adds another annotation (the “Redacted” annotation) that you can put on any property in your AutoValue class, and that property will not be included in the toString().

DF: Do you know how many times I’ve written that myself?!

KG: That’s so cool! I can add Redacted to all my passwords—and maybe my music choices!

DF: I’ve been using AutoValue for a while, but I recently ran into a couple of developers who are using a different library called Project Lombok. From what I can tell, it looks like an annotation processor that does similar things, like reducing boilerplate. How is this different from AutoValue?

RH: Project Lombok does very similar things to what AutoValue does. Its goal is to reduce boilerplate, and it actually does a lot more than just value types. It will generate a lot of what your class needs—constructors, different types, and all sorts of stuff like that. What’s interesting about Project Lombok is that it masquerades as an annotation processor, but it’s not a true annotation processor, in the sense that it doesn’t comply with the annotation processing tool spec. The documentation for Java and Java SE says that an annotation processor can generate new classes, but that’s all it can do. It can’t modify existing sources. That’s the underlying reason why AutoValue uses abstract classes and provides an implementation, as opposed to letting you annotate any class and providing the implementation within that class. That’s forbidden by the spec.

Project Lombok has found a hack for this. They use private APIs in Java SE and the Eclipse Compiler for Java (ECJ) to modify the abstract syntax tree (AST). Basically, an annotation processor is provided an object-based representation of your source code—things like a class object, which has method properties on it that represent all of the methods within your class. An annotation processor has those provided so that it can learn things about your class and source code, and then generate a new class. That’s how AutoValue works.

Lombok uses these private APIs to actually modify the AST. With Lombok, you’re not using abstract classes and getting a different implementation. You actually annotate the class itself, and it modifies that in the compile phase. By the time it’s written to the class file, it actually has the implementation.

That’s actually one of the reasons I don’t use it. There’s some inherent risk there. It’s using these private APIs, and using the annotation processing tool in a way that’s forbidden. If you want to use it (a lot of people do), that’s perfectly fine. You don’t really have to worry about your app breaking at runtime, since this is a compile time thing, but you still risk having to re-implement everything.

KG: So you’ll know beforehand if things go wrong, but if they do, it potentially involves more work. Also, Project Lombok has been around for some time, so it isn’t like, “Oh my God, this is going to break with the new release of Android Studio or something.” Things aren’t going to break. But that’s good to know.

RH: It’s a great project. I know a lot of people who have used it, and I’ve even used it in the past. It’s a personal choice.

KG: You know what I think the true genius behind Project Lombok is? It’s the fact that they have “Project” as a prefix! When you create anything, calling it Project X immediately adds so much legitimacy. I think Project Lombok sounds much better than just Lombok. If you build something called “Project AutoValue”, I’ll that, because it sounds pretty legitimate.

I want to just remind folks that, while we’ve talked about AutoValue a lot, AutoValue is part of a suite of libraries that Google has created. It’s a collection of source code generating tools. So there’s AutoValue, AutoFactory, AutoService, and Common. This is the whole suite that they made—out of which, AutoValue is one that most Android developers have found tremendously useful, especially if it’s in conjunction with an extension like AutoValue Parcel.

RH: Yeah, it’s a great suite of tools. I actually use some of the other tools. All of my extensions use AutoService.

DF: I’ve used that before too, as well as AutoFactory.

KG: Ryan, this was amazing, and I think we could keep going on and on. I have so many interesting questions to ask. But I figure that you’ll have to get to work at some point, so we don’t want to keep you on. Thank you so much for coming on today’s show and helping us understand about AutoValue.

RH: Thank you for having me! It’s been great being here.

KG: If our listeners want to reach out to you with more questions, or want to ask for more ideas and stuff, what’s the best way to do that?

RH: The best way to reach me is on Twitter (@rharter).

KG: Perfect. You also have a blog where you write some amazing posts.

RH: I do. Since I started doing Caster, I haven’t been writing as much, but my blog is at ryanharter.com. In addition to Caster, there’s some really good information about AutoValue and lots of other Android coding topics there.

KG: I hear that if folks actually want to meet you in person, there’s going to be an opportunity soon.

RH: There is! I go to a fair number of conferences, and I have to travel so far to get to them that I thought it was time we had one here in Chicago. I’ve been working with some other great developers and organizers, and we’re going to be hosting Chicago Roboto on April 20-21. It’s going to be the first Android developer conference in Chicago, so that should be a lot of fun. We’ve got great keynote speakers lined up, like Jake Wharton and Jesse Wilson. You can go to chicagoroboto.com to order your tickets, submit a talk, and get more information.

KG: Fantastic. Thank you so much again for coming on today’s show.

RH: Thank you for having me.

KG: Alright, that’s all for the show, folks. We’ll catch you in the next episode.