Java 7’s Final Rethrow Capability: It’s Effect on Method Signatures

So I’ve recently started re-reading a book called “The Well Grounded Java Developer”, that I started reading a couple of years ago. Granted, Java 7 isn’t the latest and greatest Java version, but IMO, I would do well to learn Java 7 in detail, as well as complementary JVM languages like Groovy, Clojure, and Scala. Of course, I would also do well to learn Java 8 and 9 in depth as well. One the early sections in the Well Grounded Java Developer – Sec. 1.3, The Changes in Project Coin, describes the new Final Rethrow capability of the Java compiler. When I first read about this functionality, I was confused about it, so I’m writing a brief post to succinctly explain what it is and its effect on method signatures in Java 7.

In Java 6, methods signatures were required to throw the types of all caught exceptions (that aren’t runtime exceptions) as defined by the catch blocks. For example, consider the following code:

public void testTypicalRethrow() throws Exception {
  try {
    throwSqlException();
    throwIoException();
  } catch (Exception e) {
    throw e;
  }
}

private void throwSqlException() throws SQLException {
 throw new SQLException();
}

private void throwIoException() throws IOException {
 throw new IOException();
}

In the above code, we want a generic catch block (because we want to just rethrow the SQLException and the IOException). We also want a precise method signature (i.e. testTypicalRethrow() throws IOException, SQLException), but Java 6 forces us to throw an Exception, not either an IOException or a SQLException. So, in Java 6, the following line (in the context of the above code) would result in a compiler error.

