Grails Tip # 3: refresh()


refresh() is not an undo()

In your application, you may come across a time when you need to revert or undo
changes done on a domain object. discard() comes to mind, but there may be instances where
that is not an option. refresh() also looks like an tantalizing option, but there is one critical
feature of refresh() you need to be aware:

If you have a trasient object associated to the domain object you are calling
refresh() on, you will get a
org.hibernate.AssertionFailure: null identifier
error.

Consider the following example to see why you might need to use refresh
and what you have to watch out for.

The Domain

Consider the following domain, a Car has several models
(for each year) and most of the details of a “car” is
in the model domain. There are a few description fields on
the Car domain object however.

The Code

The Car domain object:

		package com.ex
			
		class Car {
			String name
			String description
			static hasMany = [models:Model]
		}
	

The Model domain object:

		package com.ex
			
		class Model {
			String name
			int year
			Engine engine
			. (other properties)
			.
			.
			static belongsTo = [car:Car]
		}
	

Users are able to modify car details and model details at the same time.
They can also add new models to the car as well. All changes to the
Car (and it’s models) must be atomic. That is, all changes
must be committed as one transaction. Lets take a
look of the UI:

<%= image_tag "articles/grailstip3/flow.png" %>

When the user decides to change their changes,
they exectue the saveChanges action on CarController.

Because of the belongsTo relationship on Models to Cars, we
can save any user changes to Car model and it’s models by
calling save() on the Car object.

		package com.ex
			
		class CarController {
			def saveChanges = {
				.
				.
				.
				// save car under edit
				car.save(failOnError:true)
				.
				.
				.
			}
		}
	

The Problem

Due to a requirement, the users have the ability
to revert changes on a particular Model, but
still save their changes on the Car.

		package com.ex
			
		class CarController {
			def saveChanges = {
				.
				.
				.
				// model to revert
				if (some condition)
					// rever model
				.
				.
				.
				// save car under edit
				car.save(failOnError:true)
				.
				.
				.
			}
		}
	

One might think we can call discard(), but this will
not work in this situation because further down
the code, we end up calling save on Model’s parent,
the Car. Even if we discard a particular Model of a Car,
it will still be saved when Car is saved due to the
cascade behaviour brought on by belongsTo relationship.

We also are unable to change the cascade settings between
Car and Model. In this particular instance, we could
prevent cascade on save, but in other cases, we do need it.

The other other option is to call refresh() on the Model
being reverted. And we do this.

		package com.ex
			
		class CarController {
			def saveChanges = {
				.
				.
				.
				// model to revert
				if (some condition)
					model.refresh()
				.
				.
				.
				// save car under edit
				car.save(failOnError:true)
				.
				.
				.
			}
		}
	

Done right? well, not quite. Under some use cases, we
discover this exception being thrown:
org.hibernate.AssertionFailure: null identifier

The error only occurs when new objects are associated to
a Model. For example, if the user adds a new Engine to
the reverted Model. What’s going on?

When you call refresh on the Model, Hibernate will traverse
though the object’s object graph and overwrite its data
with what is in the database.

If there is a transient object associated to the Model,
Hibernate will not find an id associated with this entity
and thus will throw a null identifier assertion failure.

The Solution

To be able to use the refresh() method, you must break all
associations with transient objects in the graph in the
current Hibernate session.

This can be done by calling clear() on any hasMany associations
and re-assigning any variables assigned to transient objects to null.

		package com.ex
			
		class CarController {
			def saveChanges = {
				.
				.
				.
				// model to revert
				if (some condition){
					model.engine = null
					model.tries.clear()
					model.refresh()
				}
				.
				.
				.
				// save car under edit
				car.save(failOnError:true)
				.
				.
				.
			}
		}
	

Many people believe this to be hackish — a workaround
and, well, though this might be true, Hibernate’s API is being
used correctly and instances such as this, transient objects
are known and can be properly be removed from the session.

Though Grails itself does not offer an “undo” method, I
would argue the solution above deals with the problem at hand
using the API as it was designed. However, one of the reasons
I’ve posted this is to see if there are any others who have faced
similar problems have found a different way of solving it.

