Friday, 3 June 2016

The Poetry of Code

Write a poem about a sunrise. Perhaps you'll leap straight in, and start writing freeform verse. Perhaps you'll choose a style; a haiku, or a limerick? Something using iambic pentameter or rhyming couplets? Your choice of approach places tangible constraints on how you express yourself.

What aspect of the sunrise will you write about? The sun itself, or the environment it rises over? Maybe there's a seascape to be evoked, or mountains. Maybe a city?

Now ask a friend to write a poem about a sunrise. I promise you, it won't be the same. To the outside observer watching you work, both of you will look alike --- scratching words on a page with a pen --- but the results are wildly different.

You both work alone. Your art is your own. It's wonderful.

Write a program to sort some numbers. Perhaps you'll leap straight in, and start writing freeform code. Perhaps you'll choose a style; Object Orientation perhaps, or a functional approach? Something using Java or Python? Your choice of approach places tangible constraints on how you express yourself.

What algorithm will you choose to write? A bubble sort, or a quick sort? Maybe a shell sort to be implemented, or a sleep sort? Maybe there's some other approach?

Now ask a friend to write a program to sort some numbers. I promise you, it won't be the same. To the outside observer watching you work, both you will look alike --- typing words on a keyboard --- but the results are wildly different.

You seldom work alone. Your art is a collaborative exercise. It's wonderful.

Friday, 4 December 2015

Sometimes I'm an Idiot

Recently, I've had a few too many things on my plate to deal with, and have been flirting with burn out, so it's time to take stock and stop being an idiot. In order to stop doing something, one must understand the things that are being done. In light of that, let me enumerate some of the ways in which I am an idiot:
  • Recently, for only the second time this year, I went to one of the many social events organised by work. They're a great chance to hang out with people I'd not normally see. I've been an idiot for prioritizing sitting at a keyboard over spending time getting to know other people and getting a better view of the company I work for. More broadly, I spend too much time at work, and it doesn't bring happiness. Don’t you be an idiot too. Go and talk to someone.
  • I've still got about half my annual leave to take even though it’s now December. I've been an idiot for not prioritizing resting and looking after myself. I'm in touching distance of finishing a big project, and once that's done I'll be taking all my remaining holiday.  You should also take your leave. No project has failed because someone went on holiday. 
  • For months, I was "too busy at work" to go to the doctor about a nagging pain in my foot. After it became so chronic walking to the office every morning was painful, I finally caved and went to seek help. It's going to take months to sort this shit out. If I'd taken the time to go to the doctor sooner I'd be better already, and things wouldn't be as painful or complicated as they are. I was an idiot for not prioritizing my own health. How can I work when I'm sick? If you're feeling rubbish, or you need treatment, go and get it. Then, once you’ve done that, come back and be busy.
  • Switching off from work is a must. Drawing a line between the office and home is vital. I've been an idiot for looking at work stuff after hours, when I can't really do anything about it, and never properly disconnecting. Facebook have an app called @Work and a recently-launched @Work Chat app, and I use these extensively. Your work may use a different email or calendar server you use for your personal life. When someone who's not an idiot leaves the offices, they mute work-related conversations, calendars and emails. Not doing that is a great way to burn out. Don't be an idiot.
  • At both Google and Facebook, I've had regular international travel in order to talk to people and collaborate with teams. This has meant I've not felt able to book myself into after-work courses even though I've wanted to. I am an idiot for letting work stop me from improving myself and my life. As a concrete example, my girlfriend was Turkish (she’s still Turkish. Figure the rest out for yourself). I thought it would be nice to learn the language so that we could go on holiday, visit her family, or just chat at home (and --- hey! --- learning a new language is always fun). I tried a combination of Rosetta Stone and text books, but I always let work get on top of me, so I never put in the work required. I knew I needed to take a structured class, and I knew that would need to be in the evening. I never signed up, because I was “too busy”. Now I deeply regret that, and kick myself routinely for being an idiot. Yesterday, I finally signed up for a Turkish class even though it’s a ten week course, and even though we’re no longer going out. At least I can still enjoy learning. I really am an idiot for not doing this already.
The main lesson I’m (finally!) learning is that I’ve been an idiot because I’ve let work dominate my life. Neither Facebook nor Google made me work these hours, or worry this much, or stress about all the things that I do and have done. I let work do that to me. I’ve had enough of being an idiot.

