Hosted Tic Tac Toe

Lessons learned from building on top of my own software

Matt Higgins
7 min readAug 18, 2016

Over the past few months I’ve worked on creating a console-based tic tac toe game (written in Clojure) and a simple web server (written in Java). It was my first time building anything in either of those languages, and although there were certainly frustrating moments it was absolutely a great learning experience. Not only did I have the chance to learn about and work in new languages, I had the time and space to concentrate on trying to adhere to best practices for building extensible software — I even wrote a bit about some of that previously:

The real test of whether my server and tic tac toe programs followed those practices was whether I could build something new on top of them without making a ton of changes.

And of course that’s what my next project was — creating a hosted tic tac toe game, playable through a browser. The code is available here.

Getting Started

My first objective when starting on this project was just figuring out how to wire the different pieces together. I created a new Clojure project and wanted to be able to access code from the tic tac toe program in it.

Fortunately leiningen makes it pretty simple to specify dependencies for a project. Deploying my tic tac toe program to Clojars (a repository for open-source Clojure projects) was also pretty simple, although I did have to rename my project because its original name, clojure-ttt, was already taken on Clojars (by an 8th Light crafter, of course).

After the dependencies were declared, using the original tic tac toe code in the new Clojure project was simple.

It was decidedly not simple to use the Java server code though. I don’t want to go into all of the details, but the steps involved included:

  • creating an account for the Sonatype central repository
  • opening a JIRA ticket to be able to push my Java server code up in as a snapshot
  • renaming the project according to the conventions of the repository
  • figuring out how to specify the Sonatype snapshots repository (not the same as the “normal” one) in the hosted tic tac toe project

Now I have somewhat of an appreciation for why some developers despise the Java ecosystem. I’m certainly not passing judgment myself, but I will say the process of pushing a Clojure project was much easier (and simpler) than doing so for the Java project.

Another slight hurdle I ran into (very slight) was remembering how Java interop in Clojure works. Once I had that figured out though, I was able to use code from both of my earlier projects in the new hosted tic tac toe project. Not to do anything spectacular, of course, but I had the pieces hooked up and was able to turn my attention to creating something new.

The Open-Closed Principle at Work

The first feature I wanted to get working was for a user to be able to view a homepage. Pretty much the simplest thing I could think of.

When working on the Java server project, I made a concerted effort to keep the “server stuff” (connection handling, request and response objects, etc.) separate from the “app stuff” (the logic for how to generate a response from a request). The Java server includes an Application interface and one implementation of it (needed to pass all of cob_spec), and I knew that I would need to create a new implementation of the Application interface in this new Clojure project. Surprisingly this wasn’t too hard.

Here’s the code that got me my first two passing tests — return a 200 for requests to “/” and a 404 for everything else.

Soon after, I added to the happy path and included an HTML document in the body of the response and setting its content-type header.

One of the things that I can say I’m proud of in how I designed my Java server was the decision to define an Application interface and keep it separate from the core responsibilities of the web server.

Although part of that decision was due to trying to eliminate cyclic dependencies between the packages of the Java server and better follow the package principles, I also knew that the server would be pretty useless if it only worked for the specific scenario I was considering (passing cob_spec) when I was writing it.

The goal was to be able to add new behavior to the server* without having to modify it, which I did in writing the hosted tic tac toe program.

  • I actually don’t think of it in terms of “adding new behavior to the server” since I maintain a (mental) distinction between the server and the application behind it, but I think that’s mostly semantics.
The homepage I settled on — the user sees it’s tic tac toe and can start a new game with the settings they specify

Concerns About Duplication

One of the concerns that I had (and still do, to some extent, even after having a working hosted tic tac toe game) is whether I have too much duplication between my Java server and the hosted tic tac toe application.

One example is the idea of routing requests. I’m doing it in different ways in each project, but the basic idea is the same and it’s made me question whether that’s something that I ought to have created an abstraction for.

The same is true for what I’ve called an Action, a Clojure protocol that contains the behavior for responding to a request. I have an interface with the same name as part of the Java server, and they’re about as similar as could be. As I look at it now, I’m pretty confident that I should have reused it rather than recreate it in Clojure (even if it is just a few lines). I think I chose not to because it was part of the cobspecapp package, which contains an implementation of the Application interface. It would have made more sense, in my opinion, to have:

  1. Re-used the Action interface from the Java server in the hosted tic tac toe game.
  2. Separated the Action interface out into its own package, distinct from cobspecapp.

This didn’t prevent me from doing what I needed to do to get the hosted tic tac toe game working, but it was additional time and duplicated effort that could have been spent on something else.

The Distributed Game Loop

That duplication might have come about because I was concentrating my efforts for code re-use in other areas. One of the nice “aha” moments that I had when working on this project was realizing and understanding that it wouldn’t be possible to reuse the original game loop from the terminal-based tic tac toe program for the hosted one.

I believe I would have come to that conclusion on my own, given enough time, but I have to give credit to Cat (recently graduated apprentice and current 8th Light crafter) for a five minute chat that pushed me in the right direction, and to Dave (my mentor, one of 100 things he does) for pretty succinctly explaining that by separating the game between a client and a server, what was once a centralized game loop in the terminal-based version would also need to be distributed. In other words, I couldn’t use my original game loop and that was fine.

Final Thoughts

This project also provided me with an opportunity to try using Cucumber to write feature specs for the first time. After having seen them being used in a client project when pairing with Dave and using cob_spec (not Cucumber but still a similar idea) to drive the development of my Java server, I decided it was time for me to start writing some myself.

I found that it wasn’t that hard, technically, to do. What was challenging was figuring out what features to specify and how to find a balance between providing enough detail to be able to create a functioning application based on those features but not diving down too far into implementation details.

Although it was difficult to do that, the benefits were significant. The tests:

  • served as unambiguous acceptance criteria, clearly defining what “done” meant for a particular feature, which makes it easier to get a client to sign off on it
  • made it easier to estimate how long the project would take
  • provided clear direction as to what I would work on next

The short amount of up-front planning time definitely paid off, and the project was less frustrating overall than it would have been otherwise.

If you don’t plan out an iteration, you do save some time at the beginning of the week and can start writing code right away, but that code might not lead you in the direction that the project needs to go (i.e. where the client wants it to go). Also, you still have to confront the question “what do I do now” once you finish working on a feature — it’s much nicer to have a roadmap for the week already planned out.

I had an intellectual appreciation for that idea before working on this project, but experiencing it for myself was extremely valuable and has made me believe it.

My biggest takeaways from this project were confirming the importance of SOLID principles for software design (it really does make your life easier to be able to re-use code) and the value of planning a project based on clearly defined acceptance criteria. The incidental technical skills that I learned and/or practiced are also valuable, but it’s the higher-level concepts whose value became clear over the course of building a hosted version of tic tac toe that will stick with me no matter what kind of software projects I work on in the future.

--

--