GO Mobile

GO Transit just released their official mobile app and it is long over due. Better yet, its free (much to the demise of the the 3rd party apps on iTunes).

The menu is clean and simple – the way it should be. It has basic functionality such as viewing and favoriting train/bus schedules, being notified of departures, and viewing the Union Station departure board. Filtering of the departure board was a nice touch that no other 3rd party app seems to have done yet.

<%= image_tag "articles/gotransit/screenshot1.jpg", :class=>‘image-right’ %>

The app is very basic, so I expect it to work perfectly. It does not. Sometimes, just minutes into using the app, the main menu icons stopped working. You click on the icon, the icon reacts, but nothing happens. Sometimes, the expected feature opens after a while, but other times, nothing happens and I’m required to close the app and restart it. This is totally unacceptable. …even if the app was built by students.

I’m greatly disappointed that there is no way to view GO Transit train/bus statuses from the app. For most users, being notified of delays is the primary reason they want a mobile app!

The launch of the official app pretty much kills off all the $.99 3rd-party applications out there. These apps do not have access to any GO transit API so they screen scrape the content off the GO transit webpage and repackage it into a little apps. Because of this, whenever GO transit changes their webpage styling, the apps stop working. Often, it is no longer worthwhile for these companies to push out an update so user simply have to go off looking for a substitute app. The best apps can usually push out updates quickly, but even then; their app is not working for a day or two.

This has left riders unhappy with GO transit apps. They’ve gotten used to knowing that their app, which they paid for, will eventually stop working. This means you can never fully trust what the app is saying. If the app says there are no delays, is this because there are actually no delays or because the app cannot parse the website contents? Users end up double checking the official website.

I also developed a GO Transit app, and though I did not release it to the app store, I did try it for a bit. Like others, it scrapped the data from the main GO transit website. My app’s main purpose was to communicate delays on a user’s particular train.

Though I could easily parse the entire status section and place it on my app (which many 3rd party apps do), I wanted the ability to parse delays by train-line so users could filter it. However, every few weeks, the app would stop showing delays. I suspect that the status section does not use any template, but rather, the entire status section is just free from text-field (in addition, the entire status section is surrounded by <pre> tags to further prove my suspicion). In the end, I couldn’t find a reasonable delimiter between statuses on different lines and scrapped the app.

The image to the left is a screenshot of the status section on the GO transit website. Trying to parse it by line proved difficult because no standard template was used. In this particular example, notice how the first delay effects one train-line and the 2nd delay effects two train-lines even though it is displayed in the same fashion as the one-train line status. This inconsistent use of headers is one example of the difficulties of parsing this page.

Because of this, I’m pleased that there is an app that is based on some official API. Though, I do not really expect myself to use this app too much do the lack of status updates, I think the general public will be please to have a GO Transit app they can use with confidence.

Buyer Beware!

Groupon and other online-deal sites have been popping up all over the place recently. Like my friends, I’ve also jumped on the band wagon buying coupons and trying out restaurants, etc. Over the past months however, I’ve started hearing grumblings with these coupon sites. I thought I’d collect some of the major issues and post them here. Buyer beware!

Check the Menu Prices

Look at the prices of you menu. Even though the face value coupon may say $20 for $40 (a savings of 50%), it does not necessary mean you will be saving 50% at the end of your meal.

Consider the following example:

Say the meal costs $25 each and you go with your wife. The final bill is $50 and after the coupon, you pay an additional $10 (for simplicity sake, we won’t consider taxes or tips). The total amount you paid is $30 and received $50 of savings. This is only a 33% saving, down from the initial face value of 50%.

Going with friends?

Consider how many people you divide up the coupon. Lets take a look another example: The coupon is the same $20 for $40 and you split it among four friends. Each person pays $5 each. Say the meal costs $15 per person, so the final bill is $60 and everyone pays $5 in addition per person. The final amount each person pays is 10, which turns out to only a 33% savings. This is pretty good, but not the 50% that we began with.

Stated Terms and Conditions

Take a good look at the terms and conditions. Most restaurants allow dine-in only and only to be used during dinner. Others put restrictions on what can be ordered or even go as far as giving users a different “coupon” menu. Many times, these menu’s have been priced to make sure you end up paying additional amounts after the coupon’s discounts.

Unstated Terms and Conditions

Unfortunately, many merchants also enforce unstated terms and conditions that are not originally posted on the deal website. In these cases, your best bet is to try and ask for a refund from the deal site.

Sub-Premium Product

Beware that many theaters will seat coupon users in less-desired seats (such as front rows or seats with obscured views).

Out-of-Stock

Product based companies can state that a particular coupon product is out of stock. Buyers then wait months for their product until the coupon is expired, at which point, they are now left in limbo with the deal site and the retailer.

Businesses are often legitimately overwhelmed due huge volume of buyers redeeming the coupon. This causes crowed restaurants, long lines-ups, and legitimately out-of-stock on coupon items.

Mind the Expiry Date

Some restaurants, salons, and service businesses require you to make reservations and state that you are a coupon user. This is used by unscrupulous businesses to deny you services (stating excuses such as full booking) to try and expire the coupon on you.

Printouts Required

Many sites require you to have a physical printout of the coupon. In the age of smart phones, this is incredibly archaic and the printout isn’t really required since businesses need to keep a record of coupon purchases themselves.

Buyer Beware

Remember the old adage, “If it seems too good to be true, it probably is”.

iBomber

In iBomber, you fly a WWII bomber dropping bombs on targets. Simple as that. It is a fun and addticve game. Each mission gives you specific goals such as destroying buildings, ships, or defending your base from the enemy. In addition, it also challenges you to acheving medals on each level. You can get up to 4 medals: <%= image_tag "articles/ibomber/medals.png" %>

You have some control over the speed of the aircraft by gently tilting the iphone forward to go faster backward to go slower. Titling the phone from side to side moves the play right or left. The game has pretty tight controls and is very responsive to minor tilting of the phone.

The regular bombs don’t drop straight down but take into consideration the speed of the aircraft. The faster you’re going, the more momentum will carry the bomb forward. Therefore you have to do some careful estimation before dropping the bomb. After some practice, you’ll know how far before the target you need to drop the bomb depending on the speed of the bomber.

Sometimes when you blow up targets you items will appear. When you click on the items you get either health power-ups or special bombs. As always, powerups always come up in abundance when you don’t need them.

The rocket bombs are good for targeting moving ships or when you are bombing at high speed (such as attacking heavily defended targets). The blockbuster is well, good for nothing. It is OK for bombing buildings. The grandslam is good for blowing up areas with lots of close buildings or large clusters of anti-aircraft guns. On land, even if you don’t hit your target, the explosion will take out surrounding structures. On water, you need to be very precise because if you miss, there will be no damage to surrounding areas.

Click to see my accomplishments in iBomber!

Standard Missions

Mission Pack One

White Tuna?

A staple at most All You Can Eat Japanese(AYCEJ) restaurants, a lot of people do not know that “white tuna” isn’t tuna at all!

Most “white tuna” served at restaurants is actually a fish called “Escolar”. It is rich tasting, oily, meaty fish. It is a mild flavorful with a smooth buttery taste. It is truly a delicious fish, but with one major drawback…

The fish is poisonous. Unable to digest fatty acids in the food it consumes, Escolar accumulates a high concentration of oil in its flesh. When this oil is consumed many people suffer digestive including cramps, diarrhea, headaches, and oily discharge.

As a result, there has been a lot of controversy over this fish. Italy and Japan have banned the sale of Escolar for human consumption and other countries, including Canada, have put warnings regarding the adverse effects of consuming this fish.

Some countries have made it a strong point forcing restaurants to clearly identify Escolar from “white tuna” but here in Canada, this either isn’t the case or not enforced as I see “white tuna” on the menus of restaurants all over the place.

Personally, I’ve never had any side effects (yet) from eating Escolar at sushi restaurants. Knowing what I know now, I have reduced the amount of “white tuna” I eat at any given sitting. The Internet has recommends eating no more than 6 ounces at one time.

Adding to the confusion, there is actually a white tuna. In North America, white tuna typically refers to Albacore tuna, a light fleshed mild tuna which is often used as canned tuna. In the United States, only Albacore tuna may be referred as “white tuna”.

Though many AYCE restaurants serve Escolar, some do serve Albacore tuna. Escolar is typically bright white, but as fish ages, the flesh becomes darker. It has a very oily flesh and creamy buttery flavor. Albacore has a pick
color, and though milder then their bigger cousins (blue fin and yellow fin), it has a bolder, fishier taste then Escolar.

Compounding the misidentification, many fish retailers purposefully mislabel Escolar as Sea Bass, Halibut, and Albacore. When prepared as fillets, Escolar can look very similar as those more expensive species. Your best guard is to buy fish from reputable fishmongers.

So there you have it, “white tuna” is no tuna at all. You can sometimes tell the difference, but I’ve seen older Escolar flesh look very similar to Albacore –so it can be difficult. As mentioned before, I still eat “white tuna” at restaurants, but in very moderate amounts. The next time you are at your favorite AYCE sushi bar, just remember that you may not getting what you expect.

Additional Links

  • I found this blog entry that does a comparsion between Escoloar and Albacore and has good picture references.

    Escolar vs Albacore

Grails Tip # 2: Hibernate Session


A different object with the same identifier value was already associated with the session

The Domain

Say we are managing a store with shelves full of items. Whenever an
item on a shelf is empty, we need to create a restock order form.
Lets represent this as 3 domain classes: Shelf, Item, RestockOrder

The Code

A restock order is created when an existing item on a shelf runs out,
BUT, a order is also created for brand new items. The client has requested
that when creating new items, restock orders can also be created.

The Shelf domain object:

			package com.ex
			
			class Shelf {
				int number
				static hasMany = [items:Item, restockOrders:RestockOrder]
			}
		

The Item domain object:

			package com.ex
			
			class Item {
				String name
				String description
				double price
			}
		

The RestockOrder domain object:

			package com.ex
			
			Item item
			static belongsTo =[shelf:Shelf]
			static mapping = {
				item cascade:'save-update'
			}	
		

The editing of a Shelf takes place over several pages, similar
to a web-flow, thus the Shelf object is created and stored in
the HTTP session (therefore detached from the Hibernate session).
On subsequent HTTP requests, the user adds more data to this
object in the session. Finally, after filling out the last
page, we are able to persist the domain object to the session.

On the last page, if the user made important changes to Shelf,
the user is showing a confirmation page comparing the old values
with the current one. This was done by simply populating
the model with the current version in the session and also
re-loading the same model from the database. If the user did not
make any changes that require confirmation, we save right away.

<%= image_tag "articles/grailstip2/flow.png" %>
In ShelfController:
The index() method loads the required shelf and puts it into the
HTTP session, detaching it from Hibernate session.

		    def index = {	
				Shelf s = Shelf.findByNumber(1)
				session.putValue("shelf", s)
			}
		

The save controller

			def save = {
				// get from sesion
				def shelfUnderEdit = session.getAt("shelf")
				
				// bind update
				shelfUnderEdit.parameters = params
				
				Shelf originalShelf = Shelf.findByNumber(1)
				
				// user hasn't confirmed, might have to show confirmation page.
				if (showConfirmation(shelf, original) && params.noComfirmation){
					render("showUpdates", model:[shelfUnderEdit:shelfUnderEdit, originalShelf:originalShelf])
					return
				}
				
				// save
				shelfUnderEdit.save(failOnError:true)
			}
		

However, when we try to run the code above, we get the
“A different object with the same identifier value was already associated with the session”
error.

The Problem

Hibernate tries to keep one instance of a persisted object
in the session at one time. In this example, for any “Shelf”
in the database, Hibernate tries to make sure only 1 instance
of a Shelf object represents that Shelf.

The problem resides in the save(), there is the original Shelf we
detached and put into the HTTP session. When we try to re-attach
it, Hibernate finds that another one is found in the session.
This second object was created when we loaded the same Shelf from
the database to do our comparison. Two objects representing the
same Shelf now resides in the session and much to the dislike to
Hibernate.

The Solution

Though there are several ways to solve this problem, the method
we took was to discard the re-load Shelf object that was used
for the comparison. Therefore, when save() is called on the
Shelf that is under edit, it is reattached to the Hibernate
session and is the only object representing that particular
Shelf in the database. Thus Hibernate is able to persist the
changes without error.

			def save = {
				// get from sesion
				def shelfUnderEdit = session.getAt("shelf")
				
				// bind update
				shelfUnderEdit.parameters = params
				
				Shelf originalShelf = Shelf.findByNumber(1)
				
				// user hasn't confirmed, might have to show confirmation page.
				if (showConfirmation(shelf, original) && params.noComfirmation){
					render("showUpdates", model:[shelfUnderEdit:shelfUnderEdit, originalShelf:originalShelf])
					return
				}
				
				originalShelf.discard()
				
				// save
				shelfUnderEdit.save(failOnError:true)
			}
		

References

Grails Tip # 1: Transient Values


Not Null Property References A Null Or Transient Value

Introduction

I recently started working on Grails applications and as expected, I’ve seen the same problems come up over and over again. So, I thought it would be a good idea to accumulate the common (and some uncommon) problems we”ve seen and write about them. The domain objects and code used in the posts are purpose built examples simulating the actual problems that we’ve seen developing with Grails.

The goal is not to explain the full underlying details of GORM and Hibernate, but instead, show examples of what caused issues for me and hopefully can save you time in solving your problems. Here we go with tip number 1:

org.hibernate.PropertyValueException: not-null property references a null or transient value

Example 1

The Domain

Say we are managing a store with shelves full of items. Whenever an item on a shelf is empty, we need to create a restock order form. Lets represent this as 3 domain classes: Shelf, Item, RestockOrder

The Code

A restock order is created when an existing item on a shelf runs out, BUT, a order is also created for brand new items. The client has requested that when creating new items, restock orders can also be created.

The Shelf domain object:

		package com.ex
		
		class Shelf {
			int number
			static hasMany = [items:Item]
		}
	

The Item domain object:

		package com.ex
		
		class Item {
			String name
			String description
			double price
		}
	

The RestockOrder domain object:

		package com.ex
		
		class RestockOrder {	
			Item item
			Shelf shelf
		}
	

A Shelf has a list of items and is represented by the hasMnay relationship to Items. A restock order needs an Item, it just doesn’t make sense without one. But an Item does not belong to a restock order. Thus, we do not have a belongsTo RestockOrder relationship on Item. If a restock order is deleted, we certainly do not want to delete the Item record.

The Problem

Somewhere in our RestockController, we have the following code. It creates an instance of a RestockOrder and Item. It assigns the item to the restock order.

		def createOrder = {
				.
				.
				.
				RestockOrder ord = new RestockOrder()
				ord.shelf = currentShelf
				ord.item =  new Item(name:name, description:desc, price:price)
				ord.save(failOnError:true)
			}
		}
	

When the RestockOrder is saved, we get the following error:

          not-null property references a null or transient value: com.ex.RestockOrder.item

and the only way to resolve it is to create AND save an instance of Item and then assign it to RestockOrder. This might be confusing because, you can create and assign an instance of Item to a Shelf, like the following:

			Shelf shelf = new Shelf(number:1)
			shelf.addToItems(new Item(name:name, description:desc, price:price))
			shelf.save(failOnError:true)
		

without any error.

The Solution

A transient object is an object that has been instantiated but is not yet associated to the Hibernate session. When you associate this object to a property of a object that is associated to the session and try to save, Hibernate will complain and give you the
“Not Null Property References A Null Or Transient Value error”

This problem has to do with how GROM (Hibernate) cascades saves. Saves are automatically cascaded from parent to child when there is a hasMany relationship. This is why you can add a new Item to Shelf and save the shelf without explicitly saving the Item first. The save cascades from Shelf to Item via the hasMany relationship.

With RestockOrder, there is no such relationship and Hibernate will not do the cascading automatically. You have two solutions:

1 ) Explicitly save the Item before assigning.

		Item itm = new Item(name:name, description:desc, price:price)
		itm.save(failOnError:true)
		
		RestockOrder ord = new RestockOrder()
		ord.shelf = currentShelf
		ord.item =  itm
		ord.save(failOnError:true)
	

2) Configure the cascading behavior for Item in RestockOrder.

Here we set a save-update cascading behaviour.

		package com.ex
		
		class RestockOrder {	
			Item item
			Shelf shelf
		}
		
		static mapping = {
			item cascade:'save-update'
		}
	

Conclusion

Though this error is relatively simple (especially for this example) problem, it is very problem and can be difficult to track down as your domain model grows. Thus it is extremely helpful to have a understanding when these errors occur so you know what to look for in your application.


Example 2


The Domain

In this example, we’ll use the same domain as in Example 1. The domain objects are slightly diffrent however.

The Code


We’ll use the same domain objects as Example 1, but with slight modifications:
The Shelf domain object:

		package com.ex
		
		class Shelf {
			int number
			static hasMany = [items:Item, restockOrders:RestockOrder]
		}
	

The Item domain object:

		package com.ex
		
		class Item {
			String name
			String description
			double price
		}
	

The RestockOrder domain object:

		package com.ex
		
		Item item
		static belongsTo =[shelf:Shelf]
		static mapping = {
			item cascade:'save-update'
		}	
	

The Problem


We need to allow the user to create a new shelf but during this process we also allow them to assign restock orders to the newly created shelf. To do this, we create a new RestockOrder domain object and assign it’s parent as the newly created shelf.

Somewhere in a controller we have the following code:

		RestockOrder ord = new RestockOrder()
		ord.shelf = newShelf
		ord.item =  new Item(name:name, description:desc, price:price)
		
		newShelf.save(failOnError:true)
	

The problem is, when you run it, you get the “org.hibernate.PropertyValueException” error. This is because at the time of saving the RestockOrder, the instance of Shelf is still transient.

You get a similar exception if you try and add to the list of RestockOrder’s within a Shelf by adding directly to the Shelf’s restockOrders list:

		def currentShelf = Shelf.findByNumber(1)
		RestockOrder ord = new RestockOrder()
		ord.item =  Item.findByName("a")
		currentShelf.restockOrders.add(ord)
		currentShelf.save(failOnError:true)
	

instead of using Shelf’s addToRestockOrder() method. By using native Collection methods to add to the list, Grails will not automatically set the parent on the child entity.

The Solution

To resolve this, instead of assigning the parent of a child, you can use the addTo* method on the parent to add the Item as a child of the parent.

When you add the hasMany relationship, Grails provides an addTo* method. In the example above, you will have a addToRestockOrder() method which accepts a RestockOrder instance. This relationship automatically cascades saves from the parent to child.

  • You do not need to call save on the child.
  • It also updates the child’s parent reference.

Conclusion

In this example, I showed how you can use the addTo* method to avoid some common Grails errors, but as with all other programming problems, there are always several ways to solve the issue.

So, hopefully after reading this article, you have a slightly better understanding why these errors appeared in your code by looking at how it was caused on ours. I will continue to update this article if I find any other notable or interesting causes to this particular error.

References

What is LESS css?

What is LESS?

LESS is a css pre-compilier that has gained popularity over the past few years. There are a few good introductions to the language you can find here:

So I thought I would share what I like about LESS the most.

Syntax– I like how LESS introduces features such as variables and mixins without the overhead of learning new syntax. In addition, the use of nested rules feels like a native feature to regular css.

Variables – As mentioned previously, variables is a new introduction to css. I find variables mainly assigned to colors and they allow developers to define colors in one place so they can be changed easily without using search and replace.

Nested rules– Nested Rules are by far the greatest feature to regular css. They make css more DRY and easier to read as their inheritance is cleary visable. Nested selectors also force the developer to group togather related css within the file.

Functions – I havn’t used functions too much, but where I have, they really do help reducing duplicate code.

Operations, Namspaces, JavaScript – To be honest, I havn’t really used these 3 features of LESS very often (or at all). As I continue my use of LESS, I will update this post on how I feel about these features.

In conclusion, LESS is a WIN for me. It helps organize CSS in a “natural” way. It also helps keep LESS DRY. So there you go, LESS, it’s a good thing.

My new BBQ!

Last year I bought a gas barbecue and started barbecuing stakes on a regular basics. Cooking with a new bbq is a learning experience and takes some trial and error. Every bbq is different. Some get hot quicker than others, disperse heat at different rates, and each have their own “hot spots”. Once you learn the unique traits of your bbq, you can start grilling the perfect steak.

When I bought my new bbq, I had a tendency of over cooking the steaks so I started jotting down notes on the temperatures and duration I was cooking the stakes. I also noted down the final result. There are tons of articles out on the internet about grilling a good steak, but here is what worked with me:

T-bone, porterhouse, ribeye or NY Strip are my favorite choices for grilling. T-bone and porterhouse steaks can be quite large (and pricey) so if I’m just grilling for myself and I tend to get a small ribeye or NY striplion. My local grocery stores often sell sale NY strip steaks in 4 per pack sale packages which is a great buy.

Regardless of the type of steak, choose one that has as high degree of marbling. Marbling is the thin fat-lines that streak though the meat. When you cook the meat, these fat melts away infusing the meat with flavor. Try to avoid meat with a large hard clob of fat in the middle of the steak. These won’t melt away and can sometimes be very tough.

Steaks are graded based on the level of marbling within the meat. Top steaks have a grade of AAA (Prime in the United States), but only a few low percentage of steaks achieve this grade. The few AAA steaks are bought up by expensive steak houses and high-end grocery stores. Your local store probably has A and AA. My cheap “Chinatown” grocery store sells A to AA and my local Loblaws sells “AA or above”. The higher the grade, the better flavor, the higher price.

Let me meat warm up to around room temperature just before you throw it onto the grill. If your steaks are ice cold when you put it on the grill, the outside will be overcooked (perhaps even burnt) and the inside will be raw. Don’t let it warm up and put it back in the fridge.

Don’t rinse your steaks. My mom does this and I know others who do this. They believe they are “cleaning off” bacteria. By rinsing your steak, you allow bacteria sitting on the surface of your meat (which normally gets killed off during grilling) to penetrate deep inside the meat. The temperature achieved for a medium rare steak is not sufficient to kill bacteria that now resides there due to your rinsing.

Start on high heat, around 500 to 530 degrees F. This high heat will sear the outside of the meat, thus containing all the juices. A hot grill is also required to generate those perfect grill lines. If the temperature is too high however, you will char the edges of steak.

Make sure the steak is at least an inch thick. Anything between 1 to 2 inches is good. The thicker the meat, the longer you have to cook but if you cook it on high heat too long, you will burn the outside. With thinner meats, you can cook at high temp all the way because you will get a nice medium-rare inside without burning the outside. With ticker steaks, you may need to sear the outside and then move to indirect heat until you archive the desired rareness.

Don’t play with the meat too much. Let it sit and cook. Only lift to flip or reposition the steak. If you move it too much, the juices will begin to flow out of the steak and onto your grill.

There are several ways of knowing when your steak is done. I use the heel of the palm method. In this method, the resistance you feel by pushing on certain parts of your palm with the index finger of your other hand are equivalent to a particular rareness of the steak (when you push down on the steak). I don’t like poking my steak with temperature gauges because that causes the juices to flow out.

Let the meat sit for at least 5 minutes. If you cut open your steak without letting it sit, you will let all the juices run out. This is really important. Also, your steak will continue to cook for a bit after you remove it from the grill. So I take this additional “cooking time” into consideration.

After a few tries, you too will know how to grill the perfect steak.