public void testTypicalRethrow() throws IOException, SQLException {

However, the Java 7 compiler is smarter. The above line is now legal. Now, the following code is legal:

public void testTypicalRethrow() throws IOException, SQLException {
  try {
    throwSqlException();
    throwIoException();
  } catch (Exception e) {
    throw e;
  }
}

Previously, this signature of testTypicalRethrow would be illegal, but because the increased compiler intelligence brought on by the Final Rethrow feature allows this code to now be compiled, our method signatures can be more precise, while also having generic catch blocks.

The Final Rethrow capability allows the method signature to throw all possible types of exceptions that are actually caught, without relying of the catch blocks, themselves.

One last point… Ironically, the final keyword isn’t actually required, as you can see from the code above. So long as the original caught exception is rethrown, the compiler is intelligent enough to allow for the more restrictive method signature.

Happy coding.

Reasons for Horizontal Scaling vs. Vertical Scaling

TL;DR

Use horizontal scaling if you can, it’s usually preferable to vertical scaling. However, if you need run large monolithic apps, then vertical scaling is probably your best bet, although you should try to cut back on app size and resource utilization ASAP.

In slightly more detail, I would propose the following pros-and-cons list of horizontal vs. vertical scaling:

Dimension of Comparison Horizontal Scaling Vertical Scaling
Cost less expensive (through commodity hardware components) more expensive (specialized servers)
Availability of IT Resources IT resources instantly available IT resources normally instantly available
Replication and Backup nodes that can often serve as backup for one another other means will need to be found to replicate and backup data
Scaling Limitations often automated and not limited by hardware capacity often manual and limited by maximum hardware capacity
Failover usually builtin with nodes that can easily substitute for other nodes often a single point of failure
Ability to Run Large Applications App size and utilization is usually limited by smaller size hosts can often run large monolithic applications

My justification for the proposal of the above pros-and-cons list is the long explanation below, not the short abstract above.

Cloud Computing: Concepts, Technology & Architecture
So I’ve just started reading a book called “Cloud Computing: Concepts, Technology & Architecture” (CCCTA). So far the book is quite good. It got mixed reviews on Amazon, but from what I’m reading so far, it contains useful basic info on cloud theory. One of CCCTA’s sections describes pros and cons for horizontal scaling vs. vertical scaling. Frankly, I largely disagree with the author’s pros-and-cons list. The pros and cons of horizontal and vertical scaling can be found on page 38, in a table (Table 3.1). The table contains the following data:

Horizontal Scaling Vertical Scaling
less expensive (through commodity hardware components) more expensive (specialized servers)
IT resources instantly available IT resources normally instantly available
resource replication and automated scaling additional setup is normally needed
additional IT resources needed no additional IT resources needed
not limited by hardware capacity limited by maximum hardware capacity

 

Some points about this table:

  1. I agree with the first row. Horizontal scaling scaling is generally cheaper than vertical scaling.
  2. I also agree with the second row. Vertical scaling can sometimes require more specialized hosts and consequently more specialized IT resources that may not be immediately available.
  3. Row three is where I start to disagree with the author. True, horizontal scaling does often come with resource replication and automated scaling. But the statement “additional setup is normally needed” for vertical scaling (while probably true) is largely moot. What really matters are the IT resources which may not be immediately available (see row 2). Furthermore, this row misses the point that while resource replication and automated scaling are often benefits of horizontal scaling, they aren’t benefits of vertical scaling. Replication and backups still need to be thought of separately, because you don’t have inbuilt backups in your cluster/group of nodes. Furthermore, scaling is manual, not automatic, since you always need to provision larger hosts.
  4. The fourth row, is IMO, incorrect. We need additional IT resources for horizontal scaling but not for vertical scaling… Huh? Don’t we need additional IT resources to setup and provision and switchover to the new larger host? Seems like the amount of labor involved for vertical scaling is at least as much as horizontal scaling.
  5. As for the fifth row of the table, I agree with it. The limits of scale for horizontal scaling is, in my experience, much larger than the scaling limits of vertical scaling.

If this table was correct and complete, I don’t think that anybody would ever choose vertical scaling, because based solely on the above table, vertical scaling has no advantages over horizontal scaling. But, people do choose vertical scaling, and for good reason. The reason vertical scaling is sometimes chosen is because for all the benefits that horizontal scaling offers (and IMO Table 3.1 of CCCTA is largely correct about those benefits), not all the apps we have to deal with scale out horizontally. For big, monolithic, resource hogging apps, sometimes vertical scaling is the best choice. The high business value of some of these applications can dramatically outweigh the cost of the specialized hardware. Sure, ideally, we wouldn’t want behemoth apps that are a pain to maintain, but sometimes it’s just the best course of action. For example, mission critical databases are often such apps that demand vertical scaling. Sure, you could switch those DBs over to a horizontally scalable NoSQL solution, but oftentimes you can’t. When your Oracle DB contains real-time critical data related to bookings, and a plethora of apps access that DB directly, and you need to scale up, vertically scaling that DB might just be the fastest and cheapest thing to do (when you factor in the cost of changing all applications that connect to that DB). That being said, IMO horizontal scaling is the best longterm strategy, whereas vertical scaling might be what you need in the short-term.

Outside of table, this section of CCCTA also contains another “con” of vertical scaling that I really disagree with. On page 37, it reads:

Vertical scaling is less common in cloud environments due to the downtime required while the replacement is taking place.

IMO, this statement is wrong for two reasons:

  1. Vertical scaling doesn’t necessarily need to require any downtime. You put your old smaller host behind an LB, then setup the new larger host, then switch traffic over to the new host at the LB level. Poof… near-zero downtime. Of course, there are exceptions to this rule, but in my experience, they are few and far between.
  2. Vertical scaling is less common in cloud environments not because of downtime, but because of cost and resiliency. Bigger hosts cost more money. Like, a lot more money. And, with vertical scaling, you still have a single point of failure. Moreover, you can only scale up vertically so far, before host costs become either prohibitive, or simply unavailable.

With all that said, CCCTA is still IMO a decent book so far. I just take issue with this individual section. For the reasons described above in my “long explanation”, I would revise Table 3.1 in CCCTA to be my own table of reasons given at the start of this post.

How to Work Smart When Your Brain is Stupid

The past year has been a difficult time for me, personally. In fact, it’s been so difficult that I feel like I’ve got a case of good ole fashioned Mom Brain that just won’t go away. I won’t go into too many details, but grief is something that I haven’t yet been able to control. It manifests itself in one form or another from time to time. Predictably, my performance at work has taken a beating. However, as a result of some tactical fixes, I’ve been able to reduce the negative effects these issues that arise when I get distracted.

If you feel like your brain is betraying your desire to succeed, here are some tools have helped (and continue to help) me remedy my focus:

Volt Planner
Volt Planner

Tool #1 – A good paper planner: A good paper planner helps me set weekly and monthly objectives. It doesn’t have to be much, but it helps keep you on track to achieving your objectives and making things you are doing what you need to do. Btw, if you’re having a really tough time personally like me, your objectives and goals don’t have to be career aspirations and other ways to grow. My goals were merely there to help me try to maintain the status quo of my life. Examples of things I have put on there including various daily milestones for projects I am working on, doing one Pomodoro of house work, some administrative task or two that I hate doing, etc. Note that the planner isn’t very useful for calendar items – that’s what your calendar app on your phone is for. The planner also not for micro-level todo lists; that’s one of the uses of the log (described below). The planner is also useful for going over just before your morning scrum to state what you completed yesterday and what you intend to complete today. The one that I use is the Volt Planner.

Leuchtterm1917 Master Slim Ruled
Leuchtterm1917 Master Slim Ruled

Tool #2 – A good paper logbook: A good logbook helps me serialize my thoughts enough to complete complex tasks and investigations on how to solve a problem. I can write down things I’m trying, things that worked, things that didn’t work. I can go back through my notes as I try to remember what some highly complicated piece of legacy code does. They are also useful for large and intricate todo lists that can involve several different tasks happening concurrently. Another useful aspect of logbooks is to act as a reference for things that you need to know but will forget unless you write it down. My logbook of preference is the Leuchtterm1917 Master Slim Ruled. It’s big enough to write and draw what I need, slim enough to be relatively light, and has a hard cover to write on it without support.

Ink and Volt Meeting Notes
Ink and Volt Meeting Notes

Tool #3 – A good notebook for meetings: If you’re like me, you dislike meetings. Sitting still for an extended period while listening to other people talk feels tedious. Boredom sets in and your attention wanes. Nonetheless, you need to pay attention. Important decisions have to be made and at the very least, you need to follow along. A relatively small book to take notes (and perhaps doodle a little) is useful to retain knowledge of important facts. It’s also useful to write down a question you want to ask (or make a general comment) when somebody else is talking and you don’t want to interrupt them. For me personally, I like the Ink and Volt Meeting Notes. It’s relatively small, certainly less obtrusive than a full sized logbook, and is well suited to bring to a meeting and write down what information you need to retain, and what action items you need to take later.

Of course, these low tech items beg the question: Why not use electronic means? You can search what you write, it can be backed up trivially. The question is valid, and there is merit to using OneNote or Evernote. But for me, personally, the act of writing on paper helps me retain the information better than typing. Moreover, information on paper can be recorded faster. Diagrams are faster to draw. Lines are easier to connect text. Some basically note taking organization can get you largely to a searchable logbook.

Anyways, for me these tools help to stay on track even when I don’t feel up to it. I hope they can help you as well.

How many words does Green Eggs and Ham have?

Green Eggs and Ham by Dr. Seuss

Dr. Seuss’ Green Eggs and Ham has exactly 50 unique words.

I became interested in this fact after reading an article stating Dr. Seuss took on a bet to write Green Eggs and Ham in 50 words or less. I wanted to confirm this for myself so I thought that I would write a quick Python script to do it.

So, I found a text file version of Green Eggs and Ham and downloaded it, then dumped it into a Python script that determines how many unique words there are. After correcting the script text file to match exactly what the book says (i.e. removing the word “spam” which doesn’t actually occur in the book) and removing hyphens, other punctuation, and ignoring case, I managed to confirm for myself that Green Eggs and Ham does in fact have exactly fifty words.

Mystery solved!

The script’s output is:

set(['and', 'sam', 'be', 'house', 'am', 'box', 'see', 'are', 'in', 'mouse', 'boat', 'if', 'try', 'ham', 'would', 'there', 'fox', 'so', 'you', 'goat', 'do', 'them', 'good', 'that', 'may', 'eggs', 'here', 'dark', 'me', 'train', 'let', 'rain', 'they', 'not', 'with', 'eat', 'thank', 'a', 'on', 'like', 'i', 'car', 'could', 'tree', 'say', 'will', 'anywhere', 'green', 'the', 'or'])
50

Unit Testing Java Concurrency Issues

Concurrency issues can be notoriously difficult to diagnose, often being the cause of classically difficult problems such as heisenbugs. Attributes of concurrency issues such as intermittency and the inability to reproduce all contribute to a difficulty in debugging. Furthermore, disparity between late stage environments such as production where you have large amounts of load competing for resources and early stage environments such as your development environment where you may only have one small virtual host’s worth of load leads to issues that only appear in production, making reproducibility a major problem when diagnosing your issue. Moreover, the lack of a stack trace when such issues occur (i.e. you probably just have a logical error in your code where the wrong value is returned) makes life even tougher. For example, a concurrency issue in code that queries a different DB depending on the geographic location of the customer might inadvertently end up querying the wrong DB resulting in incorrect results every once in a while. This happened to me, personally, while working on Expedia’s Payment Service team. As my old engineering professor, MPBL, said “Intermittency is the bane of [an engineer’s] existence.”

In addition to detection, testing the fix of a concurrency bug can be equally, if not more, challenging. The fact that the concurrency issue might only happen in prod or a post-development stage after the dev environment reduces the confidence in any potential fixes when pushing. Often, we don’t even test for them in earlier stage environments because we don’t just don’t have confidence they will occur in early stage environments. Instead, we rely exclusively on existing regression tests, and just verify that we didn’t break existing functionality. “Well, it’s only happening in prod and our fix hasn’t broken anything in QA so let’s just release it. I’m pretty sure it will fix it.” Such statements are too frequently said for such “fixes”. I know I’ve been guilty of saying things like this before. :-/ Of course, such statements are often said more than once, and the investigation involving the concurrency issue often devolves into a proverbial shit show.

To help limit the scope of this post, I want to state outright that I won’t go over steps to narrow down possible concurrency issues. There are solid sources of information out there already for that, and I want to be as brief as possible. Instead, I want to focus on template code that can allow you to use TDD for possible concurrency issues that you investigate as a hypothesis as you drill down on various classes in your investigation.

With all that being said, you may be surprised or skeptical to hear that, to a surprisingly significant extent, concurrency issues can be unit tested. Below is an example of a unit test template for Java that I have currently used to employ TDD for two concurrency issues.

public class ThreadSafetyTest {
  @Test
  public void isThreadSafe() throws InterruptedException {
    // Step 1: Determine the number of parallel child threads to spawn.
    int numProcs = Runtime.getRuntime().availableProcessors();
    int numThreads = numProcs * 10;

    // Step 2: Initialize the instance to be tested that will be shared amongst the spawned threads.
    // TODO: Insert code here.

    // Step 3: Create a list of tasks that will perform the unsafe operation and assert that it
    // performs as expected (i.e. deserialize() produces a JSON request with the correct date.
    // Note that each child thread should verify something unique, so each thread here verifies a
    // unique date, based on `threadOffset`.
    List<Runnable> tasks = new ArrayList<>(numThreads);
    for (int threadOffset = 0; threadOffset < numThreads; ++threadOffset) {
      // Step 3.1: Setup any expectations for the spawned test thread here. These expectations will
      // be used in Sec. 3.2.2 below.
      // TODO: Insert code here.

      // Step 3.2: Setup the spawned test thread
      Runnable task = new Runnable() {
        @Override
        public void run() {
          // Step 3.2.1: Do the actual work that produces incorrect result.
          // TODO: Insert code here.
          // Step 3.2.2: Compare correct expectation vs. actual result.
          // TODO: Insert code here.
        }
      };

      tasks.add(task);
    }

    // Step 4: Use an AtomicReference to capture the first exception thrown by a child thread.
    Optional<Throwable> opEmpty = Optional.empty();
    /*
     * Use AtomicReference as a means of capturing the first thrown exception, since a spawned
     * thread can't "throw" an exception to the parent thread.
     */
    final AtomicReference<Optional<Throwable>> firstThrownException =
        new AtomicReference<>(opEmpty);

    // Step 5: Construct a new ThreadPoolExecutor that will execute all tasks in parallel on different threads.
    // The new ThreadPoolExecutor will exploit the `afterExecute()` method that gets called with the thread's
    // thrown exception.
    /*
     * Use new ThreadPoolExecutor instead of Executors.newFixedThreadPool() so that I can override
     * afterExecute() for the purposes of throwing an exception from the test thread if a child thread
     * fails. Thus, a failed thread will cause the test, itself, to fail. Trick from StackOverflow
     * at:
     * http://tinyurl.com/gluof74
     */
    ExecutorService execSvc = new ThreadPoolExecutor(numThreads, numThreads,
        0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) {
      @Override
      public void afterExecute(Runnable task, Throwable failureCause) {
        if (failureCause == null) {
          // The Runnable completed successfully.
          return;
        }
        // only sets the first exception because it will only be empty on the first call.
        firstThrownException.compareAndSet(Optional.<Throwable> empty(),
        Optional.of(failureCause));
      }
    };

    // Step 6: Execute all the tasks in parallel, verifying that no exception was thrown from any child test
    // threads, which will occur when a date assertion fails.
    for (Runnable task : tasks) {
      execSvc.execute(task);
    }
    execSvc.shutdown();
    execSvc.awaitTermination(1, TimeUnit.HOURS);

    assertEquals(Optional.empty(), firstThrownException.get());
  }
}

Using this template, you can test drive suspect code that you don’t believe to be thread-safe. Of course, it’s not 100% safe. The test may still pass with concurrency issues. That being, said, assuming that your code is passes for single threaded test cases, and this test passes when you set numThreads to 1, or some low number, and then fails for larger values of numThreads, then you can have a high degree of confidence that you have a concurrency issue, which this test is exposing. Again I would like to reiterate that this template has worked for me two for two times in the past where I have employed it, and has greatly increased my efficiency while fixing concurrency issues.

Let’s use this template in a real example I recently had to deal with. The problem was that during some testing, when calling an in-development web service, a team member noticed that dates in our JSON requests to our new service were being set to null. The domain objects containing the dates were fine. So our hypothesis was that there was a concurrency issue in the code that serialized dates into JSON. Consider the following stripped down version of that class – a Spring bean singleton that wrapped a GSON instance to deserialize dates returned by our web service:

@Component
public class Foo {
  private static final String SHORT_FORMAT = "yyyy-MM-dd HH:mm:ss";

  private static final DateFormat DATE_FORMAT = new SimpleDateFormat(SHORT_FORMAT);

  private Gson gson;

  @PostConstruct
  public void init() {
    if (this.gson == null) {
      this.gson = new GsonBuilder()
          .registerTypeAdapter(Date.class, new DateDeserializer())
          .setDateFormat(SHORT_FORMAT).create();
    }
  }

  private static class DateDeserializer implements JsonDeserializer<Date> {
    @Override
    public Date deserialize(JsonElement jsonElement, Type typeOfT,
        JsonDeserializationContext context) throws JsonParseException {
        String dateAsString = jsonElement.getAsString();
      try {
        return DATE_FORMAT.parse(dateAsString);
      } catch (Exception e) {
        return null;
      }
    }
  }

  public FooRequest deserialize(String json) {
    FooRequest request = this.gson.fromJson(json, FooRequest.class);
    return request;
  }
}

Note that the corresponding code for FooRequest was:

public class FooRequest {

  @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  private Date searchDate;

  public Date getSearchDate() {
    return this.searchDate;
  }

  public void setSearchDate(Date searchDate) {
    this.searchDate = searchDate;
  }
}

The above is a simplified version of code I recently had to deal with, while not so simple that it eliminates all possible causes of the concurrency issue.What this code does is initialize a non-final GSON instance via the init() method. It also checks whether the gson field is null in a non-synchronized part of the code, and initializes it. After the initialization, clients may call the deserialize() method to change a JSON string into a FooRequest instance via the DATE_FORMAT static constant. A simplified version of the test class based off the above template is as follows:


public class FooThreadSafetyTest {
  private static final String BASE_REQUEST = "{" +
      "\"searchDate\":\"2015-11-23 12:34:56\"" +
      "}";

  private static final Pattern SEARCH_DATE_REGEX = Pattern.compile("\"searchDate\":\"([^\"]+)\"");

  private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

  @Test
  public void isThreadSafe() throws ParseException, InterruptedException {
    // Step 1: Determine the number of parallel child threads to spawn.
    int numProcs = Runtime.getRuntime().availableProcessors();
    int numThreads = numProcs * 10;

    // Step 2: Initialize the instance to be tested that will be shared amongst the spawned threads.
    final Foo foo = new Foo();
    foo.init(); 

    // Step 3: Create a list of tasks that will perform the unsafe operation and assert that it
    // performs as expected (i.e. deserialize() produces a JSON request with the correct date.
    // Note that each child thread should verify something unique, so each thread here verifies a
    // unique date, based on `threadOffset`.
    List<Runnable> tasks = new ArrayList<>(numThreads);
    for (int threadOffset = 0; threadOffset < numThreads; ++threadOffset) {
      StringBuilder rqBuilder = new StringBuilder(BASE_REQUEST);

      final Date expSearchDate = updateDate(rqBuilder, SEARCH_DATE_REGEX, threadOffset);

      final String rq = rqBuilder.toString();

      Runnable task = new Runnable() {
        @Override
        public void run() {
          FooRequest fooRq = foo.deserialize(rq);
          Date actSearchDate = fooRq.getSearchDate();
          assertEquals(expSearchDate, actSearchDate);
        }
      };

      tasks.add(task);
    }

    // Step 4: Use an AtomicReference to capture the first exception thrown by a child thread.
    Optional<Throwable> opEmpty = Optional.empty();
    /*
     * Use AtomicReference as a means of capturing the first thrown exception, since a spawned
     * thread can't "throw" an exception to the parent thread.
     */
    final AtomicReference<Optional<Throwable>> firstThrownException =
            new AtomicReference<>(opEmpty);

    // Step 5: Construct a new ThreadPoolExecutor that will execute all tasks in parallel on different threads.
    // The new ThreadPoolExecutor will exploit the `afterExecute()` method that gets called with the thread's
    // thrown exception.
    /*
     * Use new ThreadPoolExecutor instead of Executors.newFixedThreadPool() so that I can override
     * execute() for the purposes of throwing an exception from the test thread if a child thread
     * fails. Thus, a failed thread will cause the test, itself, to fail. Trick from StackOverflow
     * at:
     * http://tinyurl.com/gluof74
     */
    ExecutorService execSvc = new ThreadPoolExecutor(numThreads, numThreads,
        0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) {
      @Override
      public void afterExecute(Runnable task, Throwable failureCause) {
        if (failureCause == null) {
          // The Runnable completed successfully.
          return;
        }
        // only sets the first exception because it will only be empty on the first call.
        firstThrownException.compareAndSet(Optional.<Throwable> empty(),
            Optional.of(failureCause));
        }
      };

      // Step 6: Execute all the tasks in parallel, verifying that no exception was thrown from any child test
      // threads, which will occur when an date assertion fails.
      for (Runnable task : tasks) {
        execSvc.execute(task);
      }
      execSvc.shutdown();
      execSvc.awaitTermination(1, TimeUnit.HOURS);

      assertEquals(Optional.empty(), firstThrownException.get());
  }

   /**
    * Replaces the date matched in {@code rqBuilder} using {@code dateRegex} with a new date. The new date
    * is the matched date plus the {@code threadOffset}.
    */
  private Date updateDate(StringBuilder rqBuilder, Pattern dateRegex, int threadOffset)
        throws ParseException {
    Matcher searchDateMatcher = dateRegex.matcher(rqBuilder);
    boolean foundSearchDate = searchDateMatcher.find();
    assertTrue(foundSearchDate);
    int dateStartIndex = searchDateMatcher.start(1);
    int dateEndIndex = searchDateMatcher.end(1);

    String strDate = BASE_REQUEST.substring(dateStartIndex, dateEndIndex);
    Date date = DATE_FORMAT.parse(strDate);
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.add(Calendar.DATE, threadOffset);

    Date modifiedDate = calendar.getTime();
    String strModifiedDate = DATE_FORMAT.format(modifiedDate);
    rqBuilder.replace(dateStartIndex, dateEndIndex, strModifiedDate);

    return modifiedDate;
  }
}

Basically what this unit test is doing is kicking off a large number of test threads from the test (ten times the number of processors on the host). Each thread deserializes a unique JSON string request into a request object. Each request object’s actual date is compared against the expected date. The deserializations and comparisons happen in parallel – one deserialization and subsequent comparison per thread. If any one of the dates is not equal to its expected value, that thread will throw an exception, which will be picked up by execSvc‘s afterExecute() method. If present, the first exception picked up by the afterExecute() method then fails the overall test by setting the AtomicReference to firstThrownException.

On my machine, when I run this test against the previously defined classes Foo and FooRequest, I get an AssertionError from FooThreadSafetyTest. Basically, an Optional instance was expected but an actual Optional instance containing an AssertionError was found. This outer assertion error happened in the test code at:

assertEquals(Optional.empty(), firstThrownException.get());

The inner assertion error happens in the anonymous Runnable‘s run() method at:

assertEquals(expSearchDate, actSearchDate);

For this case, expSearchDate was Thu Feb 09 12:34:56 PST 2016 but actSearchDate was erroneously null, thus failing the test.

Based on your knowledge of the SimpleDateFormat class, you may arrive at the hypothesis that SimpleDateFormat is not as thread safe as you thought it was. As such, you may decide to wrap it in a ThreadLocal instance. Your new code may be as follows:

@Component
public class Foo {
  private static final String SHORT_FORMAT = "yyyy-MM-dd HH:mm:ss";

  private static final ThreadLocal<DateFormat> DATE_FORMATS = new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
      return new SimpleDateFormat(SHORT_FORMAT);
    }
  };

  private Gson gson;

  @PostConstruct
  public void init() {
    if (this.gson == null) {
      this.gson = new GsonBuilder()
        .registerTypeAdapter(Date.class, new DateDeserializer())
        .setDateFormat(SHORT_FORMAT).create();
    }
  }

  private static class DateDeserializer implements JsonDeserializer<Date> {
    @Override
    public Date deserialize(JsonElement jsonElement, Type typeOfT,
      JsonDeserializationContext context) throws JsonParseException {
      String dateAsString = jsonElement.getAsString();
      try {
        DateFormat dateFormat = DATE_FORMATS.get();
        return dateFormat.parse(dateAsString);
      } catch (Exception e) {
        return null;
      }
    }
  }

  public FooRequest deserialize(String json) {
    FooRequest request = this.gson.fromJson(json, FooRequest.class);
    return request;
  }
}

