Tuesday, June 30, 2009

Day 25

Today I was able to start planning my new Limelight FitNesse program, since there is just no way I can expand the sidebar project. I figure I will have a load of players, one for each widget, but they will all be rather uniquely defined. Since the range of widgets is vast, like from an image to making text bold, I think it will be hard to try and follow one format. I am also going to have to do a series of conversions to interpret the Json object that FitNesse will send me, containing the widgets. At the moment, I am think this will be the chain of conversions: Json-> someList -> a widgetInterpreter -> a widget ordering process -> Players -> props and then onto the scene.

While doing some more refactoring today, I learned a lot about the nature of exceptions. When an exception is thrown, the current process will be stopped (although process might not be the right word) and Java will crawl back up the stack until there is a catch block. From there it will continue on. So in memory, a chunk of space is left open in the stack for this catch block (which I believe comes right after the function parameters), and anything below this block will be removed from the stack. An interesting question would be, if we make a thread, and in this thread we throw an exception with no catch block, where will the exception be caught? Will it rise to the top of the thread and just die? I would like to believe Java has some last resort catch so that this thread will still print the exception, and then maybe die right after that, but I am not sure. Also, if you wish to pass a certain type exception even higher, but you need to catch other exceptions at a lower level, then you can first catch the specific exception, and throw it again, then catch all others.

try{
...
} catch (SocketException se){
throw(se)
}
catch(Exception e)
{...}
this way you can migrate all exceptions to where you want them.

On another note:
Liskov Substitution Principle: Subtypes must be substitutable for their base types.
An example of this from Agile Software Development is: "Presume that we have a function f that takes, as its argument, a pointer or reference to some base class B. Presume also that there is some derivative D of B which, when passed to f in the guise of B, causes f to misbehave. Then D violate the LSP."
We came across an example of this today when trying to create a List from an array. There is a method in the Arrays class called .asList(Array array), which as you might guess, apprears to do what we wished; however, when we then tried to remove an item from the list we just made, we got an error that indicated a remove was not possible. Apparently, and correct me if I am wrong, this asList function returned an object masquerading as a List, while really having the array data structure. This was a violation of the LSP.
Reading further into this, another excellent example would be a Square extending a Rectangle. Given that a square need only have 1 side set, and the rectangle requires 2, it is possible to forsee certain errors and fragilities that might arrise.

Monday, June 29, 2009

Day 24

I have been quite inconsistent with this blog, and I believe this is a mistake. Thus I will remedy this mistake by trying to blog after each day... something I should have done from the start. The blog for me will be an excellent reference to what I have learned, what I need to learn, and what I have accomplished. It will also solidify, each day, what I have learned.

The last weekish has been mostly focused on the lighthouse task #123, changing the manner in which FitNesse updates. It turned out to be a rather larger task than first anticipated, but at long last it has been resolved. Just today we went back and refactored the code we used to implement it. FitNesse can now be updated from a single jar file, whereas it used to require a zip file containing many bits and pieces, and some of the files would even have to be changed manually.

Much of today was actually spent on getting our iPhones to work!

I have also been able to make more progress on my major summer project, the issue is that I was planning on building this project upon my FitNesse Side Bar project that I completed earlier, but now that code is overextending it intended boundaries and thus is getting a bit messy. I have been constantly refactoring, but I fear I might just have to scrap it and start from ground zero. The biggest problem I am having is that I have started passing page information through Limelight props... it might not be terrible yet, but the idea of passing the program's data through the GUI is rather disconcerting.

Monday, June 22, 2009

Day 15 & 16

I was able to finish the Lighthouse task #127 which was the purge history task. I added three buttons to the test history page, Purge > 30days Purge >7days Purge all. As proof that they all work, I no longer have any history! Since a user can also just type in the command URL?purgeHistory&days=?? where they can choose the number of days, I also had to add many checks to make sure the input is valid. A note on tests that test text outputs, they are overwhelmingly sensitive! After I was done making my changes I ran all the tests, making sure everything still worked, and I got one failure. Somehow something got changed in one of the template, though I didn't even know I changed it, and a test was failing because the text it got wasn't what it expected. So I looked at the output and what was expected and they looked the same, except finally I saw one case where there happened to be a newline out of no where. Long story short, I spent a very long time hunting through the code to find this line, and it ended up being in one of the html (velocity) templates. Maybe I hit the reformat command while in that file, and my IDE added a new line. I don't know, but it was very frustrating.

