Archive for April, 2008

Read more books!

Posted on April 25th, 2008 in Books, Opinion | Comments

If there’s one positive thing I can take out of having to ride the subway to work for one hour each way every single day, it’s that I’ve been able to catch up on a lot of reading. I love to read a whole lot, particularly about technology. So lately I’ve been able to finish a couple of books I had around, plus I’ve been able to afford more books to read, so I’ve been buying more. While I haven’t read a library’s worth of books, I think I’ve read more than the average software developer has read. I would go into a long discussion about that fact, but maybe another day.

With a myriad of books out there, it’s difficult to know which ones to read. I first got inspired by Jeff Atwood’s Recommended Reading For Developers list. Since then I’ve purchased and read many of the books Jeff recommends, which are still pretty relevant and really good reads.

So I decided to dedicate some time to write some mini-reviews about the books I’ve read, in case someone wants an honest opinion on them from my perspective. I’ve already written about a couple of books before (like the upcoming Advanced Rails Recipes book, and my not-so-popular opinion about The Pickaxe Book), so I hope to expand on that.

Also, I added a nifty text widget on my sidebar which I will update constantly on which books I’m currently reading and into, with a link to Amazon (no referral link!) for more information. I hope you all find it interesting to see where I’m focusing now.

Any suggestions on recommended reading for a software developer like me? While I like programming-specific books, I would really like to get into more books that focus not on one single piece of technology, but as a whole. Any recommendations will definitely be appreciated.

Professional Dependencies

Posted on April 19th, 2008 in Opinion | Comments

When I left my previous job to come to New York City, I made sure to clean up as much as possible, leave as much documented as possible, and clear up things with those who would be replacing my normal duties. I not only did this because it’s the professional thing to do, I also didn’t want to screw over my former bosses, much less my co-workers, since I did want to be able to maintain my friendship with many of them. Many times I saw people leave abruptly, which led to slight disorganization among the ranks for a while.

Since I only had one week to do this before I finished my non-work duties (moving, packing, saying goodbyes, etc.), and let’s face it, my mind wasn’t at my current job at the time due to the excitement of going to New York, there was bound to be something missing. So I kept the doors open with my former bosses and co-workers, assuring them that if they needed anything that I could help them with, to let me know so I can try to help them any way possible.

While I haven’t been called a lot by my former co-workers, I still get calls from time to time from them asking how to do a certain thing, or clearing up something I didn’t explain too well before I left. I also received an E-Mail from my former boss, asking if I could do some maintenance programming tasks. I has accepted, but since they didn’t answer me back in time if they accepted my terms (or rather, how much I would charge them for my time spent on this), I moved on to other projects and had to decline.

Now, I don’t mind helping out my friends as much as I can. But the problem is that a lot of the times I can’t help for whatever reason. Maybe it’s due to me having much work now like the aforementioned projects getting in the way, or I because I simply don’t remember well something in particular. Whenever this happens, I feel like I’m letting others down. Chalk that up to the way I am. Whether it’s a blessing or a curse, I’m still not sure yet.

Not to sound evil or anything, but although I want to help, I’m not under any obligation to do so anymore. I also think about it this way: When I arrived there, I had absolutely no help at all from the previous person doing the tasks I did, because that person wasn’t there anymore (from what I heard, he left abruptly on bad terms with the company). So I had to do things on my own. There were things I had to ask about, of course. But most of the things I had to learn for myself, like the programming, what type of servers / active scripts running, etc. This wasn’t by choice, it’s because there was no documentation left behind, and the bosses had no clue what the other person did.

So I question myself, where does the ‘professionalism’ end? Should it have ended once I collected my final paycheck and walked out the door? Or is it fair to have a short ‘grace period’? It puts me in a difficult position a lot of the times. I don’t want to let my former co-workers (or at least the good ones) down during their times of need, but I don’t want to be a crutch for them for too long. I think it’s time for them to start rehab and start walking on their own again soon.

Fix my mistakes. Just don’t do it yourself.

Posted on April 3rd, 2008 in Programming | Comments

When I arrived at my current job, most of the functionality from the Rails application I’m working on was already done by developers before me. There were still some loose ends to tighten, but almost everything was ‘working’. I say ‘working’ in between single quotes, because while the application was certainly working, it really only worked if everything was done in a seemingly exact pattern. Do something different from the pattern, and something will break. Like “Click here and fill in this, in this exact order, and put your cursor there, or the app will give an error.

I understand why this was done this way. I usually code this way too: after deciding what I’m going to do, I whip up a very crude version of what I want to do, then I take care of some loose ends that could be made better. But there are some things I do along the way to avoid having too many loose ends when I finish writing my basic functionality.

Most of us have heard the phrase “premature optimization is the root of all evil” by Donald Knuth. While this is true, I believe that we should think from the beginning about optimization before writing code. Your algorithm or pseudocode should be as optimized as possible from the start to avoid these things. If you think through your problem well enough, too much optimization won’t be needed.

With web development and frameworks such as Ruby On Rails, it’s easy to forget these things. A lot of the times people just sit in front of their computers and code away, hacking up whatever’s on their mind without thinking it through. I admit I’ve been guilty of this behavior before. But with age comes experience, and I’ve learned a lot since then.

Anyway, back to my current code. Apparently the developers working on it before just sat down and wrote a lot of code without thinking about such basic things, like error-handling. It’s not like they didn’t have time to do it. My workplace isn’t a stressful place, my bosses are way nice, and while we do have deadlines, it’s not like we have someone on our backs constantly nagging that we have impending deadlines. Since those original developers don’t work here anymore, I can’t ask them why they coded like this, so I have to just deal with it the best that I can.