If you execute the above code, you’ll find that the hypothesis proves correct and we may now have confidence that this block of code did contain a race condition in the manner we predicted but no longer does. Thus, the concurrency issue was corrected.

For fellow fans of Michael Feather’s book, Working Effectively with Legacy Code, you can argue that this isn’t truly a unit test, because tests such as this one “don’t run fast”. Nonetheless, in my recent experience with this test, it executes slowly, but at an imperceptible level. On my machines, it took less than 1ms.

Note also the reliability of this test template. We may have false positives from the test passing despite a present race condition. That being said, I still haven’t seen false positives so far. Conversely, however, assuming the test template passes for the single thread version (i.e. where numThreads is 1), the test should never fail unless a concurrency issue is present (notwithstanding errors like OutOfMemoryError, StackOverflowError, etc.) Thus, false positives are rare and false negatives are even rarer.

If you have actually gotten this far in the post, thanks for reading. I hope this post and template code prove useful to you in the future.

The Software Engineering Phone Screen

I’ve been doing phone screens now for some time. At this point, the first phone screen I give a candidate is basically always the same and it’s based on Steve Yegge’s now famous blog post on the five essential areas of a phone screen. At first, I followed Steve’s areas as closely as possible. However,  as time went on, I deviated somewhat from it and thought that I would share my phone screen format that has evolved over time.

