Hackintosh
There’s a sizeable gap between Apple’s low end stand-alone desktop (the mac mini) and the next tier (the $2500 mac pro). I found that my current mini wasn’t keeping up with what I wanted to do. Textmate, passenger, a couple virtual machines and Photoshop were enough to send the machine, and it’s 3G of ram to it’s knees.
Therefore, I did what any person that can handle a philip’s screwdriver would do, I built a “Hackintosh.” A good set of parts, including a Core 2 Quad and 16GB of ram will cost about $900 if you shop the combo deals on Newegg. Also, while of dubious legality, it’s really easy to do.
This guide has all the information.
The only additional advice I have to add is to be patient while installing Snow Leopard. On my machine, it took an hour for the install to boot. Or four hours clock time as I continued to fiddle with the hardware and settings. So do yourself a favor and when you start the install grab a beer, relax for a bit, then come back and check on the progress.
Are you there to ship, or write code?
Amro Mousa tweeted about a great post by Joel Spolsky about Duct Tape Programmers. Also known as hackers, rockstars, and problem-solvers duct tape programmers are the ones that just get it done.
The line that resonated the most with me is the following quote from Jamie Zawinski:
But that’s not the point—you’re not here to write code; you’re here to ship products.
Unfortunately, I don’t think this is always true. In many organizations, especially the larger, more layered organization, the responsibilities of developing the software and shipping it are held by two different stake holders. The job is to write code, nothing more, nothing less.
This can be the most infuriating and frustrating environment for a duct tape programmer. The metrics are all wrong. Number of test-cases, tickets closed, features on the box, length of scrums, etc, don’t matter if nobody is using the product.
Thankfully, if you think your responsibility is really to make things that get used, there are some early signs that a position might or might not be a fit:
Things that should make you worry:
- Being asked for a BrainBench certification
- A 30-minute interview of nothing but syntax questions
- Lots of questions about keywords
- Greater emphasis on process than the problem
- Constant quizzing on the technology mentioned in your resume
Things that should make you feel good:
- The interviewer describes the problem and how they’ve solve some of it
- You describe some of the problems you’ve faced and how you’ve solved them
- You and the interviewer start brainstorming how you’d start solving the rest of the problem
- You and the interviewer realize that you’re both way over time and are missing something important
The first set of questions determine how well or quickly the candidate can produce code, but there’s nothing in there that explores whether any of that code ever did anything useful. The product is the vehicle, the code is the driver.
The second set is for the duct tape programmer. The code might not have been the most idiomatic or the best covered, but this person has written code to solve the problem in the past and is already thinking about how solve the next ones. In this case, the code is the vehicle that’s driven by the product.
Using these these lists as guidelines can help you find the right fit and place where you can be the most productive, while avoiding misery and a padded cell. Is there anything missing from the lists?
Disclaimers first. This post is not medical advice and I’m not a medical professional. Always consult with your eye-care professional about anything involving your vision. Always.
With that out of the way, I want to answer a question that I’ve gotten a lot recently. Almost everyone has heard of LASIK (laser-assisted in situ keratomileusis). Most companies and doctors offering corrective surgery advertise this procedure. Not as many people have heard of PRK (Photorefractive keratectomy). PRK is the procedure that Sonali had done a few weeks ago. LASIK is what I will be having done tomorrow.
Both are corrective, out-patient eye surgeries, and eliminate the need for the patient to wear corrective equipment, such as glasses or contacts. The recommended procedure depends on many factors. This post seeks to explain some of these differences.
What they are
LASIK is the more common procedure. In this procedure, a surgeon cuts a flap in the cornea to expose the area on which the laser operates. Once the laser has finished, the surgeon replaces the flap, which stays in place naturally. The creation of this flap leaves a permanent scar that is visible in close examination (when the eye-doctor shines the bright light in your eye).
PRK involves the removal of the top layer of quickly regenerating cells in order to reach the layer that can be effected by the laser. There is no flap. Over time, new cells replace the ones removed and the eye returns to its natural strength.
Both surgeries take only a few minutes in the operating room.
One over the other
LASIK is the preferred procedure, because the patient is able to function normally within a few days. As long as the patient refrains from rubbing their eyes, the risk of flap displacement remains low.
However, the creation of this flap permanently reduces the strength of the cornea and increases the risk of flap displacement in the case of trauma. In situations where the patient’s career exposes them to abnormally high levels of risk for head trauma, such as mixed martial artists, astronauts, and professional deep-sea divers, PRK is the only viable option.
Even if you don’t have an exciting career and are a normal software professional, the doctor may require PRK if the corneal tissues lack the necessary thickness. This was the case with Sonali.
Also, if you’ve had LASIK, but your vision has degraded, the follow up procedure will be PRK. If PRK was not so inconvenient, almost nobody would get LASIK.
Benefits
The obvious benefits are you don’t have to wear glasses or contacts. If you’re someone like me, with absolutely horrible vision, glasses are not really a viable option. Even the most expensive and thinnest lenses have noticeable levels of diffraction for any object not in the center of my field of view. While tolerable during the day or at home, being outside at night is frustrating experience.
Contacts are far superior for vision, but they are inconvenient for traveling. There are other risks as well, including the increased risk of eye infection and eye-fatigue caused by the lack of oxygen to the eyeball.
Major Downsides
The risk with both these surgeries is that you may never regain the same corrected vision. There’s a chance of halo’s, glare and reduced night vision.
With Lasik, the most terrifying risk is that your eye might fall apart. It’s not very likely long-term, but highly likely if you rub your eyes within a month of the procedure.
PRK is a far safer procedure, but requires much more time to heal. The same level of vision correction that is enjoyed by a Lasik patient in 48 hours takes 6 weeks to achieve with PRK. It will take at least a week for a PRK patient to be able to carry out normal tasks. The first week after PRK also involves more discomfort and pain.
Dry eyes are also a problem. There are other downsides and risks. Again, please consult your doctor.
Why does PRK take longer?
Instead of resealing a cut, the eyes of PRK patient have to re-grow tissue that has been removed. This has two side-effects. One is that there are more exposed nerve-endings being stimulated, causing the pain and discomfort experienced by PRK patients.
The second is that the cells regrow, it takes time for them to regain uniform density, resulting in blurry vision. There is no way for your brain to focus the image because light is not being aligned correctly, but during this period the patient does not have a prescription. Corrective lenses will not help.
Is it worth it?
I dunno, too early to tell. Check back in a few months.
This is just an overview, since many people are unaware of the existence of a second procedure. There is much more information out on the web. Please post any questions in the comments.
This topic starts with a conversation I was having a while back about how small developer pool available for startups in Atlanta and how difficult it is to pry development talent from jobs in large companies. While never explicitly stated, the difficulty baseline is The Valley.
I think that this situation is not as bad as many make it out to be. Home Depot, UPS, Delta, AFLAC and SunTrust conjure up very different images than Google, Yahoo!, Apple, eBay, and Oracle. Yet all are Fortune 500 companies and none of them count as startups. However, we do think that individuals working at the latter set of companies are more startup friendly.
While not as terrible as the perception, I do believe that this phenomena is real and it has little to do with the makeup or mentality of the workforce. It’s a result of simple economics. A standard for working for a startup is the assumption that the employee will give up some base salary in return for performance based compensation in the form of stock options.
An Atlanta company puts itself at a hiring disadvantage using the same compensation trade-off as its Valley counterparts. Lets put some numbers to this to see why.
I’m going to assume that the company has issued 1 million shares at $1/share, and will never dilute. Implicit in this assumption is that pre-money valuations and eventual dilution is similar between the average Atlanta and Valley companies. Differences here will skew the outcomes but the goal isn’t trying to figure out specifics, but the relative reward between regions.
Now the real numbers. According to Salary.com, the salary for a Senior Software Engineer is approximately $84,000 in Atlanta and $100,000 in Palo Alto.
For exit numbers, I used the charts in this post from Scott Burkett’s blog. The average exit in Atlanta is $259 million, the Bay Area is $356 million.
Generally, in my experience, the tacit assumption is that some dollar value of salary is forgone for equity. For this example, I’m going to use $2 of salary equates to one share. Percentage trade-offs make the final outcome look better, but there will still be a difference. The final large assumption is that everything goes to plan, and the company sells right at the end of the four-year vest for the average sale price in the region.
Here are the numbers after 4 years:
| Normal Salary | Startup Salary | Stock Value | Startup Comp | % Diff | |
|---|---|---|---|---|---|
| Atlanta | $336,000 | $296,000 | $125,000 | $421,000 | 25% |
| Greater SF | $400,000 | $360,000 | $175,000 | $535,00 | 33% |
The Atlanta employee looking to be part of a startup is taking on the same risks, for a lower reward. This will reduce the pool of talent available to any startup looking to grow to a self selecting set that appreciates the lifestyle and is willing to burden the risk at that reward threshold.
I don’t know if this is a positive, negative, or even correct (those assumptions are pretty large). Please leave any feedback, corrections, or methodological faults in the comments.
Standalone Rails Migrations
One of the most annoying things about deployments are dealing with databases. In the Java world, using Hibernate to generate your schema is pretty common. It works well in development, where you generally re-create and re-seed your database after each model change. However, it can be disastrous when deploying. It felt like each sprint needed a dedicated day for diff-ing the database schemas and figuring out what changed and what needed to be applied. Often, indexes would be forgotten, resulting in un-foreseen slowness.
Ruby on Rails solves that problem with using migrations. Migrations describe how to move from one version of the database to the next. While it’s built into Rails, I came across Standalone-migrations on GitHub. Not surprisingly, it exposes the core functionality of Ruby on Rails migrations, allowing you to embed it in any kind of project. You’ll still need Ruby to run the migrations along with the correct gems for connecting to the database.
Of course, Ruby on Rails migrations have a few downsides. Personally, I believe that the database should be aware of constraints and relationships. This has other practical benefits, such as automatic indexes. By default, Rails Migrations do not support foreign key’s natively. Simon Harris wrote a plugin to automatically associate foreign keys. Way easier than writing SQL.
Getting a rails plugin to work standalone required some munging, so I ham-fisted Standalone Migrations and Foreign Key Migrations together and put the project on GitHub. If this is something you need, clone my fork of Standalone Migrations.
Migrating TestTrack to JIRA
In another long fought battle that eventually led to victory, we finally moved off TestTrack to JIRA Studio. Of course, now I got stuck with the task of figuring out how to get the open defects from one system to the other. Thankfully this ended up being somewhat un-painful. The Jira4R gem allows for easy creation of issues with just a few lines of Ruby. There are a few caveats to using this script. The documentation is almost non-existent and very out of date. It’s also not available on any standard gem repository.
In order to save another fellow developer the headaches I went through, I’ve published the source for my migration script on GitHub. It includes examples of how to use the Jira4r gem as well as installation instructions. Feel free to fork away and make it better!
In another part of the continuing series on getting Spring to work properly with our legacy components, I recently had to revisit our the way were were handling transactions. In the previous post on this topic, I demonstrated how you can use a HandlerInterceptor to control your transactions. In this post, I demonstrate how you could use spring transactions, even if you can’t use the Spring way of configuring your Hibernate SessionFactory and need to support legacy code. The end result is much like putting a Ferrari body on a Pontiac Fiero, but it will accomplish the job.
The earlier solution has a significant drawback. The transaction will commit after the controller finished processing the request. Since Hibernate will not flush it’s session until a commit, all database errors will occur in a place where you can’t respond to them easily. Pushing the transaction boundary to the level below the controller (where it belongs anyway) will allow for correct error handling at the UI level. This can be accomplished with Spring Transactions.
Spring needs two things for @Transactional annotated code to do what you expect: the session factory and the transaction manager. Our legacy code used a statically initialized class to create a session factory. My first step was to manually create the HibernateTransactionManager with the correct session factory.
sessionHolder = new HibernateUtilSessionHolder(); SessionFactory sessionFactory = configuration.buildSessionFactory(); sessionHolder.setSessionFactory(sessionFactory); HibernateTransactionManager htm = new HibernateTransactionManager(sessionFactory); sessionHolder.setTxManager(htm);
The sessionHolder is just a class I use to hold the current SessionFactory and TransactionManager. The sessionHolder is also the interface between the legacy code TransactionManager. Here is an example method from HibernateUtilSessionHolder:
public Session getSession() { SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory()); if (sessionHolder == null) { if (LOG.isDebugEnabled()) { LOG.debug("opening session"); } Session s = sessionFactory.openSession(); sessionHolder = new SessionHolder(s); TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder); } if (LOG.isDebugEnabled()) { LOG.debug("GETTING session"); } return sessionHolder.getSession(); }
Since I hide all the functionality of the TransactionManager behind the previous API, none of the legacy code is aware the underlying transaction model has changed and manual commits will work as they have done before.
The next trick is to get annotations working within the context of new code. Exposing the SessionFactory and TransactionManager to Spring is pretty easy. First, create two static methods to access what was created earlier:
public PlatformTransactionManager getTransactionManagerInstance() { return sessionHolder.getTxManager(); } public SessionFactory getSessionFactoryInstance() { return sessionHolder.getSessionFactory(); }
Now expose them to the context by using Spring’s factory bean creation mechanism:
<bean id="hibernateUtil" class="net.vijedi.hibernate.util.HibernateUtil" /> <bean id="transactionManager" factory-bean="hibernateUtil" factory-method="getTransactionManagerInstance"/> <bean id="sessionFactory" factory-bean="hibernateUtil" factory-method="getSessionFactoryInstance"/>
HIbernateUtil is the static class that created the SessionFactory and TransactionManager. The other two lines show how to use it as a factory.
Finally, all that’s left to do is to add
<tx :annotation-driven />to the spring.xml file and mark up a bunch of code with @Transactional. It might be a Fiero underneath, but it still feels like a Ferrari.
I’ve got a 512MB Slicehost instance that I needed to launch a new Rails app (details coming soon). Since 512MB isn’t a whole lot of memory anymore, I wanted to optimize the services on this machine as much as possible.
The most efficient setup appeared to be running nginx, Passenger-Nginx, and Ruby Enterprise Edition. It was actually pretty easy to get all this running and would have been even easier had I followed the correct order of operations.
Nginx doesn’t support dynamically compiled runtime modules. Everything has to be built-in at compile time. Because of this, running:
$ sudo aptitude install nginx
will get you nothing useable besides the init script.
Instead, the best approach is:
- Install Ruby Enterprise Edition
- Install nginx-passenger
- Adjust paths
- Modify the
/etc/init.d/nginxscript - Reinstall all gems for REE
- Tweak the nginx config
- Add
nginxensiteandnginxdissitescripts to make it more ubuntu-y
The first two steps are pretty self-explanatory and start with the directions found here. Of course, if you are installing nginx, you want to the following instead of the command for apache:
$ /opt/ruby-enterprise/bin/passenger-install-nginx-module
Next you want to tweak the ubuntu /etc/init.d/nginx script to reflect the new paths.
You need to change the two lines that read:
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/nginx
to
PATH=/opt/nginx/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/opt/nginx/sbin/nginx
Next, you need to add the Ruby Enterprise Edition interpreter to your path. Open /etc/login.defs and update the paths settings with the location of Ruby Enterprise.
Installing gems is pretty straight forward. There are a few small tweaks to make to the nginx config file so that it works more like the ubuntu package.
At the top of nginx.conf add/change these settings:
user www-data; worker_processes 4; error_log /var/log/nginx/error.log; pid /var/run/nginx.pid;
In the http section, add:
include /etc/nginx/sites-enabled/*;Finally, it’s time to create the nginxensite and nginxdissite scripts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #!/bin/bash # nginxensite if [ -z $1 ]; then echo echo "You must specify a site name" exit 0 fi NGINX_CONF=/opt/nginx/conf CONF_FILE="$1" AVAILABLE_PATH="$NGINX_CONF/sites-available/$CONF_FILE" ENABLED_PATH="$NGINX_CONF/sites-enabled/$CONF_FILE" echo if [ -e $AVAILABLE_PATH ]; then ln -s $AVAILABLE_PATH $ENABLED_PATH echo "$1 has been enabled" echo "run /etc/init.d/nginx reload to apply the changes" else echo "$AVAILABLE_PATH does not exist" exit 1 fi |
and
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #!/bin/bash # nginxdissite if [ -z $1 ]; then echo echo "You must specify a site name" exit 0 fi NGINX_CONF=/opt/nginx/conf CONF_FILE="$1" AVAILABLE_PATH="$NGINX_CONF/sites-available/$CONF_FILE" ENABLED_PATH="$NGINX_CONF/sites-enabled/$CONF_FILE" echo if [ -e $ENABLED_PATH ]; then rm $ENABLED_PATH echo "$1 has been disabled" echo "run /etc/init.d/nginx reload to apply the changes" else echo "$ENABLED_PATH does not exist, ignoring" fi |
There you go, a working nginx install for your rails apps in less than an hour.








