There's been a lot said about using Java in Clojure code. However, the circumstance may arise when you need to write Clojure code to run in Java. It is a little more roundabout and a little less clean, but it is possible. I'll be going over the gen class option available for the interop to take place.
Let's look at a simple example.
What we have available now is a package test with class Speak. We can instantiate an instance of speak. We can call hello("my name") on our instance and I'm sure you can guess what happens. One caveat to notice is that we must prepend our function names with '-' and we must declare our function's in the top gen-class block. We can then get a little fancier. Here's the same example with a global variable.
Now we can set the name on our instance before we call the speak function. Notice the :state declaration in the top block. We can only have one state variable, so use it wisely. Here, I intend to only use it to hold the name to say hello to. A good pattern is to use the state option to store a map of all the variables one might need since we are limited to one state variable.
Monday, January 30, 2012
Day In Review
I was on the Hosemonster project again today. We were able to finish the graphing framework and completed fitting curves to a set of data points. It felt good to have a finished product that we will then plug into the application.
The second half of the day was dedicated to refactoring. The new, edit, and view pages for our models were all basic and contained many repeating portions. In order to stay DRY and to help keep the system simple we started refactoring to collapse the new, edit, and view pages of our models into one page that then tweaks itself dependent on a parameter corresponding to a action which is passed down. I liked this refactoring since it meant we had a pattern to follow as more and more models are introduced to the system.
Another refactoring we had was to collapse the Interactor's update and create functions into one save function. Again, these two functions contained a lot of the same lines and in order to stay DRY we collapsed them upon each other. This change was fairly simple since we need to create if the model does not have an id and update if it does. This was the only different in the two functions.
The second half of the day was dedicated to refactoring. The new, edit, and view pages for our models were all basic and contained many repeating portions. In order to stay DRY and to help keep the system simple we started refactoring to collapse the new, edit, and view pages of our models into one page that then tweaks itself dependent on a parameter corresponding to a action which is passed down. I liked this refactoring since it meant we had a pattern to follow as more and more models are introduced to the system.
Another refactoring we had was to collapse the Interactor's update and create functions into one save function. Again, these two functions contained a lot of the same lines and in order to stay DRY we collapsed them upon each other. This change was fairly simple since we need to create if the model does not have an id and update if it does. This was the only different in the two functions.
Sunday, January 29, 2012
Using External Dependencies For Specific Use Cases
I am going to recount a recent learning experience I encountered while working on a Rails Project. The ideas I came away with are not Rails specific, however, and are applicable to all software. The learning experienced involved me leaning on third party libraries. This lean later turned into a fall and I realized that third party libraries are to be used for a specific case and only for that case. Dependencies are for what you yourself can not do on your own in a reasonable time period. I learned that we must be careful with the libraries we make use of since their behavior is outside of our control even if we believe to have them pinned down in test.
ActionMailer is a gem most Rails programmers are familiar with. For a story I was completing I needed to email notifications and I knew I was not going to implement a mailing system in a reasonable time period. I then introduced ActionMailer and wrapped the functionality. I had the system under test and I felt pretty confident with what I was using ActionMailer for. My tests were green. The code then went live and I quickly learned that I had made a big mistake. I started receiving ActionMailer generated exceptions. What had happend? I was green when I had committed!
Well, I was green and it was a false positive. ActionMailer has a different set of rules for test and for production. In my case I leaned on ActionMailer and got burnt. I took an array of email addresses and joined them by commas to produce a string to be used as the recipient list of my generated mail. When there were no array entries this produced an empty string. When I sent an empty string to ActionMailer in test it essentially disregards it. Great, I thought, ActionMailer handles my empty email list case! WRONG!
In production an empty string as a recipient list with ActionMailer produces an exception. When the operation is fairly common it produces a lot of exceptions. It was my fault for not narrowing my usage of ActionMailer to the specific cases in which it was actually needed. I instead used it for my empty string case. The moral of story, external dependencies are for specific use cases and nothing more.
ActionMailer is a gem most Rails programmers are familiar with. For a story I was completing I needed to email notifications and I knew I was not going to implement a mailing system in a reasonable time period. I then introduced ActionMailer and wrapped the functionality. I had the system under test and I felt pretty confident with what I was using ActionMailer for. My tests were green. The code then went live and I quickly learned that I had made a big mistake. I started receiving ActionMailer generated exceptions. What had happend? I was green when I had committed!
Well, I was green and it was a false positive. ActionMailer has a different set of rules for test and for production. In my case I leaned on ActionMailer and got burnt. I took an array of email addresses and joined them by commas to produce a string to be used as the recipient list of my generated mail. When there were no array entries this produced an empty string. When I sent an empty string to ActionMailer in test it essentially disregards it. Great, I thought, ActionMailer handles my empty email list case! WRONG!
In production an empty string as a recipient list with ActionMailer produces an exception. When the operation is fairly common it produces a lot of exceptions. It was my fault for not narrowing my usage of ActionMailer to the specific cases in which it was actually needed. I instead used it for my empty string case. The moral of story, external dependencies are for specific use cases and nothing more.
Friday, January 27, 2012
Day In Review
Yesterday, I worked on Artisan for the entire day. I paired with Myles for the whole day, since Myles is new to Artisan and unfamiliar with the code base. This was a good experience for the both of us, since Myles was introduced to the code base, and for me since I had to articulate the components of the system. It's always a good idea to articulate, at a high level, what each component of a system does. It forces you to think about your system at a high level and the missing abstractions seem to bubble up when you talk about a system in this way.
Specifically, Myles and I were able to have the iteration new/edit form working as a modal. This keeps the workflow contained on the storyboard page, which was the goal of our work. The changes actually pointed us towards a missing abstraction and implementing the abstraction for iteration presentation felt good. It made the change feel painless and allowed the existing code to stay largely in tact.
The second half of the day we revisited the storyboard column sorting bug. We fixed the bug, however we introduced redundant behavior (sorting when it is unnecessary) and are having trouble cutting this behavior out.
Specifically, Myles and I were able to have the iteration new/edit form working as a modal. This keeps the workflow contained on the storyboard page, which was the goal of our work. The changes actually pointed us towards a missing abstraction and implementing the abstraction for iteration presentation felt good. It made the change feel painless and allowed the existing code to stay largely in tact.
The second half of the day we revisited the storyboard column sorting bug. We fixed the bug, however we introduced redundant behavior (sorting when it is unnecessary) and are having trouble cutting this behavior out.
Wednesday, January 25, 2012
Day In Review
I started the day off working on the storyboard sorting bug. This is a tricky bug to get rid of because of the way the behavior works. Sortable, the jquery-ui widget, allows callback functions for an update in a single column and a receive event from another column. What is happening is a column drag for a single story will trigger an update event in the original column, an update event in the new column, and a receive event in the new column. This is fine and dandy, however, we trigger a frivolous update event in the original column and it's wasteful. I've been trying to find a way to avoid the update event, however, it's hard to define the behavior in such a way to do the event in one column and not in the other. This process is ongoing and I plan on revisiting it tomorrow.
The second half of the day I dedicated to hosemonster and the graphing functionality. I have been spiking out ways to generate curve fitting functions given a set of data points. In the morning I, out of curiosity, entered a sin function and got a jagged heart-monitor looking output. I hypothesized that calculating more points would smooth the line and it did, I had a continuous sin function. This is when I got really excited, what a cool thing to have happen.
The next problem was figuring out how to calculate the form fitting function. The solution involves creating an arbitrary length polynomial whose degree is determined by the number of points supplied. To create the polynomial involves the use of Gaussian Elimination to solve for the coefficients of the function. Wai Lee and I were able to get a polynomial class under test, use the test data provided, plug in the polynomial generator, and create form fitting curves for data points.
The second half of the day I dedicated to hosemonster and the graphing functionality. I have been spiking out ways to generate curve fitting functions given a set of data points. In the morning I, out of curiosity, entered a sin function and got a jagged heart-monitor looking output. I hypothesized that calculating more points would smooth the line and it did, I had a continuous sin function. This is when I got really excited, what a cool thing to have happen.
The next problem was figuring out how to calculate the form fitting function. The solution involves creating an arbitrary length polynomial whose degree is determined by the number of points supplied. To create the polynomial involves the use of Gaussian Elimination to solve for the coefficients of the function. Wai Lee and I were able to get a polynomial class under test, use the test data provided, plug in the polynomial generator, and create form fitting curves for data points.
Tuesday, January 24, 2012
Clojure Map to Ruby Hash Kata
I performed the Clojure Map to Ruby Hash Kata and have the video available. Unfortunately, I wasn't able to include audio to introduce the kata and walk through some of the steps. That being said, you should be able to follow along. Enjoy.
Saturday, January 21, 2012
Day In Review
After completing some stories for Artisan, I needed to go back and review the work I had done. Unfortunately, there were some items that needed work. This was helpful to review, since it's part of the learning process. One big mistake I had made is probably a common one among Rails developers, I had missed a key abstraction and placed behavioral code in my controller.
I had gone from the highest level, an incoming HTTP request to the lowest level, talking to the database, all in one controller method. Instead of doing this, I pulled the behavioral code into an interactor that mapped to an existing model. This turned out to be great for the codebase because when the interactor first came together I began to notice responsibilities that lived hodge-podge in the system that ought to be shifted to this new abstraction. It was like taking a weight off the shoulders of many system components and helped reduce code duplication, which is always a win.
I had gone from the highest level, an incoming HTTP request to the lowest level, talking to the database, all in one controller method. Instead of doing this, I pulled the behavioral code into an interactor that mapped to an existing model. This turned out to be great for the codebase because when the interactor first came together I began to notice responsibilities that lived hodge-podge in the system that ought to be shifted to this new abstraction. It was like taking a weight off the shoulders of many system components and helped reduce code duplication, which is always a win.
Subscribe to:
Posts (Atom)