Java HTTP Server: Thoughts & Takeaways

Malina Tran
Tech and the City
Published in
5 min readJan 6, 2017

When I first started 8th Light as an apprentice, I had thought building an HTTP server in Java was my capstone project. It would be the final, and therefore the most difficult, project I would be working on.

Oh, how I was mistaken.

First, it’s not any of those things. But rest assured, that’s not to say it was easy. In fact, it took me awhile to wrap my mind around what I was doing and needed to do. And it is one of the most complex projects that I’ve built from scratch. Architecture is critical. If you’ve never worked with Java or a statically-typed language, be prepared for verbosity. And you need context — in terms of how clients and servers communicate, what are sockets and streams, how multithreading works, etc. No, it’s not easy. (And did I mention that this project is reviewed and heavily reviewed by other Software Crafters?). And it was most certainly not the last project I would work on.

Beyond language-specific conventions (e.g. the “Java” way of doing things), here are my takeaways from working on this project:

Learning how the Internet works

I cannot stress enough how important this is, and perhaps a good introduction to networking, IT, or the operational side of software engineering. While I had a brief overview of requests and responses, this project helped me dive deeper into what to expect from headers (e.g. eTags), various status codes, and how image files are read and rendered. I feel a lot more comfortable poking around the network tab in Inspect Element.

Learning about concurrency, multithreading, and thread-safe data structures

From the onset, the Java server was required to be multithreaded and could handle many concurrent requests. I’ve documented the process and provided a code snippet in a previous post. And yet, as I was approaching my deadline, my Cob Spec test for multithreading continued to fail and I was continuously getting NullPointerExceptions. (This was a major learning opportunity in debugging throughout the codebase). I had to isolate major sections of my codebase to try to identify the source of the issue and in the process, learned that certain data structures supported concurrency, like using Hashtable over Hashmap, and using an ExecutorService rather than a Thread.

Learning how to hand-roll mock objects for testing

When I was told that mocking frameworks would be disallowed, I clenched my fist for a hot second.

I mean, not really and definitely not literally — but I moved on. Because this turned out to be a really useful lesson in implementing interfaces and extending abstract classes. It’s also extremely helpful to understand what happens under the hood when you’re mocking objects.

Learning how to write user stories and acceptance criteria

When I first started on this project, I was introduced to Artisan, as well as the following concepts: user stories (an Agile tool used to identify requirements framed by the end-user’s perspective), point system (optimistic, realistic, and pessimistic — in which two points equals one workday), and Gherkin-style acceptance criteria (which define the boundaries of a user story and help to determine when a story is complete). In some ways, I felt that it was redundant for me to translate the Cob Spec acceptance tests into user stories. Over time, I realized its usefulness in helping me break down the Java server requirements as well as improve writing user stories, which is, as it turns out, the 8th Light way.

Understanding programming conventions in praxis

When you build a game as “simple” as tic-tac-toe, I think you’re able to ensure that classes do not know more than they should. Although I’m not quite “in the wild,” writing code for a Java server was more complex because I also had to be mindful of techniques that I’ve learned along the way, such as Open-Closed Principle, Dependency Injection, and Single-Responsibility Principle. Also, the more I code, the more experience I have with names, roles of objects, when and what to abstract, etc.

Remember the bigger picture

When my mentors first asked me to explain how my code worked, I was a bit nervous. I was stuck in the weeds that it was difficult for me to articulate the role of router, for instance. (Plus, this is bird’s eye perspective is something I need to work on). Since diagramming is helpful for me, and I can best articulate myself through the written word, I wrote up a Gist about how my code works and provided an overview of the packages and their roles.

Weekly IPMs with my mentors also helped remind me what I actually need to be doing: build a web server, not just meet some acceptance tests. This meant that I had to go above and beyond, and just because they weren’t outlined in the acceptance tests, did not mean I have to be complacent and not incorporate an important component of server responsibilities. For instance, after receiving feedback, I realized that my server should be able to support specific file types with all sorts of edge cases, whether they existed in subdirectories or their titles had spaces.

Taking it one step at a time

Beyond the technical experience I’ve gained from this, I value the non-technical aspect of working on this project.

I have a habit of jumping ahead, trying to anticipate the solution without working through the kinks. This can be useful if you’re forced to make a decision in a short period of time, but problematic when you need to build something that will have lasting impact and implications. And it’s not good practice when you’re trying to TDD or first endeavoring on a new project. When starting with something new, start slow. Ask questions. Poke around. And don’t be overwhelmed the entirety of a project. By asking myself what I know, what I don’t know, and what I need to know, I felt like I was better clarifying my knowledge base.

Ultimately, I learned more about myself, which is incredibly beneficial in any environment or circumstance. I find myself learning best when I write words down or sketch a diagram, and less so when speaking abstractly or conceptually (read: not an auditory learner). Examples are the best; analogies, not always. I may not be able to perfectly anticipate issues that may arise or estimates for stories, but more often than not, I am surprised by my own ability to efficiently implement features. There are times when my memory recall is faulty or I have a hard time making connections or seeing the larger picture, as previously mentioned. It is, perhaps, because I fail to actively question or prod further or engage in a conversation with myself as I write code. I remind myself to not be on autopilot mode. Now, I try to anticipate error messages and the source of these errors. I try to verbally articulate my project, challenges that I’m facing, and provide as much meaningful context as possible.

Being a developer can teach you a lot about how you are and challenge you to be a better person — one who is patient, solution-oriented, dually focused on details and the bigger picture, and able to discern whether information is relevant. And maybe this introspective mode is a reflection of the spirit of the new year, but it has been infinitely helpful for me to think about how far I’ve come.

--

--