I created a document in our company’s Wiki with some coding tips that came off the top of my mind, so that hopefully any new hires can read it and follow them. Even if they know these things, it should serve as a reminder to follow these basic guidelines. By no means it’s a complete document, but these are the most common mistakes I’ve encountered.


Always handle errors gracefully

Try to never show the user an error page. If something went wrong, show a message letting the user know what went wrong, preferibly a `flash[:notice]` or `flash[:error]` message, which will appear at the top of the page, and send them somewhere where they can either try again or get more information.

Bad Example (If the item for some reason doesn’t exist, or a curious user changes the ID in the URL, it will show an not-so-helpful error page):

def offer_for_want
  @have_item = HaveItem.find(params[:id])
end

Good Example:

def offer_for_want
  begin
    @have_item = HaveItem.find(params[:id])
  rescue ActiveRecord::RecordNotFound
    flash[:error] = "Some error"
    redirect_to :somewhere
  end
end

Use descriptive variables

Although using shorter variables keeps the functionality the same as using longer variable names, using descriptive variable names and conventions will help other developers understand how an action or function works more easily. Also, using normal Ruby and Rails variable naming conventions helps others get up to speed on the scope of the variable.

Bad Example (Notice the use of two- and three-letter variables, which are not descriptive to a developer who’s just working on this portion of the code):

def update_relationship(hi, wi, opt, modify_opt = nil)
  _have_want = {}
  _have_want['HaveId'] = hi
  _have_want['WantId'] = wi
  _have_want['Delete_add'] = opt
  [...]
end

Good Example:

def update_relationship(have_item, want_item, update_type, modify_option = nil)
  have_want_hash = {}
  have_want_hash['HaveId'] = have_item
  have_want_hash['WantId'] = want_item
  have_want_hash['Delete_add'] = update_type
  [...]
end

Comment your code!

All controller actions and model functions should be commented before the action or function, giving a brief description on how it works. Also, if the code is not self-explanatory or is done in a non-conventional way, a brief explanation should be included as well to let other developers know why the code was written that way, or how it works. This will also be useful for generating code documentation with RDoc

Bad Example (No comments anywhere):

def rate( _user )
  @current_user = _user

  transaction do
    user_tv = view_for(_user)
    user_tv.next_step = View::CF[:next_step][:nothing]
    user_tv.status_for_user = View::CF[:status_for_user][:nothing]
    user_tv.rated = true
    user_tv.save!
    self.rate!
    self.reload
    return ended?
  end
end

Good Example:

# Action to rate a user after an action has been accepted, completed and shipped.
# Only the people involved in the action are permitted to rate each other.
def rate(_user)
  @current_user = _user
  # Reloading the object attributes from the database, in case something was changed during the rating process.
  self.reload

  transaction do
    user_tv = view_for(_user)
    # Sets the next step of the action to 'nothing' for both users involved,
    # indicating that the entire process is complete.
    user_tv.next_step = View::CF[:next_step][:nothing]
    user_tv.status_for_user = View::CF[:status_for_user][:nothing]
    # Set a flag to mark the user's action as rated, so that multiple feedback can't be given
    user_tv.rated = true
    user_tv.save!
    self.rate!
    self.reload
    return ended?
  end
end

Properly substitute variables from MySQL queries for security purposes

Any query to the database where the user can enter the parameters (for example, a user enters terms in a search field) can potentially allow a malicious user to run a harmful query against the database, like dropping tables. These user-entered parameters need to be protected from these types of problems.

Bad Example (In this example, a user can enter something like ; DROP TABLE users as their search parameters, deleting the users table):

@item = HaveItem.find(:all, :conditions => "title = #{params[:search]}")

Good Examples (All of these samples do the same thing, except Rails sanitizes the parameters to make sure no arbitrary SQL code is run):

@item = HaveItem.find_by_title(params[:search])
@item = HaveItem.find(:all, :conditions => [:title => params[:search]])
@item = HaveItem.find(:all, :conditions => ["title = ?", params[:search]])

Sanitize any user input before rendering it in the view

Anything the user enters should be treated as potentially hazardous. Any unsanitized output can be vulnerable to Cross-Site Scripting. Any fields in the view that show information entered by a user should be sanitized. It's as simple as adding the h function before the string.

Bad Example (Anything the user enters in the database, when shown later in a view, can execute arbitrary code):

<%= @item.description %>

Good Example:

<%= h @item.description %>

Keep presentation and business logic separate

Thanks to the MVC paradigm, Rails makes it easy for any new developer to get find presentation code or business logic, but only if they're stored in the correct places. Any business logic (such as declaring variables, conditionals, etc.) should be kept in the controller or model and not inside the views. Likewise, all presentation code (such as rendering page updates via AJAX) should be done in either regular view files or RJS templates, not in the controller.

Bad Example (Variables being declared inside the view):

<% result ||= match_result %>
<% size ||= :small %>
<% match = HaveItem.find(result.incoming_item) %>
[...]

Good Examples (In both cases, this leaves the view with just HTML and some Ruby/Rails code inside):

Declare the variables in the controller action instead of the view

def action
  @result = Engine.results
  @match = HaveItem.find(@result.incoming_item)
  [...]
end

In case the view is a partial, declare the variables when calling the partial

<%= render :partial "match_results", :locals { :result => @result, :match => @match } %>

Of course, I'm not an expert on these things. Most of them are probably common sense to most people, but you'd be surprised how often these mistakes are actually made. I'm sure you all have seen these, or probably worse. Does anyone have any other tips that can be added? Feel free to leave a comment.