Building a Java HTTP Server
As an apprentice at 8th Light, the second last major challenge is to build an HTTP Server that passes the following Cob Spec integration tests.
I’ve spoken to many of the crafters, and nearly everyone I spoke to told me that they found the server incredibly difficult but also very fun and an amazing learning experience. This is consistent with my experience.
Here are some of my thoughts from this project.
Single Responsibility Principle
In the apprenticeship we do an unbeatable Tic Tac Toe in a number of different languages.[1][2][3][4]
This has been extremely valuable and I’ve learned a lot from doing it, but the one downside is that these Tic Tac Toe projects have been generally small, with not many classes.
A HTTP server, on the other hand, needs to do a lot of different things. Following the Single Responsibility Principle(SRP), a class should only have a single responsibility. Therefore, I ended up with a lot of small classes — 39 to be exact.
In smaller projects I’ve found it quite easy to get my head around the project, and know exactly where every bit of code I’ve written is. In the server, I found that I needed to look around a bit more to see where I had extracted functionality.
I think working on an even bigger codebase will make this even more difficult, but if classes are small, well named, and adhere to SRP, ideally it’ll be straightforward to find different component.
Test Driven Development
In Test Driven Development (TDD) we
- write a failing test
- write the simplest code that can pass the test
- refactor.
While writing my server, I fell into a bit of a trap since I had specifications that needed to pass, but less of an understanding of how a server actually works. At the start I was thinking that I was TDDing efficiently by writing the simplest code to pass the tests, but in fact just writing code to pass the tests, and not an actual server itself.
I got a bit of feedback that while my tests were passing, the code didn’t look like that of a server, and my mentors and I had an interesting discussion about TDD. I thought I was doing the right thing by writing the simplest code to pass the tests, but they clarified that ultimately, you still need to have an idea of what you are building and shape the code in that way.
In hindsight, I spent more time focusing on steps 1 and 2 of TDD, and not enough time on step 3 — refactoring to make it look more like a server.
Bytes
Humans tend to think in words and images, computers keep their data in bytes. Anything that we use on a computer is communicated in bytes (in byte arrays or by streaming the bytes).
I spent more time than I’m comfortable admitting fighting to get an image to display. This is because I insisted on working with strings, when the computer needed bytes.
When working with a computer, you may be able to use strings for some things, but life will be a lot easier if you work in bytes.
Concurrency
Up until this project, I have had no need to think about threading or concurrency. A server should support a significant number of requests, therefore must be able to handle multiple things at a time.
I found the Java tutorials to be very helpful, and was very happy that an Executor Service can take most of the pain of threading away.
Reading from a stream
Reading the messages from the client was a difficult beast to tame, but doing iterative approaches, I started by just getting the headers and ignoring the body of the request.
This was relatively straightforward, as I would stop reading from the stream when there was an empty line. When I could no longer ignore the body of a HTTP request, I needed to find a way to figure out when to stop reading.
Luckily, all HTTP requests that contain a body have a Content-Length
header, which includes the length in bytes. The request tells us how many bytes we need to read.
While I found this task extremely challenging, I found it very rewarding. I had some early mornings, late nights, and weekends in the office, but it was so nice to see the tests pass one by one.
I am currently on a pairing tour, where I’m spending 1–2 days with each person on my review board. It’s really fun to work on different projects, and see what other people are working on.
My next step will be the secret challenges, and if that goes well I will become a full fledged Software Crafter!