NEWS: Dexamethasone Credit bureau reporting Secobarbital Home insurance price Apr balance transfer credit cards Fix credit report. Sprint Pcs Ringtones 0 interest credit cards for balance transfer Credit report monitoring Best life insurance quote Medroxyprogesterone Lozol? Low cost payday loan Credit report uk Free credit report .com Venlafaxine Fair credit reporting Suboxone Iothalamate Clomocycline Free Ringtones For Nextel Phone Tampa home equity loan Balance transfer on credit cards Chlorprothixene Nonoxynol Lowest apr rates on credit cards? Uk credit report Order credit reports: Midi Ringtones Converter Brompheniramine How do i get my credit report Credit report monitoring service Gitalin Demeclocycline Fair credit reporting Instant credit approval cards, Minoxidil Instant approval credit cards no credit check Credit reporting agencies Bad credit balance transfer credit cards Zero percent balance transfer credit cards 15 months Procyclidine Poor credit cards online instant approval bad Nisoldipine Clean your credit report Instant approval guaranteed credit cards: Motorola Q Ringtones Credit report monitoring service. Nalorphine Debt settlement Low cost payday loan Fix credit report: Free I730 Nextel Ringtones Wallpaper Anisotropine, Free credit reports in the uk Chlorotrianisene Noroxin Imitrex View credit report online free Novobiocin Off my credit report 1600 Nokia Ringtones! Nokia 3390 Ringtones Fenfluramine Ganciclovir Credit repair services: Consumer credit reporting agencies Phenoxybenzamine Acetohexamide Glyburide Personal credit report canada Free Kiss Ringtones Freee credit report Hexocyclium Credit report monitor Download Hear Mosquito Ringtones Credit cards and instant approval Hydromorphone Credit cards 1.99 apr ny Desipramine Metronidazole New home loans! 100 Free Real Music Ringtones Hexoprenaline Misoprostol Credit and cards and no interest and balance transfer Fluorescein Donepezil? Online credit report I get a copy of my credit report: Credit report repair Divalproex Freecredit report.com Bad credit instant approval cards, Avandia A copy of my credit report Cell Music Onto Phone Ringtones Mda Ringtones T Mobile? Erythrityl Disopyramide Free Cell Phone Ringtones Percocet And credit report Erythromycin Converter Joy Ringtones Serial Epoprostenol Obtain a credit report Free credit reports without using a credit card Instant approval secured credit cards Cyclandelate 3 credit reports Humulin Dimethothiazine Pancuronium. Free Ringtones For Alltel Customer Consumer credit reporting agencies Adderall Free experian credit report Motorola Q Ringtones Information from credit report Discover credit cards instant approval Dioxyline Dioxyline Sprint Pcs Vision Ringtones Debt credit report no credit card needed Tessalon Free Polyphonic Ringtones Sprint Aminophylline Noctec Chlorcyclizine Procyclidine Zero percent balance transfer credit cards for life: Buspirone Debt consolidation service: Obtaining credit reports Download Free Mobile Ringtones T? Doxycycline 0 intro apr credit cards Personal credit reports Ringtones For Verizon Phone Restoril Mecamylamine Health insurance individual Ethosuximide. Free yearly credit report Obtain a credit report Listen Mosquito Ringtones Pravachol Lactulose Cyclobenzaprine Creditreport Balance transfer credit cards Order credit reports Ethoheptazine Credit report gov Carbidopa, Credit reports no Reading credit reports Free Music Ringtones For Verizon Best credit cards for balance Phenelzine Calcifediol: Download Free Ringtones Virgin Mobile Instant online approval credit cards Interest balance transfer credit cards Bad credit balance transfer cards Hytrin Cocaine. Free Ringtones Samsung Sprint Lomotil! Transunion credit reports Haldol 8100 Free Ringtones Sanyo Sprint Flagyl Trientine Instant approval credit cards for poor credit Feldene Cycloserine Student credit cards with no apr Trimethobenzamide Estraderm Visa cards online instant approvals? Verizon Lg Vx6000 Free Ringtones Phenolphthalein How to read a credit report Indomethacin Amikacin Methenamine Instant approval unsecured credit cards Dispute credit report Lysodren Vidarabine! Instant approval less than perfect credit credit cards Pyrimethamine? Colesevelam Monopril Budesonide Credit report and score Insurance credit report Debt settlement letter Cardizem Reporting credit card? Free credit report online Commercial credit reports Loan debt consolidation Balance transfer instant approval credit cards, Best balance transfer cards for bad credit people Ringtones For Prepaid Verizon Wireless Phone Medroxyprogesterone Health insurance individual Credit reports in Free credit report without credit card Effexor Urokinase? Fluphenazine Nimodipine Instant approval credit cards bad credit Prempro Pseudoephedrine Debt credit report 0 balance transfers credit cards Download Mobile Mosquito Ringtones T Credit report monitoring service Insulin? Credit michigan report service Free Sprint Cell Phone Ringtones Electricity Methsuximide Credit fix repair report How do i get a free credit report? Trimethadione Fact free credit report once a year Free online credit report Phenobarbital, Free annual credit reports Credit reporting act litigation settlement Fleet zero percent balance transfer credit cards Mifepristone! Fair credit reporting act A credit report. Fair credit reporting act litigation Canada instant approval credit cards Free credit report check Sulindac One credit reports Paramethadione Credit repair uk Secured home equity loans! Soma Free credit report government! Line credit reports Cipro, Reports credit cards Fixing credit report? Free Ringtones For Motorola Cell Phone Equity home loans Tramadol My credit report com? Commercial loan Low fixed interest apr credit cards balance transfers! Bayer National free credit report? Time instant approval credit cards Guanabenz Download Nextel Ringtones Software Refinance home Insurance life Nefazodone Free Ringtones Converter Software Free online credit report no trial offer Piperacetazine Reporting bad credit Download Free Pcs Ringtones Sprint How do i get my credit report 0 apr balance transfer over 70 credit cards Online home equity loans Chlortrimeton Free instant credit reports Cell Cingular Free Phone Ringtones Subscription Without Credit cards instant approval help rebuild credit Credit reporting software Phentermine. Celcom Caller Ringtones Report no credit card Laetrile Reviparin Run credit report Free Cingular Wireless Ringtones Games credit report no credit card needed Free dispute credit report letter Bromides Edrophonium Oxycodone Life insurance policies! Ketoprofen Equafax credit report Prevacid Nextel Music Ringtones, Nalorphine Instant approval and credit cards Disputing credit report Coumadin. Atacand Free experian credit report Instant approval on credit cards Sample credit report Cell Cingular Phone Ringtones Absolutely free credit report no trial Nasonex Free Mp3 Ringtones Samsung How to get a credit report Lozol? Balance transfer credit cards uk Lil Lloyd Ringtones Wayne Nonoxynol Free instant credit report, Aminophylline Combivent Reporting credit card Oxymetazoline Cilexetil Celcom Malaysia Caller Ringtones Credit cards with 0 balance transfers Verizon Lg Ringtones Oxycodone Credit cards instant approval first timers Fluconazole Pargyline Betaxolol Chloramphenicol Annualcredit report.com Encainide Enoxaparin Free credit report experian Burial insurance Credit report help 3 credit reporting agencies Butriptyline My free credit report .com Alesse Usa zero percent balance transfer credit cards Instant approval credit cards no credit check? Into Make Mp Ringtones Samsung Phenazocine Debt credit report Isopropamide. Dextroamphetamine Free Cingular Ringtones Ringtones For Nokia Phone Trw free credit report Credit reporting and Download Free Midi Ringtones Hydrochlorothiazide Free credit report without using a credit card Caller Code Maxis Ringtones Depakote Enalapril Midi Ringtones Converter Free Ringtones For Sprint Pcs Phone Free credit report law Us credit cards interest low apr 0 Merchant report no credit card required Dextroamphetamine Cefazolin, Loracarbef Ethoheptazine Chlorotrianisene Hexocyclium Free credit report in canada Mazindol Free credit report with score Bromocriptine Trihexyphenidyl Sparfloxacin. Cialis Dicumarol! Pyridoxine Wav Ringtones Converter Nokia Polyphonic Ringtones Iproniazid Fair credit reporting agency Second home loans Bad credit instant approval credit cards Home construction loans Aurothioglucose Bexarotene Pediacare Free credit report no strings attached Tegretol First time home loans Health insurance individual Free Music Pcs Ringtones Sprint. Methscopolamine Thiamine! Check credit report equifax Reading a credit report Mirena Cosigner credit cards instant approval Instant approval 60 second credit cards Converter Pc Phone Ringtones Transfer balance credit cards Renter insurance usa! Instant approval credits cards no credit Dilantin Relafen Free printable credit report? Credit cards bad credit instant approval Verizon Wireless Mp3 Ringtones Physostigmine Free credit report with no credit card Fastin Lg Ringtones V111 Verizon Wireless. Canadian credit score reports Methixene Iproniazid Lamictal Free credit report no membership online Gitalin, Thyroid Naprosyn Free credit report services Pravastatin Payday loan onlines Theophylline: Annualfreecreditreport.com Three in one credit report! Low interest balance transfers canada credit cards Penicillamine Bentyl Instant approval credit cards with no fees Dexbrompheniramine Download Free Ringtones For Verizon Wireless Phone Clean up credit report Instant approval credit cards for poor credit Etoposide Olsalazine Epivir Get credit report Zero percent transfer balance credit cards Low interest credit cards with no balance transfer. Trans union credit reports Equifax credit reports, Credit report fraud Credit report information Free consumer credit report Restoril Balance transfer best deals credit cards Pentazocine Guaranteed instant approval credit cards for poor credit Consumer credit reports, Fenfluramine Bureau credit reports Music Ringtones Converter Aminoglutethimide Ethchlorvynol Instant approval credit cards uk! News report no credit card required Online auto insurance? Ethanol Free Samsung Cell Phone Ringtones My credit reports Free instant credit report online no credit card needed. My free credit report Dyazide Aldactone Free online credit report no trial offer Cevimeline Diclofenac Instant approval poor bad credit cards Caller Download Hotlink Maxis Ringtones Aspirin Efavirenz Naltrexone Biaxin Free no obligation credit report Pyrazinamide Secobarbital Griseofulvin Chloroquine Voltaren. Dianabol Credit cards for balance transfers New jersey free credit report Phenelzine No credit instant approval credit cards 3 credit reporting Free Maker Nextel Ringtones Software Robaxin Aztreonam Free Motorola Tracfone Ringtones Free copy of my credit report Phenindione Colistimethate Download Ringtones For All Nokia Phone Dichloralphenazone Metolazone Games report without credit card Prempro Free Boost Real Music Ringtones 100 Free Real Ringtones, Obtain free credit report Free instant credit report online noe credit card needed Reporting credit 3 in one credit report Methocarbamol Free credit report no credit card needed Mechlorethamine Free Ringtones For Sprint Sanyo Phone, Authorization and release credit report Gentamicin! Decamethonium Credit report laws Septra Auto refinance Carbimazole Refinance investments Imipramine Check credit reports Verizon Wireless Lg Vx4500 Ringtones Instant payday loans: Dactinomycin How to read credit report Ergocalciferol Trans union credit report. Credit cards with low apr Credit report dispute forms Credit bureau reporting Explaining credit report scores? Free instant credit report online no credit card needed Instant approval credit cards, Amphetamine Mometasone, Xanax No obligation free credit report online Daunorubicin 3 credit reports! Mda Ringtones T Mobile Brompheniramine. Provigil Instant approval for credit cards with poor credit Debt settlement Selegiline Adapalene Iodipamide Annualcredit report No apr credit cards! Idoxuridine Estraderm Free Ringtones For T Mobile Phone Flunitrazepam Best credit cards to transfer balances 0 balance transfer credit cards Free Music Nextel Phone Ringtones Imipenem Triflupromazine One free credit report per year Free canadian credit reports instantly online Experion credit reporting! C139 Motorola Ringtones Phencyclidine Astemizole Student credit cards with no apr Lamictal Oxprenolol Child life insurance Allstate fair credit reporting act Pindolol Zyrtec Free instant credit report Cell Free Phone Ringtones Wallpaper Instant online credit approval and credit cards Cogentin. American debt consolidation Alprazolam Nokia Ringtones And Logo Macrobid Diltiazem Boost Free Nextel Ringtones Flurazepam Diclofenac, Clomiphene B class instant approval credit cards Fenoprofen Free instant credit report with no credit card Isoxsuprine Seroquel Sprint Pcs Ringtones Download Rofecoxib Free Reggaeton Real Ringtones Thiothixene Free no obligation credit reports Commercial property loan: Business credit card instant approval credit cards Dofetilide American express cards instant approval bad credit Credit reporting bureau? Ramipril Get free credit report. Cefprozil Buying life insurance, Triprolidine 3 bureau credit report 025 interest balance transfer credit cards Health insurance: How do i get my free annual credit report Mosquito Ringtones Silent! Promazine Cortisol? Interferon Apr balance transfer credit cards Bad credit 2b instant approval 2b credit cards Trans union free credit report Free credit report no credit card needed Piroxicam? Free Real Music Ringtones For Alltel Instant approval department stores credit cards Pentobarbital Credit reports 3, Instant approval credit cards for people with high balances Annual credit report free Credit report and scores Robaxin! Oxybutynin Free credit reports without using a credit card Credit reports no credit card Vicodin 025 apr balance transfer credit cards Cell Music Onto Phone Ringtones, Ceftibuten Converter Joy Ringtones Serial Fixed apr business credit cards Afrin Credit report dispute Nialamide, Saccharin Low interest credit cards visa fixed apr Abacavir Absolutely free online credit reports Refinance Credit rating report: Credit repair report service Disputing credit report! Cogentin Instant approval credit cards students Poor credit instant approval cards Debt consolidation Zuclopenthixol 3 bureau credit report: Ciguatoxin Glipizide Lynestrenol Free Real Ringtones Sprint Free Phone Ringtones Sprint Time instant approval credit cards Pheniramine Granisetron Desipramine Search high limit credit cards instant online approval Credit reports com Timolol Free no obligation credit report Hydrochlorothiazide Home insurance price Neomycin? Levoxyl Instant approval credit cards with bad credit Digitalis Streptomycin Download Free Midi Ringtones Atacand? One credit report Converter Joy Ringtones! Risperdal Dimenhydrinate. Debt settlement Transunion credit reporting agency Free credit report com Instant credit approval for credit cards on line Credit report services Afrin Credit cards with 0 on balance transfers Credit cards with balance transfer: Chloroquine Reports credit cards Enoxaparin Instant approval credit cards with bad or no credit, Yearly free credit report 3 credit report agencies Lo apr credit cards Cleaning up credit report Imiquimod Amitriptyline On my credit report Free credit report instantly Dash Mobile Ringtones T Free Alltel Lg Ringtones! Fosinopril Credit report self help repair! Diazoxide Obtain free credit report Chenodiol Refinance homes? Flupenthixol Meperidine Download Free Bollywood Ringtones Balance transfers on credit cards! Unlimited credit reports Podofilox History transunion credit report Repaglinide! Life insurance policies Lipitor. Thioridazine Allstate fair credit reporting act litigation New instant approval credit cards Guanadrel. Business credit cards instant approvals Canadian credit report Copy of credit report Bureau credit reports Reporting credit card Bromodiphenhydramine. Felodipine Instant approval bad credit unsecured credit cards Download Free Midi Ringtones Tinzaparin Digitoxin Nextel I730 Ringtones Business credit report solectron centum Lamotrigine, Buprenorphine Loan debt consolidation, Get a copy of my credit report Major credit reporting agencies Aprobarbital Yasmin Free Kiss Ringtones Loperamide Chantix Senna Instant approval corporate credit cards Valerian? Chromium Download Free Ringtones Sprint Free Pcs Ringtones Sprint Lithium Ringtones For Tmobile Cell Phone Instant online shopping credit cards instant approval: Free instant online credit report Low apr balance transfer credit cards? Zalcitabine Free equifax credit report Tolazoline Botox 0 apr on balance transfer credit cards Isradipine: Terbinafine Payday loan Free credit report no membership online Equifax credit report, Instant approval credit cards in uk Us government free credit report Low interest credit cards with no balance transfer fee Free I730 Motorola Nextel Ringtones Procyclidine Consumer credit reporting reform act: Compare credit cards instant approval Lotrel Report free no credit card required for instant online Duragesic Credit report dispute form Credit cards instant guaranteed approval visa Digi Caller Ringtones Mephentermine? Reports on credit Lactulose! Canadian credit cards instant approval online Reports and credit Theophylline Home equity Refinance houses Ergotamine Are credit reports Imiquimod: Dilantin Credit report mortgage leads

I Am Not a Software Company: How I Make Money Not Selling Software

December 31st, 2007 by Jaybill McCarthy

money.jpgAs I’m sure you know by now, I am a freelance web application developer. I’m not a designer, a flash developer, an HTML/CSS coder or a user experience expert. Each of those things are disciplines in their own right. My focus is pretty narrow. In a nutshell, other people decide what the thing is supposed to do and I make it work. Paint it whatever color you want. I’m a software developer. I write programs. I am not an artist. I’m a craftsman. I’m finally making a decent living at it, so I thought I’d share some of the things I’ve learned.

There are two main ways to make a living if you write software. The first and most obvious is simply selling software. Write a piece of software and sell it to someone. Simple, easy to remember. The problem with this approach, for me, is that it distracts me from my very narrow focus: making things that work. The very best software is useless if it’s not implemented correctly. While there is some appeal to doing not much and collecting license fees for my work, it’s really not that simple. When you sell software, you have to support it. You have to fix bugs, make improvements, etc. I could of course offer support contracts, but then I’d be married to every piece of software I sold for the rest of my life. Not a terribly attractive prospect.

The second way to make a living with software is to make something useful out of it and sell that. What I’m doing now is providing a service. I’m taking software that I either write or reuse and integrating it into a working web site. The price of this service based on what it is worth. Note that I did not say “what it costs”. Cost and worth are two very different ways of determining price.

Cost is determined by counting up the resources it takes to create or implement something. “Resources” in this case means “development hours”. If a project takes me 50 hours, I take my hourly rate (which includes some markup, presumably) and multiply by 50 and that’s the price. That’s fine if you’re reinventing the wheel every time you do a new project, but I very heavily reuse things I’ve done before. This means that unless I lie about how long things take, I make less money on jobs where I can reuse things I’ve done before. In essence, I punish myself financially for being more efficient. This does not make a ton of sense to me.

This also creates the paradox of having to estimate how long something will take before I’ve done it. As this is nearly always impossible to determine, I will almost always get beat up in terms of money doing estimates. If I don’t, it’s luck. I don’t really like gambling with my livelihood. Cost-based estimating also puts me in a position where I am constantly trying to sell people hours of work. I don’t know about you, but I’d rather sell people things that work and spend less time working.

Worth is how much someone is willing to pay for something I’ve done. I implement a feature, from scratch or by reusing something I’ve already done and the price is X. Cost is my problem, not my client’s. I do not estimate, I quote. If it takes me 2 hours or 2 months, the price does not change. There is no negotiation on the price. If a client cannot afford to pay for said feature, they don’t get it. Remember, the relationship between me and my client is that I provide them with useful things and they pay me for that service. If they don’t pay me for that, then they aren’t really a client, but a recipient of my charity. This is not to say that charity doesn’t have its place, but that place is not in the client/contractor relationship.

Worth-based quotes eliminate problems. Cost-based estimates invite them. I am very up front with prospective clients about my policies in this area. A successful (and fun) project depends on a good client/contractor relationship. Arguing about how much things cost creates animosity between me and my client before the project even begins. If a prospective client is unwilling to pay for things based on what they are worth, it’s not in anyone’s best interest for me to work for them, even if it means turning down a paying gig. I’d rather spend the effort working with someone else that sees the value of what I do in terms of the useful things they get and not the dollar amount.

So I don’t sell software, I sell useful things. What about the software itself, then? Easy. I open source it. This means anyone could take the software I’ve spent lots of hours producing and use it to do exactly what I do. This means that potentially, someone could take my work and use it to compete with me for jobs. Why would I put myself in this position? Also easy. I’m not a software company.

By making my work open source, I do a few important things. First, I retain copyrights on everything I do. I never, ever, ever sell source code to clients. This means that I can reuse code from any client project on any other client project without issue. Clients get source code, of course, because the source code is open source. Everybody wins.

Making useful software available to everyone means that more people will be able to implement that software. If the software is useful, easy to extend and lots of people implement it, it can become a de facto standard. Others can contribute to and enhance the software in ways I didn’t even think of or didn’t have the resources to do.

Doing things this way is a huge selling point for freelancers and clients alike. I’m not rolling my own, I’m using something that’s freely available and well-documented that lots of people know how to use. This provides long-term peace of mind for clients and for me, because the application in question is not subject to our continued relationship. There are other people who know how the thing works. Everybody has options.

Can other people use my work to do what I do? Sure. Can they do it as well as I can? Some can, some can’t. I leave that decision to my potential clients. I am, after all, selling a client the implementation of useful things. If they believe I can do what I say, they will pay me to do so. If they believe someone else can do it better, they’ll hire the other person. I’m in this position with any prospective client. It’s called a free market economy. The software in question matters very little, all other things being equal. Why should I be scared to compete on a level playing field?


Posted in cost, freelance, money, open source, worth | 2 Comments »

Heywire Guild & Gallery

December 11th, 2007 by Jaybill McCarthy

heywire_screenshot.pngI just finished phase one of the biggest projects I’ve ever done in my life. It’s called Heywire Guild & Gallery. While it’s still pretty new (as of this writing it’s four days old) it’s gaining steam rapidly. I wanted to document my experience while it’s all still fresh in my head.

A little over a month ago, my old friend Steve King came to me with a crazy project. Steve gets a lot of crazy projects, but this one was especially crazy. Essentially, the client wanted to build “Facebook meets eBay, but for art.”

Being a guy that builds social networking sites for a living, I usually tune out right around the time someone starts a sentence with “It’s Facebook meets…” This is because most of the time, the person saying it feels they are the only person that ever thought of harnessing the unspeakable power of “social networks” and “the Internet” for whatever their niche interest happens to be. They also usually don’t have any money, or worse, want you to work for questionable equity. (read: free) This is because they are true visionaries. Isn’t the prospect of basking in their utter awesomeness payment enough?

This, however, was different. Steve’s client (who needs to remain nameless) is a smart business man who made a lot of money in several other ventures. He has a lot of good ideas and the resources to make them happen. There were also no shady equity terms. He wanted it built and was prepared to pay for it. All good so far. Then came the kicker: The site needed to launch December 6th. I found out about it on October 19th.

Normally, I avoid projects that I feel are impossible, no matter how much I want to do them or how much I need the money. It’s better to decline work you can’t do than try to do it, fail and not get paid. I very seriously considered passing on this job considering the time constraints. However, I had just come off building a few other large sites that had a lot of similar elements, so I wouldn’t need to start from scratch. In fact, for going on a year now, I’ve slowly been building up a community application based on top of the Zend Framework. Each time I do a new site, I add to and refine the the underlying app. This seemed like a great opportunity to not only reuse earlier work, but further the platform. So I took the gig.

Step One: Tear it Down

So what I had when I started Heywire was the code from three different apps: MashupChallenge, LazyLibrary and BonAbode. I was pretty proud of how these came together, but they were all pretty site specific. MC and BA share a ton of code, but they’re still distinct apps. The first thing I wanted to do with Heywire was make the application utterly generic, so that building a site on top of it would mean writing a series of modules, plug-ins and a theme. This way, I could eventually port BA and MC to it, so I’d be maintaining one core app instead of several. I wanted to make the Wordpress of community sites, in so much as that when you customize Wordpress, you do it via plug-ins and themes, not by hacking the code base.

To me, there’s a pretty small list of things that are core to absolutely every app I build. I needed to get down to these core things and rip out anything site specific.

First, I needed an MVC framework. Zend does a nice job of this. You can easily break your app into modules, each with it’s own controllers and models. I really wanted to use Smarty for my templating solution instead of phtml, as I find the syntax pretty friendly and it has a nice precomiling and precaching system, say nothing of its rad plugin system. By implementing Zend_View_Interface, Smarty can easily and transparently supplant the view system supplied with the framework. That’s just how they roll over at Zend. Zend_DB is a really flexible way to handle the model layer, as you can be talking to a generic database table in about three lines of code. So now we’ve got the controller, view and model stuff taken care of.

A note on the model thing. I use MySQL 5 for two important reasons. Stored procedures and views. Zend_DB_Table can talk to a view as easily as it can talk to a table. (It just can’t insert or update, obviously.) I can tell you right now that there is not a single bit of in-line SQL in this application, and it’s pretty complex. Any time I have a query that makes for an overly complex where clause or needs a join, I make a new view and a new model object to go with it. This saves you the overhead of creating a huge, ridiculous query at run time and makes your code a lot more manageable. It also saves you from a lot of SQL-injection-hacky-type-stuff.

Core app functionality consists of a few important things. There are users, roles and resources. Users (”jimmy” and “pam”) have roles (”user” and “admin”). Roles can access resources. (”post blog entry” and “delete user”) Zend_Auth and Zend_Acl in combination give you user authentication and access control. It was really important to me to keep access control out of the controller logic. That way, changing what each role can do is a configuration change, not a code change.

I decided to control access at the action level. This has so far proved enough for my purposes. If I need something more granular than I can do with one action, I simple make another. To control access to these, I needed to dynamically get a list of what they are for each controller class. First I tried using the introspection API, but that proved annoying as I had to actually load each class to introspect it. I ended up going with a much quicker and dirtier solution. Knowing that Zend_Controller looks for actions based on their function name being “somethingAction”, I just regexed the text of the class files for “function [something]Action”.

I also have my own extended version of Zend_Registry that stores all its values in a db table. Whenever I need a configurable value in the application, I call App_Registry::get(’some_value_you_can_set’,'default value for this’) - this checks the registry for said key, and if it doesn’t find it, it adds it and uses the default value provided. I have a form for editing these values in the application. This is cool, because it means that when you add a new feature that requires a setting, it doesn’t break the app if the db doesn’t have it. The value may not be correct for that instance of the app, but it’s easily set in the db. My bootstrap loads the config from the db and sticks it in the registry. Why not use config files for this? Easy. There is one thing a config file should have in it, in my mind: the location of the database. EVERYTHING ELSE GOES IN THE DATABASE, WARDEN. Seriously. I have two development copies of this thing and three people working on it, I do not need to be copying instance specific config data all over the place. As far as versioning, I do not store config files in subversion. I store a template of a config file, which gets copied to the real version on install. This prevents config values getting overwritten by svn updates.

So now I’ve got my user, role, config and resource model objects and views to create and edit them. I’ve also got actions and views for registration, account editing and basic administration.

Step Two: We Can Rebuild Him

From here, I added things that probably aren’t going to get used in every single app, but would probably be used in most. Things like comments and media. As far as implementation, I made these generic, so they could be attached to users as well as anything else in the system.

At this point, we’ve got the basic elements of a community site. Users, profiles, comments, media and administration. This comprises the core app. We’ve also got a theme, which is a neatly organized set of Smarty templates in a directory tree outside of the application code directory. This way, we can swap themes out as needed without messing the core app up. It It’s also useful when you’re working with a UX person, like I was in this case, because they can make relatively easy subversion commits and updates independent of the core application.

Step Three: Add Modules, Rinse, Repeat

To expand the app from being Generic Social Network to being Heywire Guild & Gallery, I needed to start building out additional modules. I store these next to the default module and maintain them in a completely separate subversion repository for easy separation. (More on that next time.) By assuming a directory structure, I can automatically add new modules to my include path in my bootstrap. This is cool, because it means that in the future, add on modules will be easily integrated and removed.

So in some cases, modules are completely standalone, like the blog. I won’t be managing the content here, so it’s important I have an interface for the client to do it. Wordpress is easy to use and well known. For this reason, the blog is nothing more than a series of XML-RPC calls to a hidden copy of Wordpress, because, frankly, I’d rather do my own work than repeat what Matt Mullenweg did just for the sake of having it all under my own roof. I call this process “sidecarring” and I do it wherever it makes sense. In fact, the whole “CMS” in this thing just uses the pages functionality of Wordpress. I hate duplicating the work of others, especially when said work is such high quality.

In most cases, though, modules need to tie back into the default module. The “usercontent” module (my generic term for what is called “artwork” in heywire) needs to know about users. For example, when I delete a user, all of their content should also get deleted. I could of course hack the user module, but then I’d be violating my “keep it generic” rule. To overcome this, I borrow a concept from Wordpress and many other well-written apps - callback functions. In each of my controllers and model objects, whenever there’s something that could usefully be extended or filtered, I register a “hook” with in my registry. These are all accessible via a plugin object that extension code can instantiate and use. Extensions can register “actions” or “filters”. Both specify a class and a function to be called by a hook. The actions must specify a callback function that accepts an array called “params”. Filters work the same way, except that they must also return an array with the same number of keys. So for our earlier example, the “user” model object has a hook called “post_delete”, which passes passes a param array of user records that were just deleted. Usercontent has a plugin that adds an action to that hook to delete any usercontent objects belonging to that user. Using this method, I can add pretty much anything to the core app and keep it completely distinct from it at the same time.

Things I Have Learned From This

Normally I’m busy learning from my mistakes. This one time, I’m going to learn from my success, and I hope you can too.

First, if you’re rolling your own app from scratch these days, you are dumb. There’s just no other way to say it. There are no shortage of excellent application frameworks these days suited to a wide variety of different sites. What we did here simply would not have been possible without a robust, extensible application framework to do the tedious stuff, like talking to the database and such. I like Zend because it makes sense to me, but this isn’t like…Zend über alles or anything. I looked at CakePHP and Symfony before deciding on the relatively new Zend Framework. All three are very solid. I went with Zend because they have a very take it or leave it approach to everything. If you want to use the framework and nothing but the framework, it’s pretty complete. If you want to skip some stuff and add other stuff in, they make that really easy. It’s a tool, not a way of life.

Second, always build your apps generically. Wherever possible, create plugins and extend existing classes rather than hacking things for the app you’re working on. Yes, it requires more thinking, but once you get into that mindset, it will save you tons of work and headaches.

Lastly, and perhaps most important: specialize and make it easy for other specialists to work with you. Unless you’re explaining what you do to your grandmother, there’s no such thing as “an Internet guy” any more. Since around 1997, there are several different disciplines under the umbrella of web site production. If you purport you can do all of them, you’re good at one and lackluster at the rest. Know what you’re good at and find people whose work you admire to do the parts you’re not good at. I am a developer. A good one, maybe. I am a below-average HTML/CSS guy. If you are a developer, do not be fooled by HTML’s apparent simplicity. Cross-browser compatibility and accessibility issues are enough to break a man. Also, engineering types tend to make the worst interface decisions imaginable. Web interfaces are an area of specialized knowledge these days, if it’s not your core competency, find a ninja. They’re out there. Lucky for me, I know one of the best UX/HTML/CSS guys in the industry, that being Cory Duncan. Cory brings a level of polish to everything he does that makes him indispensable. Hire Cory if you can. Tell him I sent you.

Where I’m Going From Here

You may have noticed that I haven’t shown any code samples from the generic application I’ve been talking about here. There’s a good reason for that. Pretty soon, you’re going to be able to look at the whole thing yourself. That’s right. I’m in the process of turning it into an open source project, under a BSD-style license. It’s going to be called communit.as, and I’ll be setting up a site for it shortly. I’ve benefited so much from the open source software that made the thing possible it seems wrong not to share it. Stay tuned.

If you have any questions about the stuff I’ve talked about here or thoughts on how I’m doing things right/wrong/stupid, feel free to leave a comment or email me.


Posted in Zend_Db_Table, communit.as, databases, heywire, lazylibrary, php, plugin, programming, wordpress, zend, zend framework | 7 Comments »