Tuesday, October 26, 2010

Ruby

I recently had to learn Ruby, at least, in the form of IronRuby. So far, my experience with it is good. Admittedly at first I thought that it was just another language, but after trying it out, it actually felt good working on it.

I have to point out though, the biggest misconception by the more fanatical supporters of Ruby. Ruby seems to be "agile" language. Thanks to the fantastically successful Basecamp application, Ruby has become the champion of agile software development.

Well, sorry to burst your bubble, but agile is about people over tools. Ruby is just a tool. A good tool, but it's still a tool. Improperly used, it can still result in a horrible project. Bad Ruby code is still bad code. Hell, it may even be worse than bad COBOL code.

At least most of the COBOL code out there, 5 billion or so lines, works.

Tuesday, October 5, 2010

DB or Code

I once had this feature to implement. There was a database table that had a list of user ids, gate ids and dates. The table stores this data so that it can track who passes at which gate. Users who do not use their ids at the gate will be caught.

Anyway, I could put the date calculation logic in one of two components. I could either put it in the database, as a field in a view. I could also put it in a class, as a method.

As much as I'd like to weigh in the pros and cons of both approaches, I don't think I can. I don't have enough experience as an architect, or a database designer to give proper advice. However, I do have this one bright idea.

Put it where the possibility of screwing up is less!