Instead of Steve’s five areas I just have my three. But, I tend to dive a little deeper in each of the areas because the software engineers whose work I respect the most tend to know certain things and the ones whose work I don’t respect as much tend not to know these things. These areas are:

  1. Basic coding
  2. Data Structures
  3. OO Design

Later in this post I will dive into each area with questions I ask along with candidate expectations. But the first part of the technical phone screen I do is actually a bit softer.


Warm Up

At first I introduce myself. I ask the candidate how they are doing and whether the current time is still convenient for them. After that I just ask them to briefly take me through their resume and tell me about what they have been doing for the past couple of years. I really don’t care much about any of these things.  It’s primarily intended to warm the candidate up and make them feel comfortable.  Interviews can be intimidating! As Joel Spolsky  said in his great book Smart and Gets Things Done:

I ask the candidate to describe their career history and basically tell me about themselves. This is mainly intended to get them loosened up and feeling comfortable, to eliminate any nervousness, and to let them sort of present themselves the way they want to be presented.

Building on that, there are a couple of things that this introduction can help you to quickly elucidate:

  1. A history of delivery: Drill down on what exactly the candidate did instead of what their team and company did. Bullshit, shadiness and lack of precision here are red flags.
  2. A valid reason for leaving the company: You want to hire somebody who wants something that your company has to offer, not just somebody who is seeking to flee their current role until something bigger and better comes along. Try to understand what exactly the candidate is looking for in their next role.