I have a horrible feeling that once I’m well rested, de-stressed, and feel like there’s more to life than a constant grind of work, I’ll be better at my job, and happier too. I'll have no way of dealing with not feeling like shit, but it'll be fun to find out. I don’t know whether this will be the case for sure, but doing the same-old, same-old isn’t working well.

I’ll keep you posted.

Tuesday, 21 April 2015

Monorepo --- One Source Code Repository to Rule Them All

What is a monorepo? It's a unified source code repository used by an organisation to host as much of its code as possible.

This is the pattern followed by companies such as Google, Facebook and the BBC, and is the way that I prefer to structure large scale code, as discussed in my post ruminating on codebases I have known.

I'm not entirely sure where I first heard the term but I like the way it demonstrates an intentional approach, rather than being the result of happenstance, so I use it when I can.

Of course, you need some tooling around a monorepo of any significant size. At some point, there should be more posts about that, but for now, take a look at the video of how Facebook handles this from F8 in 2015.

Thursday, 26 February 2015

Android: Forking Java by Mistake

Java has been forked, and Google is the reason. Allow me to explain.

Back in the days of Cupcake and Donut, when Android was new and shiny, one of the things that made it attractive to developers was that they could use a language they were familiar with on this new platform. That language was Java, and of course the version used was a modern one. The most recent version of Java at the time was version 6.

Of course, Java moved forward. 6 was end-of-lifed in February, 2013, and version 7 is now the oldest version supported by Oracle. Java 7's end of public updates is looming, coming as it does in April 2015. Java 7 introduced a bunch of new APIs and useful features. Some of these, such as better generics inference, are syntactic sugar and provided by the compiler, but some of these (notably "try-with-resources") need support from the runtime. That support only appeared in Android KitKat.

Versions of Android before KitKat still account for just under 60% of the market according to Google's own dashboards. That means that someone who wants to target as much of the Android market as possible has a choice to make: use Java 7's fancy new features, or stick with Java 6. Android's toolchain supports taking Java 7 bytecode, so all the syntactic sugar provided by the compiler is available, but you can't use the new features. Things are only going to get worse as Java 8 gets wider adoption --- features such as lambdas look like they're going to be widely used, especially as the functional paradigm becomes more widespread.

Java has a vast collection of OSS and commercial libraries out there for Doing Useful Things. If an app chooses to target Java 6, every library it depends on must also make that same choice.

This means that the Java market is now forking. Server-side Java is forging ahead, and the libraries that it uses are increasingly starting to use modern Java features, unless enough of their users ask for Android compatibility.

So, what can Google do to keep the world moving forward? How can developers use a more modern Java whilst still being usable by the largest part of the Android market.

The simplest thing would be to release a shim that developers can optionally load on pre-KitKat Android. Oracle's lawsuit about API infringement may make this a deeply undesirable route for them to follow.

Alternatively, individual developers can pack any required classes and APIs into their own apps. That seems like an error-prone way of doing things --- it's way too easy to accidentally use these new APIs by accident, and someone who only tests on a recent device will miss the versioning problem.

Finally, I guess some benevolent third party could create the required shim, but getting widespread usage may be difficult, and it's hardly ideal.

Once Java 8 features come into widespread use (or the use of invokedynamic gets more traction), the situation won't be so simple. I seriously hope the big brains running Android are getting ahead of this problem --- we'll need platform support to solve this problem properly, and we'll need it soon.

Until that support arrives, Java has been forked, with two family trees each with Java 6 as their common ancestor.

Wednesday, 1 October 2014

Pioneers and Settlers

I enjoyed breaking the world up into two kinds of developers so much, I thought I'd do it again.

The problems that we ask developers to solve are many and varied, but they all contain some mixture of the known and the unknown (sorry to come over all Rumsfeld this early in the post). A new project, the kind of which the company has never undertaken before, is riddled with the unknown to start with, whereas rewriting the legacy system in another language with a team who know the system and both the old and new languages is a pretty solid slab of known nastiness.

The kind of person you need for each type of problem differs. I used to think of them as "Starters" and "Finishers", but those terms are anodyne and lack the opportunity to be grossly misinterpreted. I call them "Pioneers" and "Settlers" now.