A very unfortunate thing occured on thursday. I lost all of my work for the Lighthouse task #123 because I am a newb at github. I thought that if you had a branch, everything in that branch is protected once you switch to a new branch, and thus you don't always have to commit. So to work on my other task I created a new branch and did a reset --hard to get a earlier version of the code. As it turns out, this deleted everyone of my changes on the other branch since I was a fool and didn't commit... At least now I know how to do it all, so the process of making up all my work should be rather painless, but it still sucks and now I know to always commit!

Tuesday, June 16, 2009

Day 13 & 14

I have been having a fair amount of trouble with my most recent task. Lighthouse task #123 which is to alter the manner in which FitNesse updates itself when it is first run in a new environment. There is a list of files that need to be copied over into the FitNesseRoot every time an update is done. Currently this list of files is in the updater code itself, but my task is to move that list of files. I need to create an ant task in the build.xml file that will call a java program which searches through the FitNesseRoot and finds all the files that need to be copied over in an update. This program must then create a new file with the names of all those files which need to be copied over, and a file of the files which shouldn't be copied, and then put those into the .jar file that is created when the ant build is performed. Then, once FitNesse is started for the first time, the updater must reach into the .jar file and pull out the updateFileList, read the list, and grab all the needed files and place them into the FitNesseRoot.
I have had to learn a lot about ant. How to create a new ant task. How to have that ant task called. How to have that ant task call a java program which creates a file. Currently I am trying to figure out how to pull the needed files out of the .jar file. Micah told me a command jar-x < fitnesse.jar which would pull out all the files in the jar, and then I could search through those to find what I need, but I believe FitNesse already has a way to extract the files I need. I just need to find this method.
I have also been given the new task Lighthouse #127, which is to create a way to delete the test history for a page up to a certain given date. This should be a fairly simple matter... but then again Murphey will probably strike me down for being so foolish as to think a task could be completed in any reasonable amount of time. I believe I will need to either add a new responder all together called the PurgeTestHistoryResponder, or add a feature to the current TestHistoryResponder which looks for a delete command and an input date. The task says to create 3 buttons, Purge >30 Days, Purge >7 Days, Purge all, all which would invoke the responder with a date.

I have also put some more work into my ultimate task for this summer. I believe I am going to create a LimeLight player for each of the WikiWidgets, so that when I recieve the JSON object from FitNesse, I can render the data into my own data structure of Players. This in theory could then be placed directly on the screen without too much extra effort.

Friday, June 5, 2009

MyUltimateTaskForTheSummer

So I need to find a way to bring FitNesse into Limelight. This will have to be done by taking all of the rendered information of a FitNesse page, wrapping it up in a nice bundle, sending it to Limelight, and then finally interpreting that information to reconstruct the page.

FitNesse pages are made up of a large string of WikiText (and some xml for some of the page properties, like if its a test page or a suite). When a page is rendered to be displayed, all of that WikiText is broken down into a massive tree structure of WikiWidgets. The WikiWidgets are objects that represent a wide range of functions or qualities. There is a WikiWidget for making text bold, for putting the date on the page, for making comments, or for inserting images. Each widget has a pattern of WikiText that it looks for, to know if it should be that sort of Widget. The widgets also have a parent widget and child widgets (with the ultimate parent being the WikiWidget Root). The bold WikiWidget is referenced with a ''' text to be made bold '''. When the page is rendered, the chunk of text with the ''' some text ''' would be turned into a bold widget, and the text inside those quotes (some text) would be made into a text widget, and as a child of the bold widget.