Once the soft pitches and preamble are done, it’s time for the meat of the phone screen – the technical questions.


 

Core Competency 1: Basic Coding – String Reversal

The first area I dive into is rudimentary coding skills. Specifically, the first question I ask is:

How would you write a public API method to reverse a string in your most comfortable programming language?

This is my most basic weeder question and the first one I ask because it allows me to weed candidates the fastest. If the candidate can’t correctly reverse a string in a language of their choice, I really don’t want to work with them. That might sound arrogant and harsh, but you have to establish a hiring bar from which to base the hire/no-hire decision. There is no non-boolean value for this question.

Also, note the public API component to the question. API design is a key skill for today’s software engineers. We are always interfacing with somebody else’s code. Poor candidates will design their API such that it requires extra input parameters such as start and/or end indices and/or maybe a length parameter. Crap like that is just unnecessary, and good candidates just won’t put in unnecessary information like that. That’s a red flag for me and it makes me think twice about signing off on the candidate for the next round.

As for the code itself, I try to use collabedit. However, given the simple nature of this coding problem, you can also do it just by having the candidate writing it down on a piece of paper and reading the code back out verbatim if a stable internet connection can’t be had. Note that the code needs to be compilable. If the candidate writes code that looks more like pseudocode, I explicitly ask them “Will this code compile?” At that point, they either correct their code or verify their own ignorance.

