Thursday, February 28, 2013

Abstractions

Writing a decoupled program depends on abstractions. This allows objects to use another object without caring about the details of how it is implemented. When I began my apprenticeship, over a month ago, I didn't fully understand why this is so useful. I understood why a program should have a minimal number of dependencies but couldn't make the logical jump to why abstractions are so important.

One of the first steps in my Tic-Tac-Toe program was building the board class. It was a minimal class and I stored the individual squares as a 1D array. I exposed the squares array as a public, read-only variable. Thus my game class could simply look at the desired square and check if it was empty or get its value. There wasn't an square_empty? method because I had granted access to my array.

class Board
  attr_reader :squares

  def initialize
    @squares = Array.new(9)
  end

  def set_square(index, value)
    @squares[index] = value
  end
end

If I had wanted I could have gotten rid of set_square and replaced attr_reader with attr_accessor and the effect would have been the same. I was having an issue with this code though. My game presented options to the player for squares 1 through 9. My array indexes were 0 through 8. So when I made a move or checked a square, I had to remember to subtract 1 from the square index. This was annoying enough that I modified my set_square method to do that automatically.

class Board
  attr_reader :squares

  def initialize
    @squares = Array.new(9)
  end

  def set_square(index, value)
    @squares[index-1] = value
  end
end

This left me with nagging issue. When I checked if a square was empty, I needed to subtract 1 from the index but not when I made a move. I realized that this inconsistency was pointless and that the only solution was to remove attr_reader. It wasn't doing anything helpful and was in fact making my game harder to work with. So I added the necessary methods to my board to replace the missing functionality and had this.

class Board
  def initialize
    @squares = Array.new(9)
  end

  def set_square(index, value)
    @squares[index-1] = value
  end

  def empty_square?(index)
    @squares[index-1].empty?
  end

  def square(index)
    @squares[index-1]
  end
end

Initially, this felt less efficient. After all, there are more lines of code doing the same functions as before. The immediate benefit I saw was that I no longer had to worry about subtracting 1 from the square index in my game class. The second benefit I didn't notice until later. This third version of my board allowed me to store the squares any way I saw fit. I could create any data structure I wanted for them. I could put them in a linked list, a hash, or even an array of square objects. This is where the usefulness of abstractions became clear to me. No matter how stored the squares now, it would not affect my game class. All I had to do was provide an interface to work with and I could store my squares on a computer at the South Pole and retrieve them over a network if I wanted.

This is a fairly simple example but I think it demonstrates the flexibility that abstractions allow. At the beginning of this project, I didn't understand why the flexibility mattered. I saw it as unnecessarily long code. It was only after a couple redesigns and multiple refactorings that I saw the benefits to me. It allowed me to make changes to how a class worked without affecting other classes that used it. It amazes me that I didn't see how useful this was at first. I guess that's one benefit of doing this apprenticeship.

Monday, February 25, 2013

Working Upward

Today was spent rewriting my mocks for testing sockets and server sockets. I've gotten them to a place where I think they're actually going to be useful for testing. Furthermore, I've put them in their own little wrappers. It's finally sinking in why wrapping is a good idea. Now my server won't care if I'm using fake sockets or the real deal. It should just do what it's supposed to do. My goal for tomorrow is to actually make it do the first part of what it should do.  It sounds like a huge jump, but really it shouldn't be bad. It's been really great to be working on this project at the same time as other apprentices. I've actually seen and helped solve problems that I'll encounter down the line. So yay for that, I guess. Anyway, we'll see what I can really do tomorrow.

Thursday, February 21, 2013

A New Project

I'm finally finished with Tic-Tac-Toe (even though I know I'm not). The good news is that I'm finished for now. I'll be revisiting this in the future, but for now I'm on to something new. Yesterday I started on my Java Http Server. Most of my time was not spent working on the server though. My first task was to make Rubyslim run on 1.9.3. Then I needed to update the internal test suite for Http Servers to 1.9.3 and make it work with the update to Rubyslim.

The first didn't take nearly as long as I expected. Updating the test suite was more work than I thought. Getting it to run on 1.9.3 and hooking in the new version of Rubyslim didn't take that long, but I had a new problem. The issue was that none of the tests were running. I don't mean that they were failing. I mean that they didn't even attempt to run. I eventually figured out that the configuration for the tests was outdated and managed to centralize and update it. So now instead of each test having its own config, that lives at the suite level. That occupied a good portion of my day.

I'm still trying to figure out where to start with the server. There are a lot of pieces that will need to be built, but aren't necessary now. I was happy that I was able to spike out a quick section of code and got a single test to run and pass in the test suite. The goal tomorrow will be to rebuild that code while writing tests. That's going to take some thought.

Monday, February 18, 2013