The process of breaking down the text into widgets is quite interesting. When it begins, a WidgetData object is created, and is loaded with every WikiWidget class (except literals, which is a different story). Then a builder object is created, which contains the WidgetData as well as the WikiText from the page to be rendered. Next, it will add a child widget to the WikiWidget Root by looping through every widget in the WidgetData and trying to find the first match of that widget's pattern to the WikiText. If it finds a match, it saves where the match is in the WikiText , and then keeps checking the other widget patterns to see if they come any earlier in the text. Once it finds the first match, it creates a WikiWidget object of that match, saves that object as a child of its parent (for the first match the parent is the WikiWidget Root), searches the text inside that widget for more matches (to become children of the just created widget), and searches the remainder of the WikiText for the next first match. This cycles recurssively until the entirety of the WikiText has been turned into a massive tree of WikiWidgets.

This tree of WikiWidgets would then be parsed into html and put on the page, but for my task I want to stop right here. I would then take this tree and probably turn it into a JSON object (a fairly simple data structure) and then ship it over to Limelight. Finally I would have to create some sort of translator which will turn this tree of widgets, in the JSON object, into Limelight props to be displayed.

This should be fun.

Day 11 & 12

On Thursday, and part of today, I worked on LightHouse task #126. In FitNesse are these things called scenarios. The scenarios are tables that the user can make which tie the test tables in the acceptance tests to the functions, like fixtures, that will allow FitNesse to test the production code. Whenever an acceptance test is run, FitNesse will grab all the text on the test page and render that text table by table. The test pages will also include Scenario Libraries, and thus when a test page is run, FitNesse also grabs the Scenario Libraries to be rendered. An issue occured recently (when FitNesse was changed from rendering a test page all at once to rendering a test page table by table) where FitNesse would silently crash while running tests if a scenario was ever defined twice. FitNesse would crash because when rendering the page (into html) table by table FitNesse needed a method to find exactly where in the String of text, of the page, a table resided. Knowing where a table resides is important when trying to generate the html after a table has been rendered (the rows of the table have been turned red or green and such). To find that location, FitNesse would search the whole String for the string of characters which make up the table. The issue is that if there are two scenarios (and actually the same problem would occur with two tests that are exactly alike) that are exactly alike, then that search through the String would find only the location of the first scenario, and not the second. Thus, when FitNesse attempted to render the second copy of that table, it would assume the location of the first copy, and an exception would be thrown.
In the end, the solution was fairly simple. All that needed to be done was guarentee that all tables were unique, so I just made a quick little method that added table number attribute to all tables, and generated a random number for each table. In this way, it would be dreadfully unlikely that two tables would even be exactly alike.
Today I was told what my ultimate task for this summer would be. I must find a way to bring FitNesse into Limelight.

Thursday, June 4, 2009

Day 9 & 10

On Tuesday I resolved the LightHouse task #125. FiteNesse keeps track of all the test history in a bunch of directories named after that test page. Inside those directories with the a strictly formatted name which includes things like the date and the number of passing and failing tests, and so forth. The issue was that if someone tried to access the history through FitNesse, FitNesse would toss up an error if it found any files that didn't follow its strict format. So I just made FitNesse a little more forgiving with those history files by ignoring any file that appeared corrupt, and then sending a message if someone inquired further.
On Wednesday I did a little more refactoring on my Limelight sidebar app for FitNesse. I made a video with my dad, demonstating a software kata. This is some small program which you practice writing again and again using TDD. We did created a prime number generator. What is interesting about the process of creating the PNG was that the tests would step by step lead us to a 3 line algorithm which would have been terribly difficult to come up with on the spot. I also created a quicksort algorithm using the same sort of step by step testing process in order to see if the testing process would lead to the bubble sort algorithm or if I could have arrived at the quicksort algorithm. What I discovered was that there was a leap that had to be made when testing a list of 3 unordered elements. At this leap, there were several simple solutions to make the test pass, but each solution would wind up with disparate algorithms in the long run. The diference between quicksort and bubblesort at that point in the testing was a matter of adding 1 extra variable named pivotpoint (which would eventually lead to the pivot which defines quicksort). It was pretty damn interesting.

Monday, June 1, 2009

Day 8

Today we refactored the rest of the code I wrote for the AddChildPageResponder. We also wrote all the FitNesse acceptance tests for that responder. I am now far more familiar with the FitNesse style acceptance tests and how to make the necessary fixtures to make the tests work. I also looked at the next LightHouse task #125 which has to do with the TestPageHistory files that FitNesse maintains, and making the algorithm, which uses these files, a little more forgiving towards the file names.