Lastly, for candidates who use the more standard languages that involve a call stack (which is the vast majority of candidates), I follow up the first question with a part B:

Suppose your colleague performs a code review and they state that you should use recursion to reverse a string. Would you agree with them? Why or why not?

I ask this follow up question because in the real world, recursion can go too deep and result in a stack overflow. Consequently, I think that anybody writing C++, C#, Java, etc. needs to understand these dangers. For something like the reversal of a string, where the reversed string might end up having thousands of extra calls on the call stack, this is a real concern. In my experience, great engineers all realize this fact, and not-so-great engineers tend to not realize it.

To cut the interview short or to not cut the interview short?

If a candidate cannot successfully negotiate a string reversal algorithm, do you really want to potentially hire them? Is anything, however brilliant they say after this point going to change your mind? For me personally, an inability to negotiate this problem is a showstopper. As such, if the candidate cannot reverse a string, and the phone screen is just painful for both involved, I usually cut the phone screen short at 20 or 30 minutes. The 20 minute minimum is based on a conversation with recruiting at a previous employer where recruiting felt that 20 minutes was the bare minimum time required for the candidate to feel like they had a chance to prove themselves. At the end of this question, I politely tell the candidate that that’s all the questions I have for them and ask them if they have any questions for me. I’m as polite as possible, but I also have demands on my time at work. So if I can get back some extra time by quickly filtering an unqualified candidate, then I’m OK with that. Others that I know prefer to go the full length of the phone screen, despite the fact that the candidate can’t recover from it, and that’s fine too.

