We recently had an interesting situation with our test suite while working on a Rails project. When our entire test suite was run (rspec -> cucumber -> jasmine) we would have all tests pass, however, when cucumber was run on its own it would fail. Upon inspecting our stack trace we saw that a followed redirect in cucumber was not rendering correctly. This meant that the environments differed between running the entire suite and running the acceptance tests in isolation. How could this be, we all thought, an app is an app and the environment is test no matter how it is run.
Upon inspection we were able to follow the problem to a 'singleton' we had within the system. We had a mailing list object that was meant to have a single instance to represent the single mailing list we are keeping. Within our seeds.rb file we had a check to see if an instance exists, and if not to then create an instance. Our class looked like this:
All developers on the project understood that mailing list was to be called by mailing_list.instance and in our heads we thought of it as a singleton. In production this was working. Thankfully, we had tests to expose the problem with our logic. When rspec ran it created it's first MailingList instance at id 1, which made instance work throughout the test suite and explained why our tests passed when the entire suite was ran. However, cucumber deleted its instances of MailingList after a scenario had finished. This was a problem because the mysql backend kept issuing ids in order. Therefore, the above code would return a nil object when we asked for the instance.
Our revised singleton looks a little better:
We now give instance more importance. We were able to drop the singleton creation out of our seeds file since calling instance always ensures a singleton. When we use create it gives an informative error and leads the developer to use instance, as intended. Moral of the story, tests are more important than you think.
Sunday, September 18, 2011
Tuesday, July 19, 2011
The Craftsmen Aren't Crazy
My fellow apprentice Stephen had a great blogpost that I really just want to ditto. Stephen hit the nail on the head and I want to add some ideas his main points:
1) "I write tests because I want to code well and fast": I think it's important to note the huge amounts of time we lost because of poor code coverage. Weeks of work went down the drain on slippery bugs nested in tightly coupled code. The code base was begging to be refactored, but we simply couldn't without first testing the nasty code that wasn't our own. Furthermore, it was enough work to meet our stories on time in the system so refactoring outside the scope of our stories was rare and I wish it did not have to be that way. Test coverage is amazing. It drives simple development and loose coupling.
2) "Team communication is key": No matter what the circumstances, be communicative. I learned that it's more important to ask trivial questions than worry about looking dumb. We are not impressing the other developers on the project, we are impressing the client.
3) "Communicate religiously with the client": Acceptance criteria is almost always not specific enough. Do not let the client get away with specifying vague stories. This will always come around to bite the developer when the developer's vision does not match the client's vision. Also, use acceptance criteria to force the client to understand what it is they want implemented, exactly. Colin and Justin gave some insight into their troubles with the client not understanding the story they were asking for and it really changes the flow of the iteration as time moves forward.
4) "Pair programming is awesome": It is awesome! Our project implemented code reviews and the process was more tedious and less productive than pair programming in all instances.
5) "Clean code matters": As the project grows in size dirty code gets dirtier and dirtier. It receives 'bit rot' and even though it's been working as is the entire time it can sneak in and break the project. It collects dust. A feature you thought lived totally on its own is now breaking all of the tests. It's terrible too, since it's completely avoidable. Coming off of this project I understand the importance of clean code in the scope of a big project (especially one that is only getting bigger).
1) "I write tests because I want to code well and fast": I think it's important to note the huge amounts of time we lost because of poor code coverage. Weeks of work went down the drain on slippery bugs nested in tightly coupled code. The code base was begging to be refactored, but we simply couldn't without first testing the nasty code that wasn't our own. Furthermore, it was enough work to meet our stories on time in the system so refactoring outside the scope of our stories was rare and I wish it did not have to be that way. Test coverage is amazing. It drives simple development and loose coupling.
2) "Team communication is key": No matter what the circumstances, be communicative. I learned that it's more important to ask trivial questions than worry about looking dumb. We are not impressing the other developers on the project, we are impressing the client.
3) "Communicate religiously with the client": Acceptance criteria is almost always not specific enough. Do not let the client get away with specifying vague stories. This will always come around to bite the developer when the developer's vision does not match the client's vision. Also, use acceptance criteria to force the client to understand what it is they want implemented, exactly. Colin and Justin gave some insight into their troubles with the client not understanding the story they were asking for and it really changes the flow of the iteration as time moves forward.
4) "Pair programming is awesome": It is awesome! Our project implemented code reviews and the process was more tedious and less productive than pair programming in all instances.
5) "Clean code matters": As the project grows in size dirty code gets dirtier and dirtier. It receives 'bit rot' and even though it's been working as is the entire time it can sneak in and break the project. It collects dust. A feature you thought lived totally on its own is now breaking all of the tests. It's terrible too, since it's completely avoidable. Coming off of this project I understand the importance of clean code in the scope of a big project (especially one that is only getting bigger).
Friday, July 1, 2011
The Professional Side of Development
This week was my first week with the Bridge team and it has been a learning experience. I came into my apprenticeship looking for experience in the workplace. During my time at school and while coding on my own time I'm usually working by myself or in very small groups. Our projects are usually limited in scope and intended to teach about a specific piece of the discipline. If a school project is rushed and contains untested sloppy code, that's usually okay as long as it runs. After submitting code for class I usually never look at it again. This project is different.
I joined the project, I did not start on the project. This is the first learning point. Coming into an established codebase can leave you feeling lost. It's like moving to a new city and not knowing where anything is, how to get anywhere, or how the transportation system works. The approach I've had so far is to keep in mind the scope of my problem and avoid heading into areas that I do not need to be in. That way I can focus on implementing a feature without being concerned with other areas.
The second learning point is the multitude of languages and areas of concern when building a web app. I started my apprenticeship not know any javascript, for instance, and I've been learning as I go. It's exciting to take on new languages and be able to control different areas of design than what I am accustomed to.
The third learning point has been everything involved in a project that is not code. Each iteration takes a lot of planning. Communication is constant (daily standups, weekly iteration reports, plus any extra communication needed) and requires a skill set that is very different than the skill set to sit down and write code. I'm learning about workflow and processes in a professional setting, which is a skill that I think one could only learn by doing.
8th Light is getting to me. The project didn't have acceptance testing and I am actually excited to add acceptance tests. Who would have thought?
Thursday, June 16, 2011
Cob_Spec and Credence (My "C" Projects)
Cob_Spec is starting to come together nicely. As I mentioned in my last post, cob_spec is an HTTP Server acceptance testing framework. This week I was able to implement simultaneous requests (which right now adds in batches of 100). The simultaneous requests are handled by the typheous gem and is working very nicely. Cob_spec now allows the user to specify an address to test in a batch of 100. That batch of 100 is added to an array of addresses to check in parallel and the server receives a query for each individual address when the test is run. This is shaping up nicely for testing, oh I don't know, Tic-Tac-Toe servers and the like.
To use simply grab cob_spec from Github. Next, run bundle install in the root folder of cob_spec. Then use the command java -jar fitnesse.jar -p 8080 and navigate your browser to http://localhost:8080/ to use the testing suite.
Secondly, Paul and I have taken some time to extract the estimation tool out from artisan and develop credence. Credence allows a user to create an estimation room and invite fellow estimators to estimate projects. The events are driven by pusher, which is cool because some of the heavy lifting is moved to pusher. Credence currently supports single and pert estimate rooms.
To use simply grab cob_spec from Github. Next, run bundle install in the root folder of cob_spec. Then use the command java -jar fitnesse.jar -p 8080 and navigate your browser to http://localhost:8080/ to use the testing suite.
Secondly, Paul and I have taken some time to extract the estimation tool out from artisan and develop credence. Credence allows a user to create an estimation room and invite fellow estimators to estimate projects. The events are driven by pusher, which is cool because some of the heavy lifting is moved to pusher. Credence currently supports single and pert estimate rooms.
Friday, June 10, 2011
Acceptance Testing and other Small Projects
This week I fixed and added to Cob Spec, which is a simple HTTP Server testing framework. It runs using FitNesse and Ruby Slim and so far tests for a 200 OK response and a 404 Not Found response when necessary. The plan is to expand Cob Spec further and have more rigorous testing. I'm in the process of extending Cob Spec and I started working on a fixture to simulate simultaneous browser requests, but this is still a work in progress. Eventually (when everything decides to cooperate), this test will be part of the Cob Spec suite.
This week I was also able to complete my first Artisan story (for a whopping one point!). I am now trying to focus on becoming more fluent in Rails and have the opportunity to add to the many Rails projects in progress at 8th Light. Besides Artisan, I have been working with Paul on Credence.
On a side note: It feels good to have Tic-Tac-Toe behind me.
This week I was also able to complete my first Artisan story (for a whopping one point!). I am now trying to focus on becoming more fluent in Rails and have the opportunity to add to the many Rails projects in progress at 8th Light. Besides Artisan, I have been working with Paul on Credence.
On a side note: It feels good to have Tic-Tac-Toe behind me.
Friday, June 3, 2011
Threading the HTTP Server
Unfortunately, I have not had as much time as I would like to have to spend at 8th Light (porque tengo una clase de espaƱol en la tarde). That being said, this week I was able to create a working HTTP server and play out entire tic-tac-toe games. This works great and I'm glad to be at this point. From here I need to make my server threaded (we don't want everyone playing one collective game) and manage games per user. This lead my inquiries into two directions; one, to Threads in Java and two, to using cookies to manage user sessions.
Java's standard library includes a Thread class which makes threaded concurrency fairly simple when working with Java. By having my Server class extend Thread I am able to receive concurrent Socket connections and handle them properly. This piece of work is still in progress, but extending Thread allows me to avoid a complete headache.
Using cookies is also fairly simple. When generating my packet headers I now need to be mindful of the Set-Cookie and Cookie fields. When generating a new Game, I can assign a new cookie and use a HashMap to map the unique cookie to the specific Game. Moving forward, I need to reset the cookie at the end of each game and then this portion of my code will be working.
I was also able to implement a few other odds and ends relating to my HTTP server, namely I now give out a 404 Error for paths that do not exist.
This week I was also introduced to Artisan and 8th Light's project management process. Mike was able to help me get started with using Artisan. He explained the ideas of stories, iterations, estimating, ect, that all go into managing projects. I was also able to work on an Artisan project on Artisan (let that sink in). Kevin and I were able to take some time to pair and work on a story to validate unique login names and allow users to only edit their own profile.
Finally, I was able to deploy my gaeshi project to fulfill the homework requirements for last week's 8th Light university. It's not much and I would really like to play around with Gaeshi when I have some spare time. I want to try something ambitious and create a blogging app for Gaeshi and migrate my 8th Light blog.
Java's standard library includes a Thread class which makes threaded concurrency fairly simple when working with Java. By having my Server class extend Thread I am able to receive concurrent Socket connections and handle them properly. This piece of work is still in progress, but extending Thread allows me to avoid a complete headache.
Using cookies is also fairly simple. When generating my packet headers I now need to be mindful of the Set-Cookie and Cookie fields. When generating a new Game, I can assign a new cookie and use a HashMap to map the unique cookie to the specific Game. Moving forward, I need to reset the cookie at the end of each game and then this portion of my code will be working.
I was also able to implement a few other odds and ends relating to my HTTP server, namely I now give out a 404 Error for paths that do not exist.
This week I was also introduced to Artisan and 8th Light's project management process. Mike was able to help me get started with using Artisan. He explained the ideas of stories, iterations, estimating, ect, that all go into managing projects. I was also able to work on an Artisan project on Artisan (let that sink in). Kevin and I were able to take some time to pair and work on a story to validate unique login names and allow users to only edit their own profile.
Finally, I was able to deploy my gaeshi project to fulfill the homework requirements for last week's 8th Light university. It's not much and I would really like to play around with Gaeshi when I have some spare time. I want to try something ambitious and create a blogging app for Gaeshi and migrate my 8th Light blog.
Friday, May 27, 2011
Writing a Java HTTP Server from scratch
During my second week at 8th Light I was asked to create an HTTP Server to serve TTT games to remote players. That being said, it really had nothing to do with playing TTT, which is a good thing, since the code was architecturally sound enough to place the game logic in a Package named TTTGame and create an independent package named TTTServer. The two packages only cross paths on one occasion, in an abstract class to integrate game logic and web requests.
About five minutes into development I stumbled upon the holy grail, the Sun class com.sun.httpserver. I could bind paths and verbs in different combinations to different handler classes (similar to Rails). Of course, my joy was killed and I was told not to use this class. I had to go forward and build the server from the bottom up.
I started with the essentials (this is Agile after all, I need to build iteratively out from the core). I had experience with Socket programming, although it was a little hazy. So I setup a Server class to wrap around a Server Socket and dish out new Client Sockets as they come in. This was easy enough. From here, I started to run into problems. My experience with Socket programming was to leave a connection open, send data, and close the Socket. Well, this doesn't work for HTTP. I had some learning to do. Namely, I need to learn about HTTP packets and a little refresher on rendering HTML.
The majority of this week was then spent building a Packet class and a Packet Parser class. Initially, I was attempting to build the Packet Parser in a laborious line-by-line fashion. This had to go, it was too painful to write and too ugly to use. Paul put me on the right path, at this point, by implementing the parser recursively. Not only did the LOC drop dramatically, but the class experienced a speed up (which is important with the potential for huge amounts of HTTP packets flying to and from in short amounts of time). I created a utility program to chart the two styles of parsing side by side.
I then wrote my Packet class to nicely integrate with the Parser and voila (as the French say) I had the groundwork of an HTTP Server. Now, I need to add routes based on path (throwing 404 errors when a path isn't valid), and integrating the game logic so a remote user can play.
Finally, the last item on my list of things to do is generate a Session Key for each user on my end and have the user then pass the key in to play their unique game (since we can not keep the Socket connection open throughout the entirety of the game).
Hopefully, I will have a hand made HTTP Java Server up and running in the near future.
About five minutes into development I stumbled upon the holy grail, the Sun class com.sun.httpserver. I could bind paths and verbs in different combinations to different handler classes (similar to Rails). Of course, my joy was killed and I was told not to use this class. I had to go forward and build the server from the bottom up.
I started with the essentials (this is Agile after all, I need to build iteratively out from the core). I had experience with Socket programming, although it was a little hazy. So I setup a Server class to wrap around a Server Socket and dish out new Client Sockets as they come in. This was easy enough. From here, I started to run into problems. My experience with Socket programming was to leave a connection open, send data, and close the Socket. Well, this doesn't work for HTTP. I had some learning to do. Namely, I need to learn about HTTP packets and a little refresher on rendering HTML.
The majority of this week was then spent building a Packet class and a Packet Parser class. Initially, I was attempting to build the Packet Parser in a laborious line-by-line fashion. This had to go, it was too painful to write and too ugly to use. Paul put me on the right path, at this point, by implementing the parser recursively. Not only did the LOC drop dramatically, but the class experienced a speed up (which is important with the potential for huge amounts of HTTP packets flying to and from in short amounts of time). I created a utility program to chart the two styles of parsing side by side.
I then wrote my Packet class to nicely integrate with the Parser and voila (as the French say) I had the groundwork of an HTTP Server. Now, I need to add routes based on path (throwing 404 errors when a path isn't valid), and integrating the game logic so a remote user can play.
Finally, the last item on my list of things to do is generate a Session Key for each user on my end and have the user then pass the key in to play their unique game (since we can not keep the Socket connection open throughout the entirety of the game).
Hopefully, I will have a hand made HTTP Java Server up and running in the near future.
Friday, May 20, 2011
Week one at 8th Light
When I first wrote my Tic-Tac-Toe application I tried to create working code and that was all. I didn't make any piece reusable, I didn't make my code flexible, I didn't write unit tests, and I didn't separate concerns. My computer player algorithm was brute force and worked only after too much prayer and cursing. If someone else were asked to work on the code without me being there they would probably first rip out their hair and then rewrite it. When I started, on my first day, my first task was to work with the code I had already written and I became nervous. I had to write unit tests for my working Tic-Tac-Toe. I wrote the JUnit tests in Eclipse and when Eclipse complained too much I switched to Intellij and found my new favorite Java IDE. After my tests passed it was time to re-factor.
This is when I did myself a favor and started over from scratch. I went through and implemented all the components of a Tic-Tac-Toe game (board, game rules, game logic, etc). I made a mistake in extending Board in Game for code reuse. Paul advised me to change this to a has-a relationship and went into SOL of the SOLID principles. Everything was going well and looked much cleaner.
This time around I also did strict TDD, which I had never done before. In school I typically write my code and then write tests to pass after the fact. This, I have learned, makes some people cringe. The reason my code was so clean was in part due to TDD and in part due to thinking about architecture more in depth before beginning. Regardless, clean and well written tests during TDD are invaluable to catching little bugs that blow up as the project grows.
Then it came time to make Tic-Tac-Toe players. I was told to write the Players in a way that I could drop in Players to square off, Human vs. AI, Human vs. Human, and AI vs. AI. Since I was coding this project in Java I just made a Player Interface to hold player number and return the x, y coordinates of their move when given the board state. I wrote an adapter for my brute force algorithm and a human player. I was able to drop them both in and have them play out Tic-Tac-Toe games. Then came the toughest part of the project, writing an AI player who picks their move based of a minimax implementation. This was a recursive mess when I first dove in. I developed my own TreeNode data structure (since Java Collections doesn't have trees) and tried to store each possible board state as a TreeNode. After getting essentially no where when doing this I decided to try again. Thankfully, Eric Meyer delivered a minimax lesson for all of the apprentices. Finally, I had a working AI player which used minimax.
During the second half of the week Doug introduced myself and two other apprentices to Fitnesse accepting testing framework. We're currently working through Java Fitnesse tutorials using Slim with the final goal being an Objective-C implementation. That's where I'm at now, at the end of the first week.
This is when I did myself a favor and started over from scratch. I went through and implemented all the components of a Tic-Tac-Toe game (board, game rules, game logic, etc). I made a mistake in extending Board in Game for code reuse. Paul advised me to change this to a has-a relationship and went into SOL of the SOLID principles. Everything was going well and looked much cleaner.
This time around I also did strict TDD, which I had never done before. In school I typically write my code and then write tests to pass after the fact. This, I have learned, makes some people cringe. The reason my code was so clean was in part due to TDD and in part due to thinking about architecture more in depth before beginning. Regardless, clean and well written tests during TDD are invaluable to catching little bugs that blow up as the project grows.
Then it came time to make Tic-Tac-Toe players. I was told to write the Players in a way that I could drop in Players to square off, Human vs. AI, Human vs. Human, and AI vs. AI. Since I was coding this project in Java I just made a Player Interface to hold player number and return the x, y coordinates of their move when given the board state. I wrote an adapter for my brute force algorithm and a human player. I was able to drop them both in and have them play out Tic-Tac-Toe games. Then came the toughest part of the project, writing an AI player who picks their move based of a minimax implementation. This was a recursive mess when I first dove in. I developed my own TreeNode data structure (since Java Collections doesn't have trees) and tried to store each possible board state as a TreeNode. After getting essentially no where when doing this I decided to try again. Thankfully, Eric Meyer delivered a minimax lesson for all of the apprentices. Finally, I had a working AI player which used minimax.
During the second half of the week Doug introduced myself and two other apprentices to Fitnesse accepting testing framework. We're currently working through Java Fitnesse tutorials using Slim with the final goal being an Objective-C implementation. That's where I'm at now, at the end of the first week.
Subscribe to:
Posts (Atom)