Because I was better at using the date calculation functions of the database than I was at Java (I hadn't discovered joda time yet) , I put it there. It worked out too!

Thursday, September 23, 2010

Morale Failure

I recently had the displeasure of witnessing a developer flee. The man just left, and didn't even bother writing down his password, just in case somebody else needed to work on his computer, or access the files he didn't save in the shared drive.

Now, the man deserves a lot of criticism for what he did. He made his current project even more of a pain than it already is. Still, one has to examine the series of situations that led to his unexpected departure.

He was a designer. He knew a little PHP. Although he's not totally inept, if PHP knowledge translated into physical strength, and he got into a fight with me, I would seriously injure the man.

Then there's the project. It was a Joomla project, involving internationalization. The languages involved were Japanese and English. Let's just say there was a problem with Joomfish. It was looking for table that wasn't in the database.

Now, while he was unprofessional as hell, expecting a newbie developer to work on a body of code as big as JoomFish is well, asking for trouble. It's the modern equivalent of asking some random mythological Greek kid (who does not have a divine parent) to strangle the hydra. Joomla can be problematic for people who actively use it, what more for somebody who has never used it before.


  if (!thisCustomer.IsRegistered)
  {
   decimal totalProduct = decimal.Zero;
   decimal TaxShippingTotal = decimal.Zero;

   //taxes for shipping
   Decimal CountryShippingTaxRate = AppLogic.GetCountryTaxRate(thisCustomer.PrimaryShippingAddress.Country, AppLogic.AppConfigUSInt("ShippingTaxClassID"));
   Decimal ZipShippingTaxRate = AppLogic.ZipTaxRatesTable.GetTaxRate(thisCustomer.PrimaryShippingAddress.Zip, AppLogic.AppConfigUSInt("ShippingTaxClassID"));
   Decimal StateShippingTaxRate = AppLogic.GetStateTaxRate(thisCustomer.PrimaryShippingAddress.State, AppLogic.AppConfigUSInt("ShippingTaxClassID"));

   foreach (CartItem ci in cart.CartItems)
   {
   Decimal StateTaxRate = AppLogic.GetStateTaxRate(thisCustomer.PrimaryShippingAddress.State, ci.TaxClassID);
   Decimal CountryTaxRate = AppLogic.GetCountryTaxRate(thisCustomer.PrimaryShippingAddress.Country, ci.TaxClassID);
   Decimal ZipTaxRate = AppLogic.ZipTaxRatesTable.GetTaxRate(thisCustomer.PrimaryShippingAddress.Zip, ci.TaxClassID);
   Decimal DIDPercent = 0.0M;
   Decimal DiscountedItemPrice = ci.Price * ci.Quantity;
   QuantityDiscount.QuantityDiscountType fixedPriceDID = QuantityDiscount.QuantityDiscountType.Percentage;

   //Handle the quantity discount
   DIDPercent = QuantityDiscount.GetQuantityDiscountTablePercentage(ci.ProductID, ci.Quantity, out fixedPriceDID);
   if (DIDPercent != 0.0M)
   {
    if (fixedPriceDID == QuantityDiscount.QuantityDiscountType.FixedAmount)
    {
    if (Currency.GetDefaultCurrency() == thisCustomer.CurrencySetting)
    {
     DiscountedItemPrice = (ci.Price - DIDPercent) * ci.Quantity;

    }
    else
    {
     DIDPercent = Decimal.Round(Currency.Convert(DIDPercent, Localization.StoreCurrency(), thisCustomer.CurrencySetting), 2, MidpointRounding.AwayFromZero);
     DiscountedItemPrice = (ci.Price - DIDPercent) * ci.Quantity;

    }
    }
    else
    {
    DiscountedItemPrice = ((100.0M - DIDPercent) / 100.0M) * (ci.Price * ci.Quantity);
    }
   }


And this isn't just for Joomla. This is for every framework out there. Yes, such frameworks can save on time, but they make the human resource costlier. The sample above is from aspdotnetstorefront. Imagine being new on the team and then having to add custom logic in that!

Wednesday, September 15, 2010

Bloated Prepackaged Software

In one of my more recent projects, the end client had a bunch of services on a web service. The end client wanted a shop that allows customers to look at the services and buy access. The middle man, our actual client, suggested aspdotnetstorefront.

The project involved multiple tiers. There was the web service, there was the payment gateway, and there was the cart itself. Everything had a price tag of sorts, so I was not able to play around as much as I could have. That alone should have sounded alarms in my head.

See, we were expecting aspdotnetstorefront to save us time. Well, we were wrong. Here's an example.

The date and time of the database server and the HTTP server should be the same. See, aspdotnetstorefront checks the date of the database server and the HTTP server to check for administrative logins. If they are different, it will log the administrator out seconds after he or she logs in.

Now, I would understand if CPanel behaved like that, because CPanel was designed to administer everything from one server, but for a shopping cart system? What, they didn't think customers might have the HTTP server on one state, and the database server on another state? That's just bad design.

Well, I could go on, but I probably won't be able to make a proper review. See, I'm not saying it sucks. Lots of people do, but lots of other people manage to make it work for them. I'll have to interview them all, and I don't want to do that.

I think aspdotnetstorefront behaves like that because it tries to do everything possible. Having lots of options is good, but it can bloat software to the point where it's impossible for consultants to just pick it up and make stuff with it. They need to consult the encyclopedic manual first.

That's why they don't make amphibious cars just yet. It's hard enough making cars safe for the road. Making it safe for lakes, rivers and oceans might turn it into this thing.



Yes, I got that picture from MobyGames. Where else will I find a picture of a level from an optional dungeon in an awesome RPG?

My point is, one has to be willing to put up with the bloat if one plans to use prepackaged software.

Monday, September 6, 2010

The File Uploader

Recently, I had to check on different PHP file uploaders. This one came up.

Directory Listing

Looking at the code, I would have to say that it needs refactoring. While there are a lot of comments, it's nowhere near as clean as it could be. It even uses the old <? PHP tag syntax.

Maybe I should write my own version. I'll make my cleaner.

Yeah, I'll think I'll do that.

Friday, August 27, 2010

Hurry up and DIE, PHP4

I like Wordpress, although I have to admit that it is not perfect. This is one such line that makes it imperfect. On strict servers, these lines cause me grief.

/**
 * PHP4 constructor
 */
function WP_Embed() {
    return $this->__construct();
}

Okay, it's important to keep things backwards compatible. Personally, I enjoy playing old games. When I read about Raymond Chen's work keeping old software compatible with new versions of windows, I can't help but feel respect for the guy.

However, this is different. In my example, a team was working to keep the OS (Windows) compatible with old software (SIMCity). Running old software in a new OS is an added value, and is less likely to introduce security errors. In the case of wordpress, the wordpress team is working to keep new software (Wordpress itself), compatible with an old runtime (PHP 4). Well, being able to run a new version of wordpress in PHP 4 is an added value too, but it becomes a major problem when security errors are left unpatched because support for PHP 4 has stopped.

As of this date, it has been two years since the last update for php 4 was released. I know there are still some applications out there that run on PHP 4. I worked on one last year! When I did, I complained about it, but it wasn't my place to tell the client, so they didn't get all the information about how gnarly PHP 4 is.

Well, not all clients can understand that using an old runtime is bad for their system. However, that does not mean that consultants shouldn't try anyway. Clients can be hardheaded, but I think that even the most technophobic Luddite will appreciate being told everything about their system. Giving clients the all the information that they need to make a decision about their investment should be the goal of every consultant.

At the very least, it's going to be their fault if stuff breaks, and there isn't an update to fix the problem. Getting clients to stop using this undead version is the fastest way to get rid of it.

Saturday, August 21, 2010

What the Hell File Naming

A long time ago, my mentor saw me putting multiple classes in a single C# file. He hit my head, and told me that I was doing something very wrong. He said that files should have just one class so it's easy to find out where something went wrong. Well, he was correct. It's easier to find an error in 1000 files with unique names, compared to scrolling down one gigantic file with the Ctrl+F hotkey.

That way way back in 2004.

Now, I find myself in the same situation. Being a freelance developer, I found myself working on a PHP framework called PHP Road. Now, before anybody googles it, I will warn everybody that it doesn't exist by itself. It apparently became part of the Lemonstand shopping cart platform.

I don't really have anything against it, but somebody who used the PHP Road framework named their files this way.

signupp.php
singuppt.php
signupt.php

Well, apparently, each file did something unique, and each file was important. Care to guess what? Sure, they all had something to do with signing up, but aside from that, what do they do?

Well, it's not easy to guess. Also, guessing takes time. Writing get_included_files() and looking at the source takes time.

I just had to add * REQUIRED to a few input boxes, and I had to check which files were included with PHP code. It shouldn't be that way. Well, that means that files need to be renamed.

It's okay to put some secret code in your file names, but at least make sure it's easy to decipher. Remember, somebody else might be working the code in the future. They also might be strong enough to curb stomp people.