I think that the choice to cut a phone screen short varies by interviewer. But if you’re going to do it, I think that it’s important to be respectful and polite and just inform the candidate that that’s all the questions you had and whether or not they had any questions for you. Once you are done answering their questions, if any, just part ways politely.


 

Core Competency 2: Data Structures – Choosing the right one

In my opinion, the ability to pick the right data structure is a key skill for any software engineer. We pick data structures most times we code, and it’s one that can be gauged well over a phone. To test this, I ask a lightning round style set of questions that also tests some secondary skills. The first data structures question I ask is:

Suppose you are writing some server side code that returns recommendations as part of a HTML page to the customer. To determine recommendations for the customer, you call a web service. Unfortunately, this web service is poorly implemented and you have to call it for each recommendation, until the web service returns a null recommendation. While you are calling the web service, what data structure would you store the recommendations in until you are ready to render the HTML page?

That question is a mouth full and is easily confusing on a first pass. As such, my first data structures question actually gauges a candidate’s ability to ask clarifying questions to deal with ambiguity – another key skill of any software engineer. Good candidates will tend to drill down ask a few probing questions such as “Do we know the exact number of recommendations to add beforehand?”, “Approximately how many will we get back?”, and/or “Do we need to access the middle elements?” Reasonable candidates will usually respond with a linked list or possibly an array. Personally, I think that linked lists are preferable here but I have had candidates that give reasonable answers for why an array is suitable as well and I get them to explain why.