A pioneer is the kind of person you want to tackle a problem rife with the unknown. They're undaunted by the lack of a map, and positively enjoy the uncertainty. They tend to operate on their own, or in very small groups, and explore a problem with gusto. There's a strong chance code will be written, discarded, and written again, many times over. They might stand at a whiteboard and argue about design, covering it with boxes, arrows and misleading labels, before deciding the best thing to do is to build both approaches and see which one works.

But they get the job done. And once they know that the unknowns have been worked on, reduced to a manageable level and understood, they lose interest. The thing that drives them is taking a challenge that no-one else has overcome and showing that it's not really _that_ hard.

A pioneer is just the kind of person you want to get a project off the ground. And then you probably want them off the team. They've served their purpose, and now they're going to look for trouble.

What you want after the original skeleton is in place are Settlers. They take the rough trial laid out, and they make it habitable, maintainable and a Nice Place To Be. The problems that they solve tend not to be the "what the heck are we trying to do?" ones, but the "how the heck are we going to make this work?" ones. They're qualitatively different types of question, with very different challenges.

It's entirely possible that the pioneer, hotshot iconoclast that they were, has blazed a trial through the least pleasant route. They were only interested in getting things working, not doing it the best way possible. The settlers may be forced to throw out everything that the pioneer has done, leaving just the faint whiff of the original scheme in the air. I suspect that they do this more than most teams would like to admit.

It is vital to note that the challenges and design question a settler faces are no less taxing than those faced by pioneers, they're just different.

The pioneer finds "what" satisfying, and the process of solving "how" an anathema once there's working code. A settler finds iterating on the "how" a deeply rewarding experience, but the "what" may not hold much interest at all.

Of course, it depends on the project to determine what the correct mix of pioneers to settlers is. Sometimes, you just need a small team of pioneers. Sometimes you need a room full of settlers. Sometimes you need to start with pioneers, and then replace them with settlers. It's okay. The types of problems that need to be solved on a project vary over time. If they didn't, software development wouldn't be this much fun.

If you ever work with me, the chances are that you'll find I like the pioneer work an awful lot. I like to go shooting off into the darkness, meandering with glee into rough edges and emerging, triumphant and bleeding into the light having shown that, yes, yes it is possible to do something crazy. It takes a force of will for me to be a settler, and I rapidly get uneasy and unhappy when I try it.

Friday, 26 September 2014

Cavemen and Plainsmen

It is, of course, a gross overgeneralisation to say that there are two kinds of developers in the world. In this post I plan to grossly overgeneralise by discussing the two kinds of developers that are out there in the world.

Software developers like to write code, but the way that a developer likes to write code can vary wildly. Take, for example, the caveman. When given a problem, the caveman likes to retreat into his cave. There, in the dark, and away from the prying eyes of the people around him, they can take the rough stone of the basic problem and fashion it into a thing of beauty. The art of creation take a long time, so for those of us watching from the outside, it's as if the developer has ceased to exist.

Finally, the caveman emerges from the gloom, clutching the gorgeous artifact you've been waiting to see for so long. Or rather, they sometimes emerge from the gloom clutching a precious artifact. Sometimes, in the dark, they drop the rough stone they're working on and accidentally pick up a coprolite. This fossilised turd has now been thoroughly polished and shaped. It's perfect, but there's no mistaking that it's a turd.

Oh well. At least while it was happening the manager could relax and rest easy: although they had no idea what their caveman was working on, it was clear that they working on something because they were in the cave.

Contrast this with the plainsman.

Give a plainsman a problem, and they will gleefully leap about, showing it to everyone and anyone. It's amazing to watch one of these in action. Ideas fizz about them, and new approaches to tackle the problem are tried and discarded. You'll know that a plainsman is working on a problem because you'll see it. They might be vocal, they might be chatty on groups. Who knows? But you'll see and feel the heat of creation.

Eventually, the plainsman will come off the savannah and show you the end product. It may be the glorious artifact you hoped for, or, as with the caveman, they may have become distracted and hand over some sort of steampunk turd.

Of course, in the process of doing this, they may well have given their manager a few scares and worrisome moments --- progress may have appeared slow, or a deadend may have been investigated for too long. Their manager may well be ever-so-slightly balder than before. Stress does that.

