Professional Documents
Culture Documents
Preparing For A Software Engineering Interview at Jane Street
Preparing For A Software Engineering Interview at Jane Street
Preparing For A Software Engineering Interview at Jane Street
You can find more detailed information about the evolution of our SWE interview
process on our tech blog, but the most critical bits are here on this page.
If you’ve applied or interviewed before don’t let that stop you from trying again! We
reconsider people all the time—people add to their experiences and our needs often
change as Jane Street grows—so if it didn’t work out a couple of years ago you
might have a better chance this go-around.
The structure of SWE interviews at Jane
Street
There are a few paths you can take to becoming a software engineer at Jane Street,
but they all involve a technical interview that takes place over Zoom, and continue
with later-round interviews that are mostly, if not exclusively, focused on
collaborating on a series of coding problems.
We expect you to write code in a real programming language in these interviews, not
pseudocode. You can use any programming language you’d like, but we strongly
recommend you use the one you’re most familiar with and that best suits the
problem (it’s fine to change your mind as you’re exploring the problem). You should
be comfortable with basic data structures and APIs in your language of choice.
While interviewing, we’re really interested in learning how you work. This means the
journey through the interview is a lot more important than the snapshot of the
solution at the end of it.
To that end, we try to avoid algorithm bingo and puzzles with clever “aha” solutions.
We prefer more open-ended problems that have several plausible angles of attack
and maybe even no single best answer. These problems give us more freedom to
work together and to see how the candidates’ thinking plays out. We are looking for
candidates who engage in clear and productive discussions about the problem at
hand.
That sounds nice enough, but it’s a bit high-level and hand-wavy. So here’s a more
concrete list of suggestions that follow from our overall approach:
• Be nice
• Be clear
• Know your language
• Know what you don’t know
We don’t ask software engineers to do mental math, or math olympiad questions, or
to contemplate logic puzzles. SWE interviews are about programming, plain and
simple. There are other jobs at Jane Street that do care about mental math and logic
puzzles, for good reason. Just not this one. We also don’t award bonus points for
using a functional language like OCaml. Please don’t use OCaml just because you
think it will make us happy. We want to see you at your best, so you should use the
language you’re most comfortable with. If OCaml isn’t your strongest language, then
don’t use it. We don’t go out of our way to hire people who are already familiar with
functional programming. In practice, it’s just not that hard for strong programmers to
pick it up after they start.
We have two resources in particular that boil down both sides of a SWE interview,
ours and yours: a written walkthrough of a question we used to ask candidates, as
well as a mock interview video.
If you haven’t applied for a SWE role at Jane Street yet but feel you’re ready let
us make that easy on you. Fill out a few quick fields, upload your resume, and we’ll
be in touch soon!
o Share on Facebook
o Share on Twitter
o Share on LinkedIn
By: Sebastian Funk
Are you thinking about applying to Jane Street for a software engineering role? Or
already have a phone interview scheduled but unsure what to expect? Read on as we
walk through an example phone interview with you.
We want to give you some insight into what a typical Jane Street phone interview looks
like and give you a chance to prepare. We’re going to take a look at a question we call
“Memo” which we used to ask regularly (but of course don’t ask anymore so no need to
memorize anything on this page!). As such this post is meant to be a specific case
analysis. If you haven’t yet seen it, we recommend reading this blog post for a general
overview what we are looking for in candidates.
Getting started
To allow us to work on the question together, we’ll use a shared online editor. We’ll
provide you with the link to use (either before hand or during the interview).
We expect you to write code in a real programming language in the interview, not
pseudo-code. You can use any programming language you’d like, but we strongly
recommend you use the one you’re most familiar with and will let you solve the
problem in the best way (it’s fine to change your mind as you’re exploring the
problem!). You should be comfortable with basic data structures and APIs in the
language of your choice.
Note, there are no bonus points for using a functional language like OCaml. Please don’t
use OCaml just because you think it will make us happy. We want to see you at your
best, so you should use the language you’re most comfortable with. If OCaml isn’t your
strongest language, then don’t use it.
If during the interview you realize you have seen a question before, then please let us
know and we can do a different question. As you’ll see in this post, knowing a question
in advance greatly reduces what we can learn about you!
Have you heard about memoization? Can you carefully describe what it is? If you
haven’t heard about it, don’t worry. We’ll bring you up to speed. (A good introduction is
on Wikipedia.)
Now let’s say there is a function f of type int -> int whose output only depends on
the input. f is very expensive to compute. We’d like you to write a memoized version of
this function, i.e. another function g of the same type, that returns the same values –
g(x) = f(x) for all x – but only does the expensive computation once for each input
value.
A typical first solution we’re looking for at this stage uses a hash-table to store
calculated results. A possible solution in OCaml might be:
let memo f =
let results = Hashtbl.create 256 in
(fun input ->
match Hashtbl.find results input with
| None ->
let result = f input in
Hashtbl.add results ~key:input ~data:result;
result
| Some result -> result)
(As I said above, you’re not required or expected to write in OCaml but in this blog post I’m
going to follow my own advice and use the language I’m most familiar with, which is
OCaml. You might also object that this does a test-and-set without a lock, so can’t possibly
be thread-safe. Nice spot! For the purpose of this question let’s ignore re-entry to focus on
the core ideas.)
Whichever APIs or data structures you end up using for your solution: you should be
prepared to talk about how they work and what the complexity of various operations is.
Can you think of any issues we could run into when using the function from part 1? For
example, let’s say we run your function in production and notice our application
performs significantly worse than before. Quite the opposite from what we hoped
memoization would do! Can you see what the problem might be?
The big problem is memory usage. Our application might call f with lots of different
inputs and each result will be stored in the hashtable forever – a memory leak! Can you
come up with some ideas to improve upon this?
A reasonable approach to control the memory usage is to bound the size of the hash-
table and to evict things from it in a FIFO fashion. What trade-offs does FIFO have
versus other eviction schemes? How could you modify your memo function to
implement FIFO? Let’s aim for O(1) complexity when evicting from the cache.
There are a few different ways to do this. A good solution keeps a separate queue: when
adding a new result to your hashtable, if the size grows beyond the bound, then
dequeue from the queue and remove that element from the hashtable.
Besides being able to write code to do this, we look for how you communicate your
thoughts on the problem and ideas to improve it. We don’t necessarily expect every
candidate to immediately jump to the O(1) solution, but we’re interested in the process
of talking through this problem and what you can come up with.
As you probably realize, FIFO can be very inefficient in some use-cases. Let’s say we
want to do LRU (least recently used) instead. We still want the implementation to be as
efficient as possible. How can you implement this?
Once more, there are multiple ways to do this. The easiest solution stores timestamps
with each value in the hashtable and linearly scans through the table when evicting.
This is O(n). It’s possible to improve to O(log n) using a min-heap or even to O(1) using
a doubly-linked list.
Side-note: implementing the most efficient solution One way to get to O(1) is to
maintain a doubly linked list and make the values in the hash-table point to
elements in that list. Then when looking up a cached value in the hash-table, you
can slice it out of its current position in the list and put it at the top in O(1). You
maintain a separate pointer to the bottom of the doubly linked list to evict in O(1).
Few candidates come up with the doubly-linked list immediately, so don’t worry if this
is not something you thought of straight away. While we might ask you to implement
parts of your solution, this part is intended as a discussion and test your ideas for
improving complexity. We’ll guide you to the right level of abstraction, so you don’t have
to worry too much about which details to include.
We also have various other extensions for this question that make it possible to keep
going further as far as time allows.
As a concrete example, we might prefer a candidate that wrote careful and clear code,
communicated well and had good insights and ideas along the way, but didn’t get as far
through the problem compared to another candidate that immediately solved every
part but was sloppy and hard to follow.
Every successful candidate should achieve a bug-free solution for part 1 relatively
quickly. If some of part 1 sounds unfamiliar to you, it might be better to hold off
applying to give yourself more time to prepare.
Most candidates that we pass also complete part 2 fully in the time of the interview.
Strong candidates finish part 3 with a complete solution, but not finishing this part
doesn’t mean that you will be rejected! As said above, it’s what happens during the
interview that really counts, not the result at the end.
We are interested in seeing you approach a difficult problem and walk through the
process of deriving a solution with you. If you already know the question in advance
(either by finding it online, or by talking to friends who have previously applied), it
reduces the efficacy of the interview: We now only get to test if you can write code for a
problem you’ve already understood and solved, which is a small subset of things we are
interested in learning about. For example, if you’ve read through this post, we wouldn’t
learn much from asking you Memo!
Thus we would like to ask you not to share the interview question with anybody else (in
person or online).
We usually try to get back to you about the outcome of the interview within one week.
During busy periods this might take a bit longer, but not hearing from us after 10 days is
unexpected and you should definitely poke us.
If the interview went well, we invite you to come to one of our offices (New York,
London or Hong Kong) for a day of onsite interviews. These proceed in much the same
way as the phone interview – all questions are technical.
Ready to apply?
If you read this post and feel ready to apply, then simply go here. We have a very
straightforward application process – all we need is your resume or CV. If you already
have an offer from another firm and are worried about timing please let us know early
in your process! You can also read our thoughts and experiences with exploding offers,
something we don’t do but know many other companies use as a recruitment tool. We
look forward to speaking with you!
Sebastian Funk joined Jane Street in 2014 after graduating in Computer Science from the University of
Cambridge and has been primarily working in the Trading Systems group. He is a proud former member of a
Funk band incidentally named after him.
#INTERVIEWING
Interviewing At Jane Street
OCT 24, 2014 | 9 MIN READ
o Share on Facebook
o Share on Twitter
o Share on LinkedIn
By: David Powers
Even so, sometimes all that hard work doesn’t work out - even with a great candidate -
just due to the the awkwardness of the interview process itself: time is short, the
questions are weirdly artificial, and of course people get nervous. Programming for an
audience on a whiteboard, a web browser, or even just on a computer that isn’t yours is
a bit like playing the guitar with mittens on. It can put even an accomplished person off
their game.
That’s what this post is for. By talking a bit about what we’re looking for, the ways
people do poorly, and how we think you might be able to prepare we hope we’ll reduce
the mitten handicap - at least a bit.
From our perspective, the main thing we want to figure out when we interview
someone is: are they someone we want to work with?
That probably seems obvious and maybe even trite, but it’s a point that can easily get
lost once an interview is underway. We think of our interviews as little simulations of
what it’s like to work with the candidate; and while it may seem like the interview is all
about solving the problem, it’s really not. We’re much more interested in learning
about how you work.
We are looking for candidates who engage in clear and productive discussions about the
problem at hand. Ideally they quickly find the right technical level for the discussion -
not too abstract and not too detailed. They cleanly describe the most important
considerations, and lay out a good plan for dealing with them. Where there are tradeoffs
they note them and explain which side they took and why. They ask thoughtful
questions about parts of the problem that are unclear. Overall they show tenacity and
and curiosity; they want to engage with the problem and with the people they are
working with.
We model our interviews in a way that allows us to simulate, as best we can in an hour,
what it’s like to work with someone. That means we don’t particularly value seeing
someone write union-find in 15 lines, or care if a candidate knows exactly how an AVL
tree is written (though we do care about understanding tree balance at a higher level).
Those kinds of things can be found on the internet.
To that end, we try to avoid algorithm bingo and puzzles with clever “aha” solutions. We
prefer more open-ended problems that have several plausible angles of attack and
maybe even no single best answer. They give us more freedom to work together and to
see how the candidates’ thinking plays out.
That sounds nice enough, but it’s a bit high-level and hand-wavy. So here’s a more
concrete list of suggestions that follow from our overall approach.
Be nice
The smartest, most technically clever person in the world won’t get hired at Jane Street
if they aren’t courteous and pleasant to talk to. Most problems at Jane Street are solved
with a lot of collaboration and discussion, and the solutions often take days or weeks to
work out, incorporating ideas from many many people. The tenor and quality of those
discussions is an essential part of getting to the right answer.
Be clear
And by clear, we mean simple and to the point. Use words and examples that get the
core idea across to the widest technical audience possible.
Avoid showy, highly technical or deeply obscure terms of art, especially if you don’t fully
understand them. In the best case we’ll likely just ask exactly what you meant by
“hylomorphism”, which wastes precious time. In the worst case it will become clear that
you should have said “metamorphism” instead, which is just embarrassing for everyone
involved.
In other words, we really like people who can admit when they’re unsure and speak
confidently when they have the basis to do so. Be willing to say, “I don’t know” rather
than guessing. Tell us when you are fairly confident but still a little bit uncertain. Get
used to talking about not just the problem but also your own confidence in individual
assumptions and statements.
Now, comfortable doesn’t mean that you need to have memorized the spec for a
language (assuming it even has one beyond the reference implementation). It means
that you should be able to read and write code in your language of choice without
constant access to reference materials for common things, such as:
We’d much prefer you use a language that you know well, and can prove your skills
with. Similarly, when picking which features of the language to use pick the ones you
understand best. We’re not going to be impressed with your elegant use of Python
decorators if you don’t really understand what they do.
If you do get partway through and start to lose faith step back and talk about it. Explain
exactly why you are concerned. If there really is a fatal flaw and you’ve seen it we’ll help
you get out of the jam, and we’ll appreciate that you articulated it. If it’s just not quite
perfect we’ll likely encourage you to continue.
Review CS 101
We’ve hired plenty of successful people who didn’t have a traditional college
background in CS and we certainly don’t require a masters or a PhD. That said, we need
you to have a solid working knowledge of core computer science concepts, including:
So if you can’t for the life of you recall what amortized analysis is and you can’t nimbly
bang out the code for a depth-first search it’s probably worth reviewing some of this
material.
This doesn’t mean that we quiz every candidate about deep kernel internals, or the
differences between SDRAM vs SGRAM. But for some jobs in systems development we
do expect a fair amount of detailed knowledge, and in general it’s a big plus if you can
take into account things like cache effects, IO patterns, memory representations, and the
capabilities of real CPUs.
Lot’s of things. But there are a few things that pop up time and again that people worry
we are looking for that bear mentioning.
We aren’t looking for you to finish. Our questions are often designed to be open ended
enough that even the best people we’ve seen couldn’t answer them fully in the time
allotted. We want to keep the conversation going to learn everything we can, and we
don’t expect that you’ll answer everything 100% perfectly.
We also don’t expect you to give the perfect answer or to deliver bug free code. Coding
in front of people is hard. Coding with a time limit is hard. Coding, in general, is hard.
Build something from scratch and on your own in a language you like. Don’t stop short.
Build the whole thing. Make yourself do the parts that are hard for you and don’t accept
half-finished code just because you think you know how you would finish it. Dive deep
into the layers of the libraries and language that you built it upon, and understand how
they work too.
When you think you are done show it to the smartest people you know, get feedback,
tear it down and build it again with what you’ve learned.
We are looking for people to build real things with us, and practice really does make
perfect.
David Powers joined Jane Street in 2006 after spending time as a system administrator, directing IT at an
investment bank, and making swords to sell at renaissance faires. He graduated with a degree in mostly
Philosophy from Oberlin College in 1999 with just enough CS to land a job. At Jane Street he's had the chance
to write a lot of software, helped build out an office and data center or two, and has been invested in
recruiting for the past few years.