Next I usually ask:

How would your answer change if we knew the exact number of recommendations to retrieve beforehand?

Good answers will list an array for this. But again, some candidates give reasonably sound reasons for a linked list and that’s OK too. A big part of this core competency is probing their reasoning. If they have good reasoning skills, then I’m OK with going with either.

My third data structures question is:

How would your answer change if the web service returns duplicates and we need to filter them out?

For this a set is the correct choice.

Next I deviate from choosing data structures and delve in a little to see if they understand how a set is actually implemented. We quickly get to the underlying hash table implementation. So I again delve and say:

Explain to me how a hash table works internally so that it can filter duplicates.

Hashing is meat and potatoes programming, it’s ubiquitous, and again, solid engineers really tend to understand how hashing works at a high level and in my experience shaky engineers tend not to know.

Next, I try to gauge whether or not they understand concurrency by asking:

How could you make a hash table concurrent?

This is not necessarily a no-go for an intermediate level engineer, but it is a definite red flag for somebody interviewing at the senior level. The candidate who truly understands concurrency will realize that you need to synchronize on individual elements (or stripes) of the internal array, and not lock the entire array.

Lastly on data structures, I ask:

Since customers will probably only look at the top ten recommendations, what data structure would you choose to only ever keep track of the top ten recommendations, discarding all others when attempting to add?

This is a classic use case of a heap (i.e. priority queue). Again, in my experience, super-par engineers tend to know this and sub-par engineers tend not to know.


Core Competency 3 – Object Oriented Design

The last part of the phone screen entails object oriented design. In addition to purely object oriented design, I look for the following skills:

  1. Ability to design a type hierarchy
  2. Ability to distinguish where composition should be used and where polymorphism should be used
  3. Ability to deal with ambiguity
  4. Communication

The question that I ask is:

How would you design an animal kingdom hierarchy for a virtual zoo program?

The question as it stands can’t really be answered correctly without further information. Competent candidates quickly get to asking for use cases where they then find out that intention is for a separate virtual zoo program that we don’t care about to use classes in the type hierarchy of animals to draw them. After a little while, we get to a basic hierarchy where there is a default interface specifying a draw method called Animal. Abstract subclasses include entities like mammals, birds, and fish. Finally concrete classes are for various species that will be drawn in the zoo.

Finally, I ask them how, after the initial release of the virtual zoo, they would insert a flying fish (i.e. a fish with bird wings) into the existing hierarchy. Many candidates just aren’t able to design a solution that doesn’t result in duplicate code for drawing the wings or without multiple implementation inheritance. I’ve lost count of how many times I have seen a crazy type hierarchy with methods and parts of methods jumping between classes and superclasses and child classes. I don’t want to work with such hierarchies, so I filter out candidates who are not likely to be able to design anything better than them. As the Gang of Four said:

… our experience is that designers overuse inheritance as a reuse technique and designs are often made more reusable (and simpler) by depending more on object composition.


Jon’s Final Thoughts

So this is what I ask in my first phone screen. While not strictly Yegge’s five essential areas, I do gauge three of his areas and check for a few more things that I really feel are required by every solid software engineer.

Also, note that interviewing isn’t a perfect science. Acceptable answers in some areas might be just fine for me and unacceptable for other engineers, and vice versa. As time goes on, you will start to be able to perceive how candidates perform relative to others you interview, and you will be able to gradually calibrate your technical bar as time goes on.

I hope that this post was useful and you are able to incorporate some of these ideas into your own phone screens. Feel extremely free to leave comments and/or questions, subscribe to this blog, and/or share this post. 🙂