Taking a step back, and only looking at the starting point and the end point, the two kinds of developer are identical. They're both given a problem, and they both sometimes solve it, and sometimes they royally screw it up. It turns out that they both probably follow the same techniques and processes to figure out how to build the software they're crafting. It's just that the caveman keeps this quiet, and doesn't like people to know how things are going until they're done, whereas a plainsman has never managed to figure out how to turn off the noise, or has consciously dialed up the volume.

Managers may actually prefer a caveman. If the end result is going to be the same anyway, it'd be nice to have a quiet life, free of stress, so that the manager can get on with the important work of whatever it is that managers do (Gantt Charts? Going to meetings? Browsing the web? Who knows --- they're a mystery to me, much like cats)

The manager is wrong, of course. It's infinitely preferable to work with a plainsman.

The reason is that it's a rare developer who has to work entirely alone and isolated. They tend to work in teams (as an aside, what is the collective noun for developers? A confusion? A multi-faceted-opinion?) Within that team, there's normally someone who needs the code that our hypothetical developer is working on. Being able to see progress allows others to prioritise their own work. And that moment, where the idea is dropped, and the turd picked up? That moment may not go unobserved in a group.

Managers know this too. I poke fun at them because I can. Not cats, though. Never poke fun at a cat.

Now, although I present this in black-and-white terms, it should go without saying (though I'll say it anyway) that it's a rare developer indeed who sits at one or other of these extremes. You can spot a caveman by the feedback from their peers. Things like "needs to work on communication", or "where the did this highly polished turd come from?" A plainsman might have feedback saying that they're noisy.

If you ever work with me, I'm a plainsman if you're within earshot. Ask anyone who's worked with me, that's quite a distance. However, if you're not on the IRC channel I'm on and out of earshot, I'm a pretty effective caveman. Which means that I should never be left on my own. Or fed after midnight. No. Hang on. That's Gremlins, right?

"I'm not trapped in here with them. They're trapped in here with me."

Update: I really like the terms "caveman" and "plainsman", mainly because I find that they're ones that people remember easily, and which fit the premise of the analogy well, but I'm aware that they're not gender-neutral. Suggestions for replacements have been "morlocks" and "eloi", or "troglodytes" and "herders", but both of those cast the caveman in a pretty negative light, which isn't really what I want to say. "Cavedweller" and "plains-dweller" are probably the best alternatives.

Friday, 24 January 2014

A Ranty and Dogmatic Troll Masquerading as Coding Guidelines

This document represents a series of guidelines for writing code that will swiftly pass code review with my team. It doesn't attempt to be fair. It doesn't attempt to listen to your opinion. It does present a series of guidelines. You may chose to ignore those guidelines (after all, if they had to be obeyed, we'd have called them "laws") We may choose to point back to these when reviewing your code. We'll attempt to avoid being (passive) aggressive when we do so.

Hugs and cuddles.

Test first
We're working on a framework for writing automated tests. It's probably a good idea for us to lead by example and write some tests. It hasn't been proven — but it's a scientific fact — that writing tests after the fact is as boring as boring can be. So we write the tests first. This has the added advantage that we can think about the kind of functionality we want independent of how it's implemented.

Or "Keep It Stupidly Simple, You Ain't Gonna Need It". When writing new code, just write the code you need. Don't attempt to write some ├╝ber-generic, ultra-lightweight, whizz-bang sub-framework for handling every conceivable edge case when you only need to do "this thing" once. It's another Scientific Fact that engineers are bloody awful at spotting patterns before the patterns emerge. Wait until the third or even fourth time you repeat something before attempting to extract a common API.

A good book for this? "Refactoring to Patterns".

Prefer composition over inheritance
Let's admit this up front: Java's a deeply flawed language. If I had to write this crap in vi or emacs, I'd be sitting in a corner, rocking backwards and forwards, weeping gently and pulling at my hair. Fortunately, we have IDEs, so It's All Okay. One area where Java is flawed is that it's really easy to inherit from a base class, and really clumsy to do proper composition. Nevertheless, as a rule of thumb: inheritance of interfaces is cool, subclassing a concrete base class is not.

Now, there will be times where it'd be Really Useful to be able to share some common functionality between things that appear to be related. For some reason, this always seems to happen with base test classes. It's a weird fetish, and it's one we should be disabused of. There are better ways to handle this, possibly through JUnit's Rules, or by extracting the common functionality into its own class and just newing it up on demand.

Point is: if you're using inheritance to share some common functionality between otherwise unrelated classes (and "it's a test" doesn't make them related) you're not doing inheritance right. You are, in fact, Doing It Wrong.

Role-based interfaces #ftw
Role-based interfaces: we like them, we use them, and we encourage other people to use them. Yes, this will mean that your classes might implement a lot of interfaces. That means that they collaborate with a lot of other classes. That tells you something. It probably tells you your class has too many roles or responsibilities.

Remember, kids, inside every fat class are at least two classes waiting to climb out.

Expose Collaborators
We take the use of Dependency Injection as an article of faith. This does not mean that we whole-heartedly embrace the need for a "DI Container", but it does mean that we're huge fans of exposing the collaborators of a class via its constructor (because "constructor-based DI")

Having said that, "new" is not a dirty word. It's totally pukka to use it, particularly for those handy utility classes we mentioned above. Having said that….

Utility Classes: Just Say No
A utility class represents a severe failure of imagination. They tend to become dumping grounds for only loosely related methods, which are typically static. If you have one of these, a fun exercise is to decompose it into what I like to refer to as "Objects" and use those instead. If you're having trouble with the traditional "noun-based" approach to identifying classes, try a bit of London School TDD and see what shakes loose.

Singletons? Static Methods? Also No
Singletons (in the traditional "implemented as a static field in a class" sense, not in the "ideally we'd only have one of these" sense) destroy our ability to have fun and write tests that can run in parallel, slashing our potential productivity. Also, it leads people to start using the Service Locator pattern instead of Dependency Injection, and we take DI as an article of faith (see above), mainly because it facilitates TDD by making collaborators clear, like we (also) said above.

Use strong types where possible
We're using a high ceremony language. Might as well embrace that properly. We dislike Stringly-typed code, and we like Tiny Types. Why do we like them? Because they allow our code to express intent as clearly as possible, and we can do things like "hang behaviour" off them as the need arises.

BTW, this means that we really should never be returning "WebElement" from a Page Object. Return a class that models the thing the user would expect to be returned, even if that leads to a class with nothing but a constructor.

Use the most abstract type that conveys intent for variables and fields
The most abstract type explains to the reader what you do. The concrete type is how you're going to do it. You should be able to change your mind about "how" without needing to change the "what". The most abstract type that conveys intent for a variable ("Map" instead of "HashMap", "WebDriver" instead of "DroidDriver")

I've been asked whether a method should return an ImmutableSet or just a Set when it returns a set of things that both sorted and immutable. Redundant as this question may seem, I'll still have a bash at answering it. Return the ImmutableSet, as that conveys the intent of the return value. If the caller doesn't care about the mutability of the set, they can assign it to a Set. Everyone's happy.

Use the right naming convention
The naming convention in our codebase is a hangover from the Android coding style, which was created by people who wrote C++ for a living (which also explains why there are so many static methods in the framework too) We don't write C++ for a living, and using a foreign language's coding conventions in Java code makes you look like a clown and an arsehole.

However, it appears we're perfectly happy to present ourselves as people who find it hard to get dressed in the morning without hurting ourselves. Consequently, when writing code that's just for us, use the coding standard of the rest of the codebase and choke back the waves of nausea. If you're writing code that we'll put in front of a public who believe we're competent engineers (that is, OSS) use the Google coding standard (effectively Oracle's, but with a two space indent)

Use the Ubiquitous Language, Luke
If everyone calls it a "Self Aggrandizsing Wattle", don't name the class "AndroidPoweredMultiflexViewPort". We want people to find the classes we write, and we want them to understand how they relate to other classes in the system. Using the names that people call things as class names is Totally Cool.

Also, if you've not done so, go and grab a copy of Domain Driven Design and attempt to wade through as much of it as you can bear. Then skip to the end and read the bit about Anti-Corruption Layers. That bit's good.

Naming Things
Design Patterns are a means of communication, not blueprints. Similarly, the thing that makes classes interesting isn't what pattern they happen to implement, it's the role that they play in our system. Leave the pattern name off the class name, ok? The exception to this is the "Builder" pattern. Everyone expects the "Builder of Thing" to be called "ThingBuilder". We might as well go with the flow on this one and buck our own contrarian ways.

Similarly, every concrete class is an implementation of something, so using the postfix "Impl" (presumably if you're too lazy to name something properly, you're too lazy to type "Implementation") as a class name is a Dumb Thing To Do. Name the class for the particular thing that makes it interesting within the system, or prefix the name with "Default" if there is genuinely nothing interesting about it. Try and avoid naming the class around some obscure implementation detail that no-one using the class cares about.

BTW, it's acceptable to append the name of the interface being implemented to the class name, but it's better to try and name the class for the role it plays in the system.

  • Single Responsibility Principle
  • Open/Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle
Presumably you're a Software Engineer. If any of those are hard to understand, then I'd suggest using your favourite search engine to read up on them.

Document in Proper English That Which Needs Documenting
It's a safe assumption that anyone actually reading your code is a professional software developer. Telling them stuff that they can see just by reading your code in javadocs and comments is Not Helping, so don't do it. Use comments to explain the reasoning behind particular design decisions, or to alert people to odd corner cases that might actually need explanation.

Consider replacing one line comments of a block of code with a sensibly named method containing that block of code. After all, when it comes to maintaining this shit, only the most dedicated of developers will actually update the code and the docs.

It's cool to use correct grammar and punctuation. Please do so, and try and end sentences with a period cretaceous

Monday, 4 November 2013

On the Naming of Tests

I'd thought that this was part of the automated testing canon already, but apparently not, so a quick note on the naming of tests appears to be in order. Well, how I think tests should be named. :)

When using an xUnit-style framework, the common pattern is to test class Foo in another class called FooTest. Within this test class, there are several methods. The principle I like to follow is that if you took the name of the test class, stripped off the "Test" postfix, and then listed the names of the tests as bullet points, you'd end up with a list of roles and responsibilities of the class under test. You'd end up with something like:

  * Should eat cheese
  * Should not consider cake as cheese
  * Should handle null cheese by throwing a SpecificException

And so on.

Put another way, if someone were to delete the class under test and the bodies of the tests, could they recreate something functionally identical to the class under test using just the test names? 

Monday, 9 September 2013

Time Keeps Ticking

A note so that I never forget again: the time used by a ZipEntry instance in Java appears to keep ticking.

ZipEntry entry = new ZipEntry("foo");
long expected = System.currentTimeMillis();
long seen = entry.getTime()

// This fails
assertEquals(expected, seen);

Update: it turns out that the problem turns out to be that DOS timestamps only store seconds with a precision of 2 seconds. The above could be reduced to:

ZipEntry entry = new ZipEntry("foo");

// Note: we set the seconds to an odd number
long expected = Calendar.getInstance()
    .set(2013, SEPTEMBER, 10, 12, 14, 1)
long seen = entry.getTime()

// This fails
assertEquals(expected, seen);

More on MSDN.

Monday, 22 July 2013

On Managing Time and Direct Emails About Selenium

I tend to get a few requests a day asking for help with a problem with Selenium. I almost never reply to these. It's not (just!) because I'm an evil minded, grumpy so-and-so, but because it's not a great use of anyone's time.

I am just one person. I have a full time job, and family and friends that I like to spend time with. I work on Selenium as a volunteer, and that means fitting it in where I can. Fortunately, work are understanding about this, and support my role in the project, which means I do far more than if I only had the occasional evening free. Still, it does mean that I prioritise my time spent on the project. This is how I do so:

  1. Writing code. That comes first.
  2. Spend time on the IRC channel. I often just lurk here, but it's a handy way to talk to the core development team and keep an eye on what's going on.
  3. Answer emails to the selenium-developers group. This is where we run the project and hold design discussions. It's not a good place to ask for help, unless that help is about implementing Selenium itself.
  4. I scan the webdriver and selenium-users lists, answering questions where I can and provided I have time.
Now, the nice thing with this ordering is that the further down the list you go, the more people there are who are able to help you with your issue. Put another way: asking for help in the user lists means that you're far more likely to get the help you want. It also means that if someone else runs into the same problem, Google can come to their rescue. A private email doesn't have that benefit.

I know that may be frustrating for you. I know that it seems to make sense to contact prominent people on the project directly. I understand your particular issue is urgent and important to you. I really do, and that's why I don't answer your emails.