Almost But Not Quite Done

Today I spent most of my time cleaning up my Tic-Tac-Toe code and adding tests in a few areas that were lacking. I was feeling pretty confident until I said I was done. Then I hadn't added a Gemfile. Then it was missing version numbers and I needed a .rvmrc file as well. Oh, and hey, the Qt version keeps not letting the player make a move. To explain how this happened, let me say that the Qt version doesn't lend itself to testing (at least not in a way that I know of). This illustrates what a dangerous world it is without tests to back up assertions.

In the end, I finished everything except the Qt issue. That has to do with wanting to lock the board when it's not a human player's turn and then unlocking it when it is. The real problem I have with this is that I'm not even sure if it's necessary, but I have no way to accurately test it. So tomorrow, I'm going to remove the locking and see if anyone can break my game. If not, then the locking is probably not necessary.

Thursday, February 14, 2013

The (Hopefully) Last Bits

Everything seems to be coming together with my Tic-Tac-Toe app. I've gotten the command line worked out with the new way of handling player input. There's now a real runner living in between the game and the gui, which handles all the action. I was even able to spike out the Qt portion and get that running. As penance for horrible, untested code, I threw out what I wrote and intend to implement it for real tomorrow.

Surprisingly I'm on track to meet my estimate for this phase. I have a feeling more little issues will crop up to delay me though. They always do. This evening I had a vexing issue where I was accidentally breaking one test with another. The weird thing was that it was in another file. That turned out to be a difficult thing to track down. Now, I have an idea of where to head next. That's what's important.

Monday, February 11, 2013

Qt For Real

This weekend I managed to bring the console version of my Tic-Tac-Toe app back to life. It probably spent a little bit too long in pieces, but it is what it is. Still a little bit of work to go, but hopefully not to bad. Doing this allowed me to focus on the Qt portion of my app today. Thankfully the refactoring I did to my game made it really easy to make a window and make it so I could click and place moves on the board. That part was surprisingly easy. I think this just means that the rest of the program will take me a while. We'll see.

I spent this evening investigation dialog boxes. It looks deceptively easy to get a dialog box to come up and then return the value you want. I think the trick will be writing a custom dialog box. None of the built in ones seemed to use radio buttons. I suppose that I could use a pair of select dropdowns if I have to. I think this is it for tonight though. I've had enough for one day.

Friday, February 8, 2013

It Never Ends

This week has been quite busy. I don't think I've put this much work in for a while. That's why I declared Wednesday night a no work time. Thursday was back to work as usual on Tic Tac Toe. I was still having trouble with a circular dependency. After speaking with a craftsman, I was given an idea how to remove it. An interesting side effect of this change was that a whole file or two disappeared. The feeling of being able to get rid of code without losing functionality is a good feeling.

There is still a lot of work to do. I still haven't made any progress on the Qt version of my game. My mentor and I tried to find some solutions to my block today. This involved a white board, time, and a lot of convoluted drawings. I've got a couple ideas now though. My goal is to try and implement them this weekend so that I can start on the Qt version next week. I also need to spend some time with Rylan and rewrite our broker software. There's always more to do.

Tuesday, February 5, 2013

Oodles and Oodles of Rindlets

Wow, I've been exhausted lately. This weekend was pretty much a blur. I spent most of each day working on my Tic Tac Toe program. I pulled it apart and fit the pieces back together again. It allowed me to remove several unnecessary files and to reorganize things so that something can drive the game, instead of it driving itself. I feel like it will be easier to add the Qt stuff on top of what I currently have. I'm still trying to solve my command line issues though. I haven't worked out how to do player selection or how the driver will actually run the game.

Rindlets are the reason why I'm still at this point by Tuesday evening. The apprentice assignment this week has been very interesting but it's also a lot of work. There's so much wiring that has to go on to be able to make a stock purchase and then confirm it. There was a problem with confirmations and it was that they didn't exist until this morning. Rylan and I were asked to come in early to help Paul write some of the project code. It's really interesting seeing how people with more experience think about and write tests. I've still got so far to go.

While this morning was interesting, more issues kept cropping up. Necessary information was still missing from commands. When we talked to Paul about this, the response was, "Can you write it?" That was cool, but it felt like a lot of responsibility. It also meant that Rylan and I didn't get very far on our own stock broker today. Thankfully tomorrow seems to be a trial run. Still, I learned how to do a pull request on github. More importantly I learned the embarrassment that comes with not running tests before committing. I still can't believe that we actually submitted a pull request to master before we ran tests. I'm going to chalk that one up to the learning process. It's something that I do not intend to repeat on a shared project.

Anyway, I'm really tired right now. I think it's time for some rest. There's more work to do, but I'm not in a condition to do a good job. At least not right away.