First and most important, does it actually return the correct results! Also are all the changes requested actually put into the proc.
Replace any cursors with set-based logic not while loops!
Replace any dynamic sql in a stored proc if possible. This should be a last resort, not a first resort. If you must use dynamic sql, make sure to have a debug parameter which will show the code generated for the input values rather than running it. You will save no end of time when you need to adjust this or find out what went wrong with a particular set of values.
Never use select * especially if there are joins as at least one field will be sent twice.
If a table variable is used and a large data set is returned, suggest replacing with a temp table as it is likely to perform faster. Do not actually replace without performacne testing of course.
Replace any correlated subqueries with joins.
Use aliases and make sure that you put the alias on all the fields in the select. It is much easier to maintain if you don't have to figure out later which of the twelve tables in the join had that field.
Look for hard-coded values that can be parametized or pulled from an existing table. Especially if some of them will change with time (such as where mydate >'20090101'); these tend to cause bugs later.
If using Union, consider if Union All will work. It will be faster if so.
Check to see if left joins should really be inner joins and vice versa. Check to see if there is a left join with a value inthe where clause filtering on that table. Except for "Where myid is null", this will change a left join to an inner join. LIkely you have the worng results or you didn't need a left join. If you do need a left join, move this condition to the join and out of the where clause.
If you are doing more than one insert/update/delete make sure a transaction is used. Also make sure that any transactions have a way to rollback if one of the steps fails.
I'm sure there is a lot more, but this is a start.