Friday, December 31, 2010

Using Hamachi for Remote Desktop Sharing

I, or more correctly one of my clients has used GoToMyPC before to share their PCs for support purposes. I am not in the PC support business so it isn't something I care too much about, but sometimes I do get curious about alternatives.

One alternative is LogMeIn. Definitely lower cost. If you are a gamer or non-profit, some of their products and services are provided without fees. That's actually something a few people and organizations I know of would benefit from.

The first free thing is the LogMeIn Free service. Even the Pro version is not at all pricey. LogMeIn Free gives you most of the interesting things of GoToMyPC, without the cost. If you still need to share files, you can always use DropBox or one of the other fine sharing services.

The second free thing is what would appeal to hobbyists, gamers, and some non-profit IT types: the Hamachi Virtual Private Network.  You download a little pop-up utility that lets you connect to another computer also running Hamachi, or host a connection.  They call it "mesh" network, but it is basically peer-to-peer networking.

One neat thing about Hamachi is that you can also use it to tunnel Windows Remote Desktop Connections or VNC connections. Create a network on one of the Hamachi clients and connect to it on the other client. After that you can use any RDC client to connect to a Microsoft Windows PC or VNC to connect to a Linux, Mac, or PC client, using the IP address that Hamachi shows in its pop-up.


Don't forget to grant access to Hamachi in your software firewall and through your router's firewall. Also, Windows users will have to enable RDC sharing and set a password for it in their control panel. 


 As I write this, I'm connected through Hamachi to my Lenovo T61, and running RDC to access the Windows desktop. It is on my local LAN, so performance is not representative, but it is neat that it can be done, effectively making it unnecessary to use LogMeIn or GoToMyPC at all for non-commercial purposes.

Wednesday, December 29, 2010

Classes and Inheritance in Javascript

Here is some news for Javascript monkeys: Javascript does not have classes. None. Nada. When people speak of OOP classes and Javascript, they are making it up, literally.

Any talk of OOP classes in Javascript code is a pretense. Now, some of that code is really ingenious, really nifty stuff. But there are no first-class classes in Javascript.

There are two consequence of these non-first-class constructions:

  1. Core language primitives were designed before the faked constructs existed and although the core language retains its closure (as much as before the extensions), the faked constructs introduce new elements and relationships that are not necessarily conserved through the primitive operations. 
  2. The extended constructs do not necessarily meet the same algebraic axioms; the library may not entirely consistent within itself. 
A typical case is the use of JSON to send around objects which use library-based inheritance frameworks. It is easy to reconstruct the property sets, but difficult to ensure that the invariants assumed by your class framework remain invariant after a round trip.

Monday, December 27, 2010

Another birthday past

I turned 47 today. It wasn't the birthday I might have hoped for, but it doesn't seem like I could have expected much more.

The weather was rough this week-end, but the roads were mostly clear and I planned on going in for a half day at least. My son wanted me to drop him off at a buddy's house, which meant he wouldn't be home. His mom asked me, obliquely, if I had wanted to drive her to work, to which I replied not really and made an unwise remark about what a wise aleck she was being. She called me a jerk, and left a bit later. On my drive out my son wished me a happy birthday, which was poignant. So that was how my day started.

I went in to work for the morning. Nothing special, just some debugging to figure out why someone else's home-brewed JSON parser wasn't actually doing the right thing by failing to properly initialize Prototype.js object's base classes. I figured it out but it didn't get fixed. It is not my place to set that priority as yet, but still -- it is the difference between doing the right thing and making things work for right now, that can bite you later when you are no longer looking. Deserialized objects should always be constructed the same way any other instances of classes are; anything else is a proximity fuse code mine.  So that was the second part of the day.

Plans to have lunch with a friend were interrupted at the last minute due to fear of the previous weekend's weather. I don't blame my friend, but it was unexpected and I was looking forward to having a good conversation.  Instead, I spent much of the rest of the day alone. I took a late lunch out and chatted with the restaurant owner, but it wasn't the same. I read up on Hobo and got a Jasmine gem to install properly, and looked over how JSON should (really) deserialize... finding that people don't seem to do it right at all in most cases, at least not with respect to higher-order class/inheritance constructions implemented at the Javascript library level. It continues to amaze me that people do mud-pie programming in Javascript and pretend that there is rigor and soundness to what they are doing. So that was the third part.

Checking messages, a few people wished me a happy birthday. My mom, her sister, and my sister called to say the same. That's nice. Not unimportant, but they all seem so... distant. Well, they are distant, but we don't really have much in the way of enriching conversation going on either.

Later, my wife got home early, and needed to vent about the goings on at her place of employment. Lots of dishonest communication in the workplace, compounded by a general lack of integrity, unrealistic goals, and hidden agendas, make it pretty rough for people to have a satisfying workplace life. When management and practitioners accept false premises for arguments, the fallacies inevitably compound and accumulate like waves cresting and crashing back upon a beach. It wears you down personally, and slowly undermines whatever solid thing you do manage to build. I got to hear about it, and offer consolation and comfort.

She got me a present too, a ceramic grinder because I grind nut mixes. Nice thought, but it was from the local mall and, as it happened, gummed up within about a minute. OK for fat-free things maybe, but not nuts and cocoa beans. I spent the next hour cleaning it out carefully before re-wrapping it for a return. I thanked her for it, but given the price (over $60) it did not seem like a keeper.

She put the TV on. I've come to hate TV. It isn't my choice of spending any evening, let alone my own birthday. It is icy out now, the roads are dangerous, so there is no going out. I lay down on a love seat in the other room to reflect on the day.

She puts the dog out and goes to bed early, not saying much otherwise. She doesn't seem to be angry or bothered in any way, just indifferent. Sigh.

I wonder how to improve upon what seems like a completely hideously unsatisfying social life. I mean, seriously - being alone all day???  It isn't reasonable. It isn't healthy. It just isn't right.

Blogging about it seems like a good enough idea, at least to help me reflect.  I wrote once before about analogies in fiction, how there are often disturbingly concrete mappings to reality. Today was a day in the life of Robinson Crusoe. I tilled the soil, planted corn, minded my traps, said my prayers, and spent the balance of my time thinking about what else I could do to improve my situation and do more than merely survive in isolation.

Normally that would be enough, but today was sad and lonely, and here at the end of the day I'm just glad to say it is over.
And I have seen that there is nothing better than that man rejoice in his works, for it is his portion; for who doth bring him in to look on that which is after him?

- Ecc. 3:22

Saturday, December 25, 2010

Christmas Spirit

Standing in the doorway, early snowflakes 
falling gently down. A quiet violence lights
the nighttime sky. Our darkness was long ago
stolen by the kings of business and commerce.

Their light could not illuminate, only confuse and irritate. 

Meltwaters dripping slowly from the eaves. 
The TV fades into the distance, no video 
succubus to steal the soul of our conversation.  
No conversation left to be had. Just drips
of ice water punctuating the silence.

Friday, December 24, 2010

Storage without the GitHub price

So, I'm looking at GitHub and thinking, "It's a great service, but what are the other options?" Their micro plans are a very good value at $84 (USD) to $264 per year, but I just purchased a 1 terabyte LaCie NAS for about $150, and I'm already paying about $60 per month for broadband access to my (home) office. Would self-hosting my own space make sense?

The main disadvantage of using an office-based solution, in two words, is "lightning strikes". Most office equipment is exposed to higher risks of electrical surges or direct strikes, especially when it is located in a residential building. Forget about what uninterruptible power supply companies and line filter vendors will tell you -- if lightning strikes any utility connected to your home, chances are good that their equipment will be the first, but not the last, to be taken out. Lightning can travel miles through air, so a 1/4 inch spark gap isn't going to be much protection.

And computer years are logarithmic, especially the consumer-grade stuff most of us use at home offices. A lot of equipment is just going to fail after a couple of years. At three years, odds are much better for failure. At five years, even if it is still running your equipment will appear to have been purchased eons ago and you'll wish it would fail. I don't look at my LaCie NAS so much as an investment, as a necessary expense for the sake of quickly restoring my MacBook Pro. It just does not pay back to deploy mission critical services on an ad-hoc platform.

Especially if it is your mission, you'll put in way too much time to fix and maintain the platform. It is certainly fun to hack devices to get, eg, git running on a NAS device, but unless you are using that knowledge to build a salable infrastructure as a paid service, it makes no sense at all to pursue. It isn't your core competency and you don't gain competitive advantage by doing things in a technically curious but otherwise inferior way.

Finally, vendors make it hard all the way around to deploy your own micro services. Broadband providers are well known for limiting what you can do with their bandwidth. LaCie blocked a Webdav based hack to enable ssh access (and hence a GIT install), because it was also an obvious back-door security hole.

So a home-brew solution is really kind of stupid on its face. The one valid reason for doing it at all, is if your technical curiosity leads to a genuinely better way of managing your data. I can see a massively distributed peer-to-peer rsync like service being a way for micro businesses to avoid dependence on large data centers. Again, as a curiosity, perhaps, but that is a far cry from a sensible operational strategy.

Interestingly, though, LaCie offers an alternative in the form of Wuala (pronounced like the French word "viola"), a service offering encrypted file storage space. Wuala is very much like DropBox, and reportedly has faster throughput. One other attractive feature is that you can trade excess storage capacity on your LaCie NAS for space for cloud space... in effect by allowing a section of your NAS to be part of the cloud itself. Not sure I want to trade my bandwidth as well, nor risk getting on the radar of the broadband provider.

Tuesday, December 21, 2010

URI Knot Theory

It is proposed to use language developed in the theory and practice of knots, as a primary metaphor for the architecture of the Universal Resource Identifier.

Introduction
As remote as mathematicians and topologists can bring Knot theory, the practical application is immensely approachable to most people. At the very least, they understand implicitly how useful and at the same time challengingly complex it can be to arrange loops in strings of tensile material. URIs are strings, and tie together the World Wide Web through a process which involves pulling &emdash; which is to say tension &emdash; as the primary means of establishing connectedness. That is to say, URIs are knots.

The study of knots is at once both a highly developed intellectual pursuit and a supremely pragmatic, almost purely mechanical skill. The architecture of a knot determines its strength, aesthetic beauty, elegance and approachability, and ultimately whether it has any utility in practice. The art and science of knots goes back into prehistory, and thus it evolved a language and sets of patterns that well-describe thousands of years of problem solving, where the problems involve tying things together. Thus, the language of knots should be a rich source of language well-adapted to the problems of designing URI architectures.

Background and Overview of The Language of Knots

From the perspective of analyzing the mechanics of a knot, it is conventionally decomposed into the following parts:
Bight
Bitter end
Loop
Elbow
Standing end
Standing part
Turn
Working end
Working part
As a hint of the fecundity of this language, consider briefly the idea of the "Working End" of a line: it is the leading portion which allows further extension of, and adaptations to, the knot. Just as some knots can be constructed in the middle of the line, it is predicted based on the metaphor that some URIs can be constructed as fragment taken out of a continuous string, without access to the working end.

At the time of the first draft of this post, August 3rd 2010, a Google search indicated no results on the query ' knots "uri architecture" ', and similar searches failed to produce any results. I have yet to do a formal literature search, but the Google results suggest that it is an idea which is not thoroughly discussed, and is perhaps a novel contribution.

Types of Knots

The common practical (or alternatively, the mathematical) classification of knots can also provide a meaningful working language for URI architectures. The list is from the Wikipedia entry on knots. Considering what each might mean in a Knot Theory of URI architectures leads to interesting possibilities for enriching the language of addressing on the Web.
Bend 
A knot uniting two lines (for knots joining two ends of the same line, see binding knots or loops).
Binding 
A knot that restricts object(s) by making multiple winds.
Coil 
Knots used to tie up lines for storage.
Decorative knot 
A complex knot exhibiting repeating patterns often constructed around and enhancing an object.
Hitch 
A knot tied to a post, cable, ring, or spar.
Lashing 
A knot used to hold (usually) poles together. 
Loop 
A knot used to create a closed circle in a line.
Plait (or Braid)
A number of lines interwoven in a simple regular pattern.
Slip (or Running) 
A knot tied with a hitch around one of its parts. In contrast, a loop is closed with a bend. While a slip knot can be closed, a loop remains the same size.
Seizing 
A knot used to hold two lines or two parts of the same line together.
Sennit 
A number of lines interwoven in a complex pattern.
Splice 
A knot formed by interweaving strands of rope rather than whole lines. More time-consuming but usually stronger than simple knots.
Stopper 
A knot tied to hold a line through a hole.
Trick 
A knot that is used as part of a magic trick, a joke, or a puzzle.
Whipping 
A binding knot used to prevent another line from fraying.
I will discuss more on the applications of this language to problems of URI architectures in follow up.

Sunday, December 12, 2010

On-line Meeting Options

Recently, a member of the Raleigh-Durham Web Design Group challenged me to hold on-line meetings for the group. I'm really interested in the the physical meetings, and remain a bit skeptical that on-line anything is a substitute for face-to-face interaction. Yet there are some interesting possibilities.

It makes me curious: what does "on-line" really offer us? The mundane features seem to be

  • screen sharing (with or without keyboard and mouse pointer sharing)
  • instant messaging
  • conference calling
  • videoconferencing
  • presentation or application sharing
  • session recording
  • whiteboarding

Personally, I've never seen a high-tech conferencing option that doesn't suck compared to the elegant simplicity of a low-tech in-person meeting. But that's beside the point: on-line services are not a substitute for human communication. The members who are asking seem to be saying that the costs of attending in-person meetings outweighs the reward... but some of them may be willing to put out some effort to meet on-line instead.

We are a volunteer group, so free or low-cost alternatives are attractive.  Members use PCs, Mac, and even Linux systems, so single-platform clients are ugly.

Some of the more obvious options:
  • GoToMeeting
  • Join.Me
  • DimDim
  • Yugma
  • Mikogo
Of these, Yugma's free offering stands out. It integrates with Skype, and allows up to 20 participants on-line.


We are looking for options. What are they?  Is there anything better for remote members than screen sharing? What's the latest and greatest in telepresence? What features are bloat and what do people actually use in practice? 

Friday, December 10, 2010

Social Networking and Propagation of Ignorance

People tend to think of ignorance in terms of something absent, as a gap or a hole in conceptual space. That's a pretty ignorant view of ignorance.

Ignorance, by its nature, is represented in peoples brains by neural patterns, is exchanged in communication, and is clearly evident when mob-think pervades Facebook discussions.  Urban myths are ignorance encapsulated as the stories of our modern apocrypha.

Ignorance, when realized consciously, can be variably hope, fear, or some other longing, but never faith, confidence, or trust. Without knowing what others don't know, ignorance is not just bliss: it pervades everything you say and do rather deeply and very materially.

Fighting ignorance with ignorance is not like fighting fire with fire. It is more like burning your neighbor's house down because you see fire on the horizon. That strategy is not very likely to be successful, even if it you are taking action.

This is the truest danger of social networking: ignorance is a learned meme.

Wednesday, December 8, 2010

Unnatural Bifurcation of Progressive Enhancement vs Graceful Degradation

I'm working a couple of projects out of NC State University, where Universal Design is not just a buzzword, it is a whole design center.  We recently discussed priorities for an HTML5/RoR Web application (in a nutshell it is to be a social delivery vehicle for giving diagnostic assessment to kids), and the subject was raised.

We are dealing with many different mobile devices, and the problems we are face are an extension of those  seen by designers working toward different desktop platforms and browser combinations. That brings to mind several other philosophical approaches as well, among them Transcendent CSS and Yahoo's Graded Browser Support.

NCSU incorporates its own design philosophies into Universal Design, so I don't want to mislead the reader, but my comments are not about any one philosophy but about a tendency among all of them to take the problem as a single dimension and premise the solution as a two-partition.

More specifically, quoting the YUI Graded Browser Support article:
Graceful degradation prioritizes presentation, and permits less widely-used browsers to receive less (and give less to the user). Progressive enhancement puts content at the center, and allows most browsers to receive more (and show more to the user).
In our case, the application is perceived, navigated, and reasoned about as an application with a set of behaviors and data to be stored and retrieved. Both "presentation" and "content" are second-class citizens; the behavior of the tooling takes precedence by an order of magnitude, overshadowing all else.  Whether that is right or wrong, that is the way it is on many if not most Web application projects.

My point is certainly not to argue for or against a focus on tooling; rather, that in any dynamical system it is the trajectory that is being followed that is of interest, not any one static coordinate. Content and presentation are coordinates in the space, and don't really give us the conceptual tools necessary to analyze the trajectories of moving objects.

The bifurcation is unnatural, and one might suspect it is because it is being applied to applications whose meta-model doesn't really track that of the Web. They work, not because they treat their information as content or cleanly delineate content and presentation layers, but because they use model-view-controller architecture.

Hence, there is a tension between understanding these applications in terms of content (and the two philosophical approaches to making designs adaptive), and understanding these applications in terms of behavior. For the most part, the applications, by design, ignore content as means of integrating behavior and strongly favor an explicit, imperative approach to sculpting a system.

There is really nothing progressive about imperative coding; really it is rather old-school.

Monday, December 6, 2010

Hobo: Play play play, edit edit edit, do stuff...

So, I'm about ready to do something grounded with the Hobo/Heroku/Git/RubyOnRails/Rails technology stack.

One of the really sad things about the present state of Web technology, is the amount of preliminary technology stack setup that has to go on just in order to get to the starting position. That's another series of posts right there, but I digress.

A cool thing about OSX is that it allows terminal sessions to be pre-configured to launch commands, then bundled into groups, so I can launch (a) a regular command window in which to run shell commands or rails consoles (b) a terminal in which to run the development server (c) a terminal in which to run Jasmine (d) a terminal in which to run rake, rspec, steak, cucumber, etcetera and (e) a MacVim with NerdTree; and have them all pre-configured with the right shell, Ruby, and Gems.   A featherweight setup for development of a specific application can be configured within a few minutes and launched with one click. But again, I digress.

Start up the server for Leapercan; oops -- my other logged in user has a Rails 3 app running on port 3000 -- need to use -p option to make this one run on, Idunno, port 3030.

/script/server -p 3030

Huh. MySQL gives an error:

Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

OK, this isn't the first time MySQL has gone AWOL under OSX. I'm still wondering why this is happening. Workaround seems to be: ps -ef|grep mysql to get the PID of the MySQL server, then kill $PID or kill -9 $PID to force the service to start a new process. Of course, MySQL has been installed to load automatically as a process upon boot, and to restart if it is ever killed. Killing the MySQL process works.

Ah, but alas, now it is really late, and I've got to pause again. Perhaps the next thing I'll do is create a questionnaire application -- something to play out 25 questions or so in order, and capture the results in a simple table. I'll use a one-time-pad to provide some measure of scope of access, to limit the visibility of the questionnaires to just those who should be authorized to fill one out.

I'll also need a time-limited list of authorizations -- basically just a mapping of user identities to scope identifiers.  Both elements of the mapping could be opaque, but the user identities should be supplied externally. The idea here is that an institutional user should be able to load up a list of authorizations for a one-time use.

Another aspect of the system: the user interface should be Web based and targeted toward mobile platforms, particularly the iPhone/iPad/iPod Touch or similar Android devices. It should not give any special consideration toward working on an IE browser or any other insecure platforms.

Sunday, November 28, 2010

Things I Don't Miss About Windows

After working on a MacBook Pro with OSX Snow Leopard for a few months, I almost go into convulsions when I am forced to tolerate the utter inferiority of Microsoft Windows.  Don't ask me which version: XP, Vista, or 7 are all just different colors of terrible.

Why?

While UNIX was a proven and well-understood operating system (OS) for mini computers, the original PCs were underpowered and had to settle for much less than a real OS. Yet UNIX had captured much critical knowledge about how to succeed at providing access to computer resources.  Support for multiple users, connectivity, and the security it would require were accommodated by fundamental design decisions built into its core.

Over years the feature set of Microsoft's OSs have expanded to cover many of the same requirements as UNIX, yet without the same level of consistency and performance as the latter.  The Windows OS line is itself probably responsible for more security breaches and real dollar losses expended in dealing with its security issues, than any other OS on the face of the planet.

Steve Jobs made a brilliant move in adopting a UNIX style core for OSX. Are there still flaws? Sure. But you just don't see the time robbing, attention wasting, excessive security risks that you are guaranteed to see under a Windows regime.

They say, "Time is Money,", but really it is worse than that. You will never get back the time you lose dealing with the short comings of the Microsoft platform. Best never to go that way, for down that path lies madness.

Friday, November 26, 2010

Industrial Strength Testing for Joomla Part 3

Under a test-first development practice when you're rolling out an add-on, you should also be rolling out a rigorous suite of tests to demonstrate that the add-on really works and satisfies some fundamental security and accessibility criteria.

Lacking such an automated test suite, it is not rational to expect an add-on to perform correctly. It is certainly not reasonable to purchase an add-on without the assurance that a test suite passes and can be repeated under your host environment. 

The truth is, most software is crappy. Let's posit a valuation function Crppnss(t) to determine how crappy a piece of software is, and suppose it is inversely proportional to the number of automated tests V(t): Crppnss(t)=1/V(t). That's a reasonable assumption. Although there are studies that suggest the relationship between latent bugs and number of tests is linear, even a small number of tests can have an impact much greater than a linear correspondence.

Since most Joomla components show little or no evidence of automated testing, it follows that most Joomla components should have high Crppnss. That is to say, the theory would predict that they should be quite crappy, and that is just what we see in practice.

Am I missing something here? No doubt. Yet I suspect that the Joomla/PHP testing cup will still be less than half full when I'm filled in on what I'm missing.

After my initial draft of this post, I did more research. Apparently PHPUnit and Selenium, with a Joomla specific runner, is the soup du jour for Joomla 1.6 testing. It is evident that the team has put in a good amount of effort to put together a rational tool chain and process. So the Crppnss for Joomla has officially gone from infinite in version 1.5 to less than one in version 1.6. 

Thursday, November 25, 2010

Industrial Strength Testing for Joomla Part 2

Following up to my previous post, I'm really regretting the lack of general testing facilities in Joomla. 

Curiously, the Joomla MVC framework doesn't seem to help as much as hurt. Unlike Rails/Grails/Cake etc the framework doesn't do code generation and doesn't speak to clean coding idioms. So you end up with the worst of both worlds: the constraints of a framework with the productivity of from-the-ground-up work.

It isn't that testing in the framework is poorly framed -- it is simply absent from the picture.  The developer shouldn't really be "rolling his own" when it comes to extending and integrating with a content management system. An active Joomla contributor could speak better to the test coverage and soundness of their PHP tool chain and technology stack, but I've seen little evidence that testing is handled with any rigor in the Joomla community at large.

Why do I bring it up? It costs a lot of time to fix stuff that other people broke, and I cannot afford to do that. I don't like doing it either. Foundations should be demonstrably sound and stable.  If you cannot demonstrate soundness and stability with rigorous tests, your are living in a magical pixie dust land where everything flies because you wave your hands and say it is so.

Wednesday, November 24, 2010

Let The Right One In

As I sit here in my favorite pizzeria, Anzio's, having downed one too many of the tasty circular sectors, I notice someone walk in the door that I recognize. It is the owner of a local auto repair chain, and a prominent member of the local chamber.

We've met a handful of times; his blank expression says that he either doesn't recognize me or doesn't want to acknowledge my presence through eye contact. Either way it is fairly strange behavior from someone in sales.

Now, ordinarily I might re-re-re-introduce myself, but I've gotten some very peculiar vibes from chamber people. Like they don't know me, and don't want to. There's something very icy about meetings that they and other organizations do as networking-for-networkings-sake events.

When someone doesn't want to acknowledge you it probably isn't worth a second thought. Like this blog entry. Ah well. No harm, no foul.

The second thought is this. I contrast his behavior to that of a sales clerk. During a visit to the local Tiger Direct, uh, sorry, "CompUSA", turning to speak to my son I heard someone say, "hey, I know you". Looking back, I immediately recognized a guy who had visited the Raleigh-Durham Web Design Meetup several months back.

The guy had taken a sales clerk position after a business venture failed to come together. We chatted briefly about a common problem of finding resources to pursue projects, about networking, and his new job, then he showed my son where some cables were.

What's the difference between these two people's perception of me?  One was approachable and open, and treated me as a peer; the other was absent and closed, and treated me as a total stranger. One was searching for business, the other had inherited his business from his family. One seems to have more money than the other, but I'm more likely to get leads and business from people who are open like the sales clerk than people who are closed like the auto guy.

We can and do affect how people perceive us through our initial contacts with them. On the other hand, no amount of contact will alter a person's integrity. Some people are just going to play you. Others will maintain an adversarial position and keep a poker face on, no matter what your intentions, altruism, or openness. It is best not to let those ones in.

Industrial Strength Testing for Joomla Part 1

Ugh. Developing with PHP seems like such a crap shoot, and the picture gets even more muddled if you try to work with a rats nest of third-party components. In general, the quality just isn't there.

My development environment for PHP bears some of the blame. I'm not a Zend user yet, though I probably should be. Still, like C and Perl, PHP seems to encourage inelegant coding.

One tool that I have used is VirtualBox. "What," say you, "does VirtualBox have to do with testing?" Well, for one thing, VirtualBox allows me to virtually reconstruct almost any hosting environment on my Lenovo T61 or MacBook Pro. The result replicates the hosting environment much better than a "WAMP" style native installer, compartmentalizes the services in a sandbox that can be put to sleep, and avoids application upgrade hell. It can even replicate the horrors of "open_basedir=." in its PHP configuration (that breaks a LOT of packages).

I've used the Joomla JumpBox appliance for a test deployment server, but recently switched to using the TurnKey Joomla appliance. Could I use shared or cloud hosting for test deployment? Yes, but the local virtual machine is private, fast, and can be junked much more quickly.

When used in the development cycle, a virtual appliance is, in effect, an industrial strength test fixture. But test fixtures are only a part of the solution to testing. A general purpose test framework is needed.

Monday, November 22, 2010

Hobo, Finally

During the previous setting up of the Heroku staging, I found out the name Heroku gave to my new application:

Creating afternoon-water-18...... done
Created http://afternoon-water-18.heroku.com/ | git@heroku.com:afternoon-water-18.git
Git remote leapercan added

OK, that's a bit strange, but I can deal with it. The name of my app as known by Heroku is "afternoon-water-18". 

I need a database for my Hobo. I choose MySQL, just because it makes me do something to set up. Plus, I've already got it installed. 

I update my Gemfile to include the mysql gem:
mvim Gemfile
2G
A
gem 'mysql'
:wq

then invoke bundler again
bundle install

Now to create the database:
mysql -h localhost -u root 
mysql> create database leapercan;
Query OK, 1 row affected (0.12 sec)
mysql> quit
Bye

I don't have a password set up for my database. I should. There's no excuse for laziness, except procrastination. I'll do that later.  The changes will go into database.yml . Since I don't have a password set up it should just work.

Now I call Hobo to generate the application:


hobo -d mysql leapercan

Lots of output. Well, everything is great, except that the app now lives under a subdirectory. I use mv to put the files up one directory. 

mv leapercan/* .
rmdir leapercan

There, that's better. Next time I'll do that a bit differently. 

I follow the tutorial from here, and create a hobo migration:
ruby script/generate hobo_migration
Unknown database 'leapercan_development'

Uh-oh... did I miss something obvious? Yup -- I omitted the _development from the intended database name... go back into mysql... drop database leapercan; create database leapercan_development;

Try again... looks good this time. It asks me if I want to generate or migrate now, or cancel?  I migrate now and accept the default migration name. Hobo takes care of running the migration for me, so I don't have to rake db:migrate at this point.

OK, so time to try it out a little:

ruby script/server 

A mongrel server is started, which we can visit at localhost:3000.  Very niftily (I know that's not a word): hobo has created a closed shell of an application with user accounts, and is ready to set up an administrative user.  Hobo feels more like a 4GL rapid application builder than Rails alone. 

I'm adding a model now. The tutorial is talking about Contacts, but I want to think about the warranty information I had to track down this morning.  I carry around keys and coins and never really have trouble finding them because they are either in my pocket or dropped into a bowl on the nightstand. I admit, sometimes I leave them in my pocket and dig them out before throwing the clothes into the laundry.

ruby script/generate hobo_model_resource pocket name:string content:text

Wow, it really generates a lot of stuff. A RoR purist might say it is a bit much, but I don't know enough to be that picky. I migrate again, same method as before:

ruby script/generate hobo_migration

Cool. Now there's a new tab for Pockets, apparently with the CRUD interfaces bootstrapped for me. I create a new Pocket, call it Leapercan, and put some application maintenance details in it. Stuff someone would eventually ask about, if they were asked to support the application.

It just works. That's a very, very nice quality.

Did I mention how little I value debugging? Debugging other peoples' code is like trying to understand and have a discussion with another developer by relaying the messages through a stupid, more or less insane, and completely soulless being. I'm in awe of people who can do it, but I'm finding I have less and less tolerance for stuff that doesn't work as expected.

The tutorial mentions how Hobo works at this point, automagically adding or removing fields and tables, based directly upon what it finds or doesn't in the models. To delete a table, just delete its model and generate another migration. You'll be doing the hobo_migration dance a lot during early development.

On the other hand, rolling back to a previous version apparently involves editing of the migration files directly and a  rake db:migrate VERSION = version_no  

It isn't much, but I'll push it anyway. Nope... Heroku says I need to run bundler. Bundler says I don't. What gives?  It tells me to look at http://docs.heroku.com/bundler... completely unhelpful advice... GoogleTime... looks like a common problem, but the advice offered doesn't work. Like, AT ALL.

git add Gemfile.lock
git commit -m "Added Gemfile.lock"

After several attempts at modifying the Gemfile, running bundler, and adding both the Gemfile and Gemfile.lock, git push leapercan master still craps out with that same error. Every Time. Even when I destroy and reinit the git repository.

Looks like Heroku is in the crapper at this point in time. It took me from a nearly seamless experience to an brick wall. Epic fail. Waiting, wondering, and - the thing I hate most of all - debugging someone else's code.

I'm starting to hate you, Heroku, and I hardly even know you.

So I start hacking, wildly guessing. I figure, something is lying to me, so I decide to do exactly the opposite of what it seems to be telling me. It says

   You have modified your Gemfile in development but did not check the resulting snapshot (Gemfile.lock) into version control



   You have deleted from the Gemfile:
   * version: 1.0.6

MISDIRECTION! I really wish that some programmers would learn to communicate better than brain damaged slugs.

Google had a lot of bad advice, utter nonsense, akin to cutting off a chicken's head and sprinkling its blood on the ground. The true reason for the problem is that Bundler records its version number in the METADATA section (which happens to be at version 1.0.6), and the bundler up on Heroku (version 1.0.3) apparently cannot deal with the fact that it has a slightly different revision level.  So I deleted the version number line from Gemfile.lock, and BAM, it just works.

WOOHOO!

Except... it didn't work. The command line says "yes" but the Web interface says something went drastically wrong. Wait. I forgot one more step: the Heroku database migration.

heroku rake db:migrate

Ah, such sweet release. All done.

The bundler version discrepancy reminds me of US EPA emissions requirements for commuter vehicles: not only do the requirements add to the cost and complexity of the auto, the emissions parts are directly the cause of most of the failures. How much difference is there between 1.0.3 and 1.0.6? Probably very little. Yet the version labels themselves completely HOSED the system. There's a lesson in there somewhere, about not enforcing something that doesn't really matter.

References
Rapid Rails with Hobo (Free from the Hobo site)


Sunday, November 21, 2010

Hobo on Heroku

Ok, so I'm toying with a Web application, code named "leapercan" because Leprechaun is not only unavailable as a domain name it is also difficult to spell.

Not that I claim to be especially proficient in Ruby or Rails, but I've been fortunate to help a really crack team of Ruby on Rails programmers for the past couple of months. I'm a dinosaur by comparison, but I'm picking up something along the way.

So I want to try something new, but RubyOnRails based. We've been using Rails 3 with all sorts of gems including RSpec, Steak, and Jasmine, and deploying with Capistrano. I'm looking for a solo app -- Hobo sounds interesting, and a free account on Heroku is an easy way to get started.

Here's what I've done and found so far.

Before anything else, note that I'm hanging back on versions so as to avoid having to deal with bugs at the bleeding-edge. My goal is to explore Hobo and Rails capabilities, not to debug them.

Debugging time is time mostly wasted.  Like an argument with your spouse once you've worked around the disagreement you generally forget why it was a problem in the first place.

First, I use RVM to manage my Ruby versions, but not the gemsets feature. So I install version 1.8.7 and set a .rvmrc up so that my work environment will default to rvm's global gemset for 1.8.7.

cd ~/workspace
mkdir leapercan
echo "rvm use 1.8.7@global" > leapercan/.rvmrc
cd leapercan

RVM now tells me that 1.8.7 is selected. Now, if I had other 1.8.7 apps on this machine, I might use a named gemset instead, to avoid polluting the global space; in that case, I would have used the gemset name instead of "global". Now that I think of it, that probably would have been a better idea...

I confirm it is using the right Ruby. As it happens, my system ruby is also 1.8.7, so I could have avoided the download. I check the version

which ruby

/Users/mamiano/.rvm/rubies/ruby-1.8.7-p302/bin/ruby



Next, I install the bundler, because it is just easier to list the right gems in a file than to 'member the nitty-gritty details in stream-of-consciousness mode.

gem install bundler

After that, I use my trusty MVIM to edit the Gemfile, and put in the gems we're expecting to use:


source 'http://rubygems.org'


gem 'rails', '2.3.10'
gem 'hobo', '1.0.2'
gem 'heroku', '1.13.7'


I'm a freakin' idiot savant, to have come up with the version numbers, right? Wrong. I used the fact that rubygems.org provides a RESTful interface to look at the all kinds of information about a given gem, and just plugged and chugged until I figured out which versions I could probably use without too much more trouble.  The format I used was http://rubygems.org/gems/GEMNAME , where GEMNAME was one of rails, hobo, and heroku.

Write and quit the Gemfile, and run bundler:

bundle install

Gahk! It complains about

Could not find gem 'rails2.3.10 (>= 0, runtime)' in any of the gem sources listed in your Gemfile.
Well, that's not right. I had omitted a comma after the gem name and version number, and bundler just concatenated the two into one string.  I correct the mistake and continue. 


After a while of downloading and installing, you'll end up with a bunch of new gems in your rvm maintained gemset. You can list these with gem:

gem list




*** LOCAL GEMS ***


actionmailer (2.3.10)
actionpack (2.3.10)
activerecord (2.3.10)
activeresource (2.3.10)
activesupport (2.3.10)
bundler (1.0.6)
configuration (1.1.0)
heroku (1.13.7)
hobo (1.0.2)
hobofields (1.0.2)
hobosupport (1.0.2)
json_pure (1.4.6)
launchy (0.3.7)
mime-types (1.16)
rack (1.1.0)
rails (2.3.10)
rake (0.8.7)
rest-client (1.6.1)
will_paginate (2.3.15)



OK. So, by now I've also set up a free account on Heroku, gotten a link to activate the account, and logged in. Heroku says I need to add my public SSH key, so I do:

heroku keys:add

Enter your Heroku credentials.
Email: mamiano@nc.rr.com
Password: ********
Uploading ssh public key /Users/mamiano/.ssh/id_rsa.pub


(Note that I had used earlier used ssh-keygen to create my public and private keys as part of a GitHub account setup. You don't need a GitHub account to use Heroku, just git. Google it if you don't know how.)

You can use "heroku help" to list a quick reference to the commands. I won't repeat them here.

Heroku says I need to set up my working directory as a GIT repository, so I do:

git init
git add .

git commit -m "LeaperCan: gold at the end of the rainbow"
 4 files changed, 63 insertions(+), 0 deletions(-)
 create mode 100644 .bundle/config
 create mode 100644 .rvmrc
 create mode 100644 Gemfile
 create mode 100644 Gemfile.lock

Now we need to tell Heroku about the new application. A helpful blogger has already run into the problem of using a slightly newer version of Rails than is standard on Heroku, and pointed out the command line to use the "bamboo" stack instead, which has my version of Rails on it:

heroku create --stack bamboo-ree-1.8.7 --remote leapercan


Git remote leapercan added


So, at this point, I've gotten myself a live sandbox to play in... I'm ready to actually play with a Hobo application.

To Do: Play play play, edit edit edit, do stuff...

Now suppose we have played enough that we have something to deploy. According to Kiwiluv, it is as simple as doing two steps:

git push leapercan master

And


heroku rake db:migrate --app heroku-app-name



Unfortunately at the moment my family wants attention and I'm just about out of play time.
Sigh. Rather than forget what I've just done, I take what time I have left and dump it into my blog, along with the references.


References
http://rubygems.org/gems/heroku/versions/


http://docs.heroku.com/rails
http://www.kiwiluv.com/techblog/?p=560
http://cookbook.hobocentral.net/manual/download

Saturday, November 20, 2010

A Smattering of Design Guidelines

Use the metaphor of resources to determine consistent, implementable URL and URI patterns for your pages. Sketch your site's map. But only just sketch.  If you don't understand how this relates to your design, consider that "pages" is just a metaphor itself and the branches of site map don't necessarily mean "page". 

Lay out for substantive content first. 

Get specifications for the devices you expect to support for access to your information.  Generalize the specifications into a set of parameters characterizing a category of media, rather than device.  Create a style profile for each generalized category of media space. You might have a Desktop space, a high-definition smartphone space, a low-definition mobile space, a tablet space, etc.  Consider each profile a proxy for one of your audiences.

Define your profiles incrementally. Choose a grid or columnar layout, and flow content into place.

Apply a strategy using Occam's Razor to your code:
pluralitas non est ponenda sine necessitate 
Which is to say, don't use more markup than absolutely necessary to convey the meaning of the message. Use CSS for style. Don't use DIVs for positioning or include other gratuitous markup for layout tricks.  Don't rely upon the relative positions and parent/child relationships in the markup for style or layout effects beyond in-line layout.

Include a browser reset. That will eliminate browser-introduced pluralities. It is regrettable that as of the year 2010 CSS3 and HTML5 still make it difficult to follow the Occam's Razor principle. But even a critic can see the situation is improving.

Use Behavior Driven Development with scenarios to storyboard the site. Why is anyone looking? What do they need to do?

Friday, November 19, 2010

Joomla means carnage

Man oh man. I just got done futzing around with an XML RPC service plugin for Joomla. What a nightmare, like slogging up to your neck in feces for four hours.

Thing is, it isn't that complicated a problem, but trying to do things the "right" way is what makes it virtually impossible to accomplish.

First, there is little published information that is in any way self-consistent. Please don't tell me about the so-called "Master ..." book for Joomla. It is spotty at best. The information might be there, but it is so poorly organized that you have to jump around in the book to patch it together, making it that much more difficult to judge if you've gotten the pieces right.  Still, one can muddle through part of the way on that.

Second, how do you test it?  There is no admin side functionality for testing the RPC interfaces you enable. Isn't it a little bit mission critical to know if they work?

Third, none of the Joomla APIs appear to be very stable. Write something custom for it, and you're most  certainly guaranteed that custom code will break when you update. At least, you'll have to test it thoroughly before updating any production system that uses your code.

Fourth, debugging this stuff is one epic hack after another, just for the debug environment. I tried the PHP XMLRPC debugger and finally had to give up after being roadblocked in three completely different ways.

First, the xmlrpc feature had been left out of the "hardened" php test server.

Then the Javascript based debugger started firing off "OPTION" requests because the test server was running on the local network (The standards working group that came up with the rule of sending an OPTIONS header aught to be taken out back and stoned for that particular hack. At least, the browser should warn you it is deliberately ignoring the method of your request and pretending to be brain-dead.)

Then, when things didn't work, the debugger doesn't give you details, it just says "Didn't receive 200 OK from remote server. (send failed)". OK, um, DUH. What failed?

Well, best not to continue. Down that path lies madness.

Request for Proposal, or, Trying to Bypass Design

Consider what an RFP for a house might look like, were it to be written in the manner of an RFP for a Web site or software project:



Request For Proposal

Requirements
1) Contractor shall construct one building shelter, to accommodate one (1) family including all bedrooms, a kitchen, dining room, and toilet(s).

2) All work performed must comply with industry standards.

3) Wood studs and gypsum drywall are acceptable materials for construction.

Proposals without detailed plans and estimates will not be accepted.


Do you think developers give you wildly varying proposals? Is your RFP process designed to get others to do design work for you for free? Then it masks your own lack of due diligence, and you will get every bit of design that you pay for.

Big Design Up Front is not necessary nor is it sufficient for a project's success. But you still need to take the process seriously. Such requests are a clear indication that the RFP writer is not at all serious about project success.

Personally, I think RFPs used to elicit design input without payment are unethical. The behavior is no better than asking one dentist to lay out a strategy for fixing your teeth, then paying another to follow the program without remuneration to the first.

Thursday, November 18, 2010

A Design Guideline


Use the metaphor of resources to determine consistent, implementable URL and URI patterns for your pages. Sketch your site's map. But only just sketch.  If you don't understand how this relates to your design, consider that "pages" is just a metaphor itself and the branches of site map don't necessarily mean "page". 

Lay out for substantive content first. 

Get specifications for the devices you expect to support for access to your information.  Generalize the specifications into a set of parameters characterizing a category of media, rather than device.  Create a style profile for each generalized category of media space. You might have a Desktop space, a high-definition smartphone space, a low-definition mobile space, a tablet space, etc.  Consider each profile a proxy for one of your audiences.

Define your profiles incrementally. Choose a grid or columnar layout, and flow content into place.

Follow Occam's Razor:
pluralitas non est ponenda sine necessitate 
Which is to say, don't use more markup than absolutely necessary to convey the meaning of the message. Use CSS for style. Don't use DIVs for positioning or include other gratuitous markup for layout tricks.  Don't rely upon the relative positions and parent/child relationships in the markup for style or layout effects beyond in-line layout.

Include a browser reset. That will eliminate browser-introduced pluralities. The Yahoo! UI library has one. Eric Meyer has another. There are plenty of examples.

Choose a dominant typeface family and style to fit the message, audience, medium, and purpose.  Use a san-serif font for body text, a serif font for headings. Align the sizing of both, since characters in two fonts will often differ in size. Use a font stack to specify the desired font, one or more fallback fonts, and a generic family as a stand-in. Carefully consider use of an OT/TTF or SVG Webfont with or without a foundry service like Typekit or Typotheque, or WOFF.

Choose a subordinate typeface for UI controls. Distinguish them with different colors or a different font family.

Determine word spacing, letter spacing, line spacing,

Use Em for relative sizes, but understand that one Em is equal to 100% of the font size property in effect within the context of the markup. So there is a cumulative effect of the settings.

Use proper glyphs for hyphen, en-dash, em-dash, and minus signs (I don't on my blog). Use the HTML entities for these and other special characters.  (See smartypants or typogrify.)

For text blocks and columns, use multiples of ems to set line width relative to multiples of characters. Aim for 10-15 words or 75-100 characters per line. Set line height with a unitless number so that it is based on the font size.

CSS3 may support hanging punctuation (quotes and parenthesis are hung in the margins.)

Check out webtypography.net, usabletype.org, alistapart.com/topics/design/typeography

Wednesday, November 17, 2010

Points vs Pixels vs Percents vs Ems

There's a saying attributed to Mark Twain that one should never argue with a fool because onlookers may not be able to tell the difference. I've seen a lot of Web people arguing about accessibility, design, and typographic units, and I am forced to agree with Clemens.

I'd like to see some compelling arguments. There are none. Units are units, and whether the browsers actually do the right thing or not is quite irrelevant to the question of accessibility. A site cannot be made accessible by hacking it to coincidentally work around defects in specific browsers.


Accessibility to a building is not a property of the bricks and mortar that make it up, but an emergent condition stemming from the challenges a person faces when navigating the patterns present in the structure. We cannot design buildings to address every challenge, so instead we create building standards to guide the minimum architectural feature set.

Similarly, accessibility of a Web site is not a property of the bits, nor is it feasible to design them to address every challenge faced by users - instead we have nascent standards for building-in accessibility by proxy, as a set of architectural features.

When we build our town halls and commercial buildings to ADA standards, what we are saying is that we expect certain patterns and relationships to be exhibited in the resulting structure. What we are not saying is that the door frames were field modified to accommodate an Acme brand Model 68020 wheelchair.  Nor are we saying that the door frames were field modified because the doors were found to be constructed of defective alloys. The first case is too specific to one assistive device, and second case is clearly cause to demand a completely new set of standards-compliant doors.

Changing style sheets and muddling with markup in order to make something "accessible" for a specific set of browsers is ludicrous. It also smacks of being way too touchy-feely, relying upon subjective qualitative ideation rather than quantitative assessment.

Either we develop to standards, or we don't. Hand waving about pixels being inaccessible, points being "just for print," or percentages and ems being superior, is missing that argument entirely.  If some feature of the site doesn't work for you, to the extend it is specific to a given browser it is not an issue of accessibility but a defect in the product... and we will all be better served if we stop making accommodations to defective products.

Tuesday, November 16, 2010

I'm Enjoying Ruby on Rails and BDD

Nothing beats writing tests first with a truly integrated framework like Rails.  Steak and Jasmine make it practical, even if they have their oddities. FactoryGirl, I'm not so sure about, but once it is set up it seems to be pretty reliable.

Done correctly, things just work. Done incorrectly, especially with FactoryGirl, side-effects can really clobber you and steal precious development hours away.

The case for concrete sizing




What people have to say about "points" in Web typography. Points...
  • are a "standard method" for print typography
  • may be more legible in print, less legible on screen
  • and page resizing may not work consistently in certain browsers
  • are not relative to changes in base font-size (smallest, smaller, ... larger, largest) 
OK, so I'm seeing the real problem here: lots and lots of Web designers are mixing the metaphors of Web layout as a formatting process and Web layout as an interface specification. 

Don't do that. 

If you are going to design liquid layouts with relative sizes, by all means, go ahead and play. Your designs are going to be beautiful, but then again no design on the Web belongs to the author. A design is always the merging of the intentions of the author with the choices of the user, within the limitations of a browser. So all that pains-taking is going to look great, but we know that by design it is guaranteed to break. 

The thing is, points mean something objectively. In modern typography they have been defined to mean 1/72 of an inch. Yes, that's an English measure, the only widely used measurement system based upon human factors. Like our calendar it is entirely based upon the pragmatic considerations western civilization determined centuries ago. It is flawed and odd, but it is objective and well grounded in our experience.

So, tell me again, why do we want to measure fonts in pixels or percents, when we want our designs to be accessible to humans?


Incidentally, the argument against points on the basis that Web typography must deal with multiple device formats and layouts, is fundamentally flawed. The world of print typography has far more media formats than Web browsing devices can shake a stick at, ranging from huge to tiny, and on many different types of substrates. Points work precisely because they are an objective measure that can be directly multiplied by a unitless ratio for scaling, and thus do not need to be re-interpreted for each formatting context. 

Sunday, November 14, 2010

On the ideal of networking

Thinking about some of the finer points of the IndieConf, on the ideal strategy of choosing several people and being helpful over time with the goal of establishing numerous positive interactions, thus building trust and establishing relationships.

Don't assume that payback from that strategy is uniformly distributed. It is most definitely not.

It isn't random either.

Nor is the payback going to be from the people that seem to be the most friendly, or those for whom you've put yourself out for the most.  At least, not at the start.

What you'll find is that most people are leeches, willing to get but not to give back. Many more will undervalue anything offer that doesn't have a price attached to it. And a great number will just simply be prejudiced against something about you that has nothing to do with anything, but will prevent them from ever doing business with you.

There were some key things in this respect from the IndieConf speakers on the subject:
  1. Intentional Pursuit. They chose who to pursue, and those they chose to pursue are people around the industry in which they wish to work.
  2. Quick Selectivity. They made snap judgments to quickly eliminate disfavored prospects from their list.
  3. Overt Spying. They made lists, and profiled the people they were pursuing.
  4. Low Commitment. They did not over-invest their time, their reputations, or their other resources. 
An example of #4 is that most of them mentioned, as the "positive interaction", sending an email note with an article of potential interest to their target, once every 45 days or so. They would review a list of their prospects once or twice a week, and with them in mind glean articles from RSS feeds and the "help a reporter"  site. If they found something they'd push out a note. Very cheap, low outlay of time and no commitment, but it reminds the prospect that you are there.

Yet, people will still forget you, ignore you, or even get annoyed at you. If someone doesn't respond positively, don't obsess or fret... just move on. When you find someone who welcomes advice but never reciprocates or who actively works against you, strike them from the list and pick someone new to network with.

I've spent a lot of time pursuing connections at our local chamber, and in town, with the hope of getting business. Now I see that I've done several things wrong.
  • none of the chamber or town hall people are in fields in which I'd like to work, or express similar interests
  • my openness, tolerance, and patience have been extreme; in particular I was too slow to weed out poor connections
  • no tabs were kept on people, or other personal profiles, though I did stay in touch, and
  • the commitment of my time and emotional energy in volunteering, offering advice, and making other resources available, was substantial and interfered with me earning my keep elsewhere
There were people I admire, people I connect with, but I've been passed over twice for major business that I asked for, and on the whole it has become an un-enjoyable experience. Time to move on.

Stupid Blogger!!!!

I hate Web based applications. Always, I get fooled into spending time writing something, only to have some random keystroke navigate away from the page and into oblivion.

AAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHH!!!!!!!!!!!!!!!!!

We need to put a stop to this crap. We use these freaking interfaces
ALL 
DAY 
LONG
 Why should they continue to be riddled with sucky design features. BACKSPACE causes you to lose all your writing? REALLY??????



OK, so, score one for Blogger. It saved the edit as a draft. (Insert begrudging Calvin-and-Hobbes grimace here.) It is still stupid to have backspace change the page. 

Another dump... old... from JS Camp...

 I didn't just want to leave this on my old laptop, but don't really have time to pick out the good parts, so here goes another dump...

HTML5 and JS APIs - MikeTaylr.com/code, /pres/ncjs, /pres/ncjs/apps

Constraint Validation
- form validation
- hooked through JS
- el.willValidate, .setCustomValidity()...
- el.validity object can be probed for information
- Opera currently supports 100% automatically
- examples used the new W3C querySelector api to query the DOM; jQuery does this internally if possible
- but beware that the built-in validations may be naieve ; consider foo@cheeseburger which looks like an email but cheeseburger is not a valid top level domain
- HTML5's email regexp is deliberately broken to make it accept the crap found in the wild

Pattern based validations

regexps are part of the spec
- you can hook into onkey and set a trigger to call a function that changes the valdity properties

Canvas
- 2D API for drawing bitmapped graphics
- 2.5D animated racecar example from Ajaxian
- Transformations, Compositing, Focus mgmt, Pixel Manipulation
- (painting)
- get drawing context, draw path, stroke; code looks like PostScript, or the bitblit from Win32
- higher level built-ins for common geometric shapes; strokeRect()...; or images drawImage(...), which can be manipulated through common transformations
- custom fonts loaded and drawable; some people are writing graphic editors in Canvas; bespin uses canvas text
- box shadows (which used to be in CSS3, not anymore)
- could Canvas kill "Flasturbation" ?
- "modernizer" does feature detection
- for IEn there is Google XCanvas for compatibility, using VML to emulate canvas
- Google working on a Flash replacement for XCanvas
- can save as a base64 encoded PNG or JPEG, for local storage or export
- cannot save images loaded into canvas if they were loaded across domain; pixels are tainted

GeoLocation
- supported by iPhone, FF3(?), Opera10.5+)
- getCurrentPosition(successf, errorf, opts); watchPosition(sf,ef,opts)
- three options
- position.coords object gives detailed positioning information
- use to dump into Google Maps, get map of curr. loc
- always asks for explicit permission
- depends upon the device's means and algorithms used to determine its position; triangulation, phone gps, routers capabilities, etc



JQuery UI
Overview; draggable, droppable, drag-and-drop or revert; uses callback event triggers defined to watch events; resizeable, constrained dimention resizing; etc etc etc
- Most events should be cancellable; those which aren't are b/c of bugs
- they have a set of sample icons in their CSS framework
- autocomplete plugin; can bundle the original input along with the autocompleted value and rendered labels to avoid additional lookups
- behaviors of plugins is overridable by defining handlers for the events and returning false to block the default behavior.
- plugins generally use the static markup on the page and applies styles; button for instance can be applied to almost anything
- unsupported combobox plugin is also in the autocomplete demo
- Datepicker plugin allows i18n for calendar; also multiple calendars
- currrent discussion on-going for i18n across the entire library
- dialog plugin looks nicer, more controllable than alerts; can be applied to any element with any content; can make modal or non-modal dialogs;
- progress bar ; simple; has callback event triggered whenever value changed so listeners can pick up on status changes; animated backgrouns allowed - just use CSS and image trickery
- often features are really accomplished by using built-in style capabilities like overflow; jQuery avoids setting most CSS properties except for dimensions.
- they focus on high-value features which require considerable amount of code to implement, not on one-liners
- Position plugin coming in 1.8: relativistic positioning; !!! hot !!!; will not redraw, but if you bind to the window resize event, you can call to the positioing function again.
- "testswarm"?
- CSS stuff for JQuery done by "Filament Element"
- ARIA: jquery ui should be compliant by 2.0, partially now; with assistance from Fluid




Storage and MVC Applications
Claypool MVC framework; full app stack in JavaScript, HTML DOM
- well, sort of. Actually runs off Java app container; Jetty included
- data source can be client site via Gears or other offline api; FF, Chrome, Safari, IE8 may (modernizer.js will check); and HTML5 thing
- localStorage.setItem(id, jsonstring )
- ~.getItem(id)
- not a very formal query language, just a simple api; need to provide access methods which stringify and parse it; the model must manage the serialization of stored properties to and from strings in storage; note that changes to an array of ids via self.delete will cause reordering , so that the indexes returned in the array by this.ids() are invalidated.
- includes a debugging trace facility that need not be removed afterward
- crash and burn due to FF incompatibility with the storage api
- proxy (ruby)

Saturday, November 13, 2010

I reject you, Perl

So, I'm piddling with some tiny shell script, and decide to substitute in some perl instead.
'cause, I'm just a sucker for a language that looks like it was designed by a thousand drunken monkeys.

Well, so, anyway, I find out that this doesn't work as I'd expect:
perl -lne 'print $ARGV[0]' filename

When called with -e argument, $ARVG[0] doesn't equal the first argument to the script. Really?

It is supposed to be an array of command line arguments. Unlike every other language that uses an argv convention, Perl doesn't include the name of the command in the array, but I digress.

When you run Perl with the -e argument, it magically changes.

The rationalization for this design feature are no doubt tucked into some dusty corner of a list server, but who really cares?  It is different in a way that seems gratuitous and more than a little astonishing, so even though it was an ancient decision, it still seems rather stupid.

Everything needed could be done in shell. Anyway, other smarter and smaller languages exist. I have options.

So when I'm stupid enough to bother with a massively bloated interpreted language like Perl, and it decides to astonish me with a really poor implementation design decision and unexpected behavior, rather than blame myself and accommodate the idiocy of the language, I reject it.

Attending IndieConf

Wow, there are a lot of fat people here. I'm one of them. There must be a market to sell to here: health maintenance and improvement for independent workers!

I'm dumping notes here. Please see the conference site for links to the really good stuff.

Patrick O'Keefe - Marketing Yourself in online communities
Why
- you can differentiate yourself much more easily than in a global space
- you get people who are self-selected as interested in a specific subject area
- those participating in online communities are much more influential in decision making, sharing advice

Prerequisites
you have to be personable
be able to communicate well
not be resentful of authority but work well within the norms of the community
be able to not talk about yourself, post links to yourself
you need time, and keep plugging at it persistently on a scheduled basis
you should enjoy the topics of the community in which you participate
the community should allow you to fill out a profile, link to details about your business


Four categories
community of your peers, within your industry
an industry you want to reach, not your own, something specific
 - not in general, programmers
 - you can use this to stand above the rest and offer information
local business communities
 - local service businesses
small business communities

Becoming a member of the community
You have to enjoy it enough to participate for at least a half hour a week or more; if not, don't bother.
Pay attention to the guidelines and norms, and be respectful.
Fill out your profile; that is where you will get benefits; if it doesn't allow you to link to your own site, don't bother; make sure the site allows signatures and put your links there.

One of the attendees asks, how to recover from making a faux-pas in a discussion about a technical question? The answer comes back,  remember that any posts are to the entire community and will hang around potentially forever; don't get in nasty arguments but agree to disagree and decide if you want to to be a "know-everything" person.

Building a Reputation
"Do good, whatever that means for your brand."
Help people. Demonstrate knowledge by answering questions.
So that when they need your service, they will think of YOU.
Use Google to track for referrals from your signature links

Michael observes the effect of being considered a perpetual "newb" after starting by asking basic questions. How do you overcome that long term? "One idea might be to start a new profile" - not recommended - mainly because many communities consider multiple accounts as a bad thing.  Patrick doesn't think past posts will hurt in that respect, if you are continuing to participate and gain credibility.

What's the ROI of online community participation?
 - note that online conversations last for a long time, are seen by many people, and can be responded to long term
 - credibility
 - book deals
 - other peripheral benefits you could not foresee
 - association of you with a given service

"Anonymity is the enemy of a good online community... but it is not for business professionals... part of being a professional is putting your name [on what you do]...".

Patrick notes that he once bought 67 of his own book from Amazon, because it was cheaper than the publisher discount, and it pushed his ranking up to 200th place. Note: How to rank a book up on Amazon.com: buy a few tens of copies of it.


Mital Patel - Legal issues - www.TriangleBusinessLaw.com
(Mital is using Presi.com, looks really neat.)

- leaping in; employment issues; noncompetition/non-solicitation agreements; intellectual property

Which form of business? Sole proprietorship, LLC, S Corp, C Corp; (need operating agreement articles of incorporation, bylaws, meeting minutes, EIN)
Tax differences: LLC is simpler to operate from a paperwork perspective, but there are differences in how taxes are done.

Contracts
 - Payment terms: Retainer, Net 30 or Net 60; best to ask for a deposit for some fraction of the work; you will save yourself a hassle if client cash flow gets tight later.
 - Representations and warranties: underpromise, overdeliver
 - Subcontractors: employee vs independent contractor; always use "independent contractor" if that's what they are; don't use "1099 employee" too lightly.
 - Indemnification: limit your liabilities if things go wrong; guard yourself against what could happen if client provides incorrect data or misuses the software;
 - Choice of law; specify your home locale to use the "home court advantage".
 - IP: selling vs licensing; selling means the client owns everything and can bring someone else in to work on the software as a competitor to you; licensing indicates your client has terms to use it, but you may have the ultimate rights to it. Suggestion that licensing is the often the most advantageous model.
- Make sure IP is spelled out; the law doesn't say by default who owns code. Commonlaw copyright gives the author rights; you need to make sure those things are spelled out.

A question comes up about the enforceability of IP ownership agreements regarding work and product done in your own time/resources. The answer comes back, it depends on the state and agreement.

Forms of IP law
Copyright: written expression; "work for hire"; Photographer automatically owns the copyright; use the words "Work for Hire" and assure the copyright is assigned to you.
Trademarks: Name and brand symbols for your business; domain name alone is not a trademark use;  "likelihood of confusion" test; check state trademark registries; Also at federal: USPTO.gov. A commercial search will cost a few hundred dollars.
Patents: not as common for independent developers and designers
Nondisclosure Agreements (NDAs): avoid giving away your business model; venture capitalists and angel investors will get offended by them; hard to enforce but often having them in place keeps people in line.

Growing: hire slowly, fire fast, and use solid employee agreements: non-competition, non-solicitation; don't want employees jumping ship and taking your clients.

Brandon Eley - Effective Networking for Independent Contractors

"Networking gets a bad rep"
- Introversion is no excuse; people will attend conferences and not mix socially with people.
- Freelancers may consider networking events to be too time consuming.

His mom kept 3 ring profile binders on each customer, detailing every aspect of their lives; she'd use these to find customers to market to personally and proactively.

His initial network: calling parent's friends, relatives, and worked from there word of mouth.
Prerequisite: you need to maintain relationships with people, and keep up with them over years. Build relationships.

Basic principles
 -"emotional bank account" for each person you meet; you need to make deposits by helping them in some way; Goal in attending events should be to walk out with a new relationship.
- give first; at least five substantial times before you expect results from them and build trust
- give often; and consistently; pass on leads
- don't try to connect with everyone; people max out at about 200 people they can keep up with on a regular basis; look for the people you have common interest; invest your time in those that are really promising

Online communities
 - LinkedIn; puts everything he does professionally on his public profile; links to those he feels worth networking with; asks those who comment on his presentations to give referrals;
 - Facebook; a social networking antipattern; uses it only for personal social interactions, semi-privately; but you cannot rely upon it being private. Be Extremely Careful.
Pepper O. points out that for a female small business owner, not having a Facebook page is a serious omission.
 - pick niche communities related to topics that your intended customer base will want; forums; where are your perfect customers visiting?  Plaxo has many small executives; inside919 has many small businesses;

Offline communities
- Pick where to go; don't go to places you won't get valuable contacts or run by a referral group; target places with specific topics; Meetup.com ; twitvite.com, regional conferences;
- look to get 10 connections and try to keep up connections with those people over time
- go into a conference with a friend, someone who knows different people than you, and introduce each other
- don't "pitch" your stuff; ask and listen more than you talk
- don't be a business card ninja; only keep cards if someone wants to keep in touch; it is just annoying
- AVOID referral groups, as if your life depended on it; you need to build relationships instead
- don't hang around with your nose in a phone or a laptop; put the smartphone away when you're in the hallway; talk to people; smartphone as a pacifier.
- FOLLOW UP. Number one thing he expects is that 95% of the people will never contact him. The only thing worse is people who spam him before he gets back from the conference; like monthly newsletters
- DO NOT SPAM. that's like overdrawing your account

Keeping in touch to build a long term relationship
- Connect > Followup > Provide Value > Keep in touch
- Sends hand-printed note on a card to people;
  - carries a space pen to write on glossy business card to jot down how he met a person;
  - just write a few words to trigger
  - Sends an email as an alternative; if you don't have the address or it is not quite appropriate to send a card
- Follow up: (mentioned sending a client note at a rate of 4 articles over 6 months) works with a pool of about 10 people and scans feeds about once or twice a week to see if there is anything of interest to someone in that pool; might also use a CRM system and tag the prospect with their interests;
- Provide value:
  - see articles written in their industry, send them on with a quick personal note;
  - maintain practice over a period of time; send consistently
  - "helpAReporterOut.com" - sends out notes periodically on different industries; send to clients; copy and paste a link
- After you have established a relationship, ask for business; call up and ask to talk over coffee; ask if you can show them what you have to offer; ask for leads

Use Software to leverage and extend your memory
Uses "Highrise" CRM; keeps track of profiles by bcc of any email you send to the client;
Zoho and SugarCRM are more advanced.

 Stop looking at yourself as a salesperson, and look at it as building a relationship with people.


LUNCH

AFTER LUNCH

Doug Foster: Convince ME!
www.theideamechanic.com

Think like the buyer. Don't think like a seller.
- Ask yourself, "Why should I buy what you are selling?"
- WII-FM: What's In It For Me? Make you Money? Save you money? A need or a want? Leverage? Security? Why are you looking at it?

As a buyer, I expect you to know
- My industry; My business; My pain

How do you sell? A process:  -> Foster-> Find -> Educate -> Close ->
Closing is really just asking for the business. Don't be afraid to ask.

Find:
 - Talk; whenever you get the opportunity, share what you do,
 - Hang Out at watering holes, meetups,
 - Network ; check out Triangle interactive marketing association TIMA
 - Subscribe: RSS, MailChimp
 - Get social

Educate. Once you have a prospect, take them on a trip: tell your story; show proof; try it; satisfy completely

Close
 - deciding is logical but buying is emotional
 - "I" will convince me;
 - No buyer's remorse; don't badger and box the prospect in to buying something they don't want. You don't want the client to feel like they had no choice.

(Show's Johnson Automotive Badger commercial as an anti-pattern.)

Foster
 - Ask a lot of questions after you complete the deal
 - Listen to the answers completely
 - FYI - send out notes every now and then to remind prospect that you are thinking of their needs, something that is of value to them
 - Deliver and manage expectations; get the cycle down to do less selling and do more delivery
 - Fix; don't be afraid to admit when things go wrong and jump onto a fix for it.

Plan the Trip
- "If you don't know where you're going, you're going to wind up somewhere else" - Yogi Bera
- Know Me, Know my story, Know my backstory
- Who/What/When/Where/How/Why/How much
- Ask, "Why should I make this trip" metaphorically. What will I see? Do you know my points of interest, and will we pass them along the way? Who else is along for the ride?
- I only have so much money and time.
- Are we going down the street or around the world? Are we there yet?

Tell the story
- Scenarios; a way to predict possible alternate outcomes; "The Art of the Long View" by Peter Schwartz; how might the sale go?
 - Plan alternate routes for roadblocks and shortcuts... if they say "go", then close and move on
- Short Stories that Sell; innately, we love flawed characters;
- Our brains are wired for stories (and pictures)
- "The back of the napkin" Dan Roam; brain wired to process at different levels who/what, how much, where, when, how, why

What works better, on the phone or face to face? If you know the person, phone is fine; otherwise if you can get a face to face meeting jump at the chance. You can't beat a face to face.

- I want to know "your" story as a buyer. It should be unlike anyone else's story.
  - Your story aught to overlap, so it becomes (y)our story.
  - Fit the story to the location and situation.

Speaker says "My story is, 'I help people sell'"
A good story:
 - invokes emotion
 - memorable
 - length, width, depth
 - truthful - what is just an idea? what works now?
Goal is to start a conversation, threaded with other stories; nobody likes a monolog.

7 layers of how to tell a story (The OSI model)
Application Purpose, conversation
Session Media, audio, video
Transport Delivery: best effort or guaranteed?
Network
Link
Physical

(Bank of America story, 160k IP phones in 10 minutes)

Show proof: why should I believe you?
- buyer may be smarter than you
- be honest; assume you are the dumbest person in the room
- build trust with repeated truth telling
(speaker going too fast here)
- demonstrate
- pull out a success story; 1st hand best; 2nd hand good; make it viral

Try
- if seeing is believing, trying is buying
- make it an engaging experience; make it real; make it a WOW
Dance or watch, watch or try
- "Good" a crowd experience of a random gathering
- "Better" a community of interest experiencing, concert or conference
- "Best" a personal experience

Educate
- Questions are good; good conversations have questions, even tough ones
- it is the start of a conversation;
- Concerns are a great thing
- where can buyer go to learn more?
Ask me, listen to me, respond to me directly

Only 2 questions count for buyers: did I buy? Would I buy again?
What if the buyer is not satisfied? Some people are never satisfied.

A customer that is satisfied and remorseless, will be your best seller.
- Slides are up on slideshare.

Rebecca Murphy - Git and Tickets
or
"tools for getting better paying work"
"tools for getting better customers"
"cya"

"I can't work without them anymore"

(complicated email thread with two or more tasks emerging from it)
- had learned to tolerate terribleness and accept whatever was thrown
- morass of emails, downloads, labeling, everything mixed up in the inbox

(describes clumsy process using zip files and many overwritten files, no ticketing system until late in the process, and no version control)

Lesson learned:
- email is evil: a ticketing system brings sanity to client requests
- mentions "assembla" as a ticketing system
- no context switching is required when using the ticketing system; whereas emails presents very many distracting emails vying for attention; narrowly focused to one client needs
- you can assign priorities to tickets (* but: some clients think everything is high priority)
- you can propose a new status, and requires sign-off by a client
- you can assign tickets to a client, and you can see where bottlenecks are
- you can see who might be overloaded with tasks
- can be integrated with GIT/Mercurial/SVN
- email based entry

"I really don't like working remotely anymore, at least with a team of developers; I want to be able to show a client -- I'm done with my stuff"

"Ticketing systems are not rocket science"

Version control is non-negotiable
- either the client needs to set it up or set one up yourself
- server is not necessary for setting it up
(* important to note - .git lives under the directory, so a remote repository is the best way to protect the source from a "rm -rf")

"Learn to use the freakin' command-line"

git-diff
- you can see what you just changed before pushing it!

git-commit
- you've basically made a snapshot
- you can undo the change
- you can combine two commits into a single commit, reorder commits
- we have a snapshot that we can roll back to
- replay the history of what you did
- use the tool to get the changes up to the server

git tag -a v1.3
- tags with a version label, so you can do
git checkout v1.3
- or rapidly roll back
git checkout v1.2

"I will not FTP anymore, because this is how it should work."

git bisect start
git bisect good v1.2
- marks v1.2 as a good snapshot
git bisect bad master
- mark the current code as bad in some way
- work through commits to check; mark each either good or bad until you get to the commit that broke
- identify the change that broke the system

git branch (* IMHO, branches are evil)
- work on your new feature and commit as normal but commits will not touch the "master"
- work on experimental changes without breaking the stable code
- pull master back into branch
"The most amazingly trivial thing to do... you'll start to do it for little things, because it is so easy"

git-add --patch
- select which of your changes to add
git-commit -v
- see your diff when writing your commit message
git stash/ stash pop
- kind of like a mini branch
git rebase -i master~10
- edit (!) the last 10 commits

"Having the power to do this sort of stuff in your day to day work is wonderful"

GUI Tools
- gitx (doesn't recommend it for doing the command line stuff)

How to get clients to do this stuff
1) Fire bad clients. Srsly.
Tell them up front that you require Git/SVN, Net 30 terms, a ticketing system or project management system, access to a hosted dev environment or setup on local machine
2) Do it without their permission or involvement
3) Use Github, follow instructions; setup ssh keys; find a project and clone it.
4) Use a ticketing system like assembla; there are lots of other options

Links on pinboard.in/u:murphey/t:git , /t:workflow/

Matthew Bass - Homesteading for freelancers

"Not the construction kind... the kind you do with software"

- hated being tied down all day in corporate work
- as a freelancer, you have time flexibility but you are still tied down
- as freelancers, you fall under the "self employed" category; but there is an advantage to being a business owner, to build products that people pay for;
- stop trading time for money and start diversifying your sources of income

How-To of Building Your Own Product - what's worked for me

Setting Goals can be challenging
- some people set no goals
- some people set goals but they are the same as everyone else's goals
  - "College" expectation and earn a degree: what he found was that the degree didn't really help him.
- we want to set goals unique to our circumstances and talents, and where we feel we are being led, not because everyone else is doing it

Homesteading (re: Nathaniel Talbot)
- self-sufficiency and creating thinking
- may be out in the middle of nowhere,  isolated, alone;
- starting from very little and building it from there
- everyone else expects venture funding, too lofty goals
  - small initial investment, get small amount of income

"You gain strength, courage, and confidence by every experience in which you really stop to look fear in the face... Do the thing you think you cannot do."
- Eleanor Roosevelt

Teascript?
 - and various other philosophical questions
 - problem to be solved: how do home-schoolers get a transcript to present to colleges?
 - proposed solution: a web service for home-school families to get a PDF

"Getting Real" - free online book by 37signals
- Build less
- Stay lean
- Manage debt

Minimal viable product
 - be very careful only to put in necessary features
 - keep "to do" comments and unfleshed out tests to a minimum; set a threshold to avoid technical debts

Release features immediately, get feedback immediately, better motivation to keep working on the product

Catch an idea
- find a target niche

  - Teascript has 5600 subscribers already, despite the crudeness of the interface; there simply aren't any Web based alternatives out there. It is a true niche application so the bar is a little lower.
  - People saw the app and that it worked well, and stuck with it

- pick something easy
 - creating a single PDF was not a hard thing to do; a full-blown planner would have been much more difficult
- solve ONE problem

Taking off
- scope out the competition
- create a skeleton app
- post a tease page with a form
  - you can collect emails of people interested in beta testing the app
  - got over a 50% participation of initial beta tester
- Be selective with what feedback you get from your customers
  - file away features for reference
  - people will use an app even if you don't think it has all the features you think it should have had

Build what they need
- beta testing
- be willing to change

Build what you need
- dashboard / charts
- automation
- watch how people are using the system
- private schools started using the service; totally unexpected b/c pricing structure is oriented toward families, not toward schools
- built an admin back-end to view users, stats, export data
- certain things got to be a drain on his time, managing it; automation helped eliminate that

When to stop
- minimal viable product
- don't get sidetracked
- we are never truly "done"

Deployment
- VPS vs shared
- Original apache proxying Mongrel
"Like, I just want to build applications."
- now running on Phusion Passenger
- Capistrano, baby! (Definitely recommended; can be used with PHP or anything else...)
- shared hosting had issues; migrated to Slicehost but then we had to do everything from scratch
  - it was painful, but worth it
  - lasted for years

Marketing
- email / blogging
- let other "spam" for you
- speaking for fun and profit, to your audience
- Google AdWords (generating steady traffic for about $30/month, perhaps b/c it is a niche application)
- didn't like doing marketing, but it didn't sell itself;
- but a good idea and implementation will be spread by those who like it
- Speaking can be scary -- very scary -- but it can be worth it ; check out toastmasters
"Speaking can give you some leverage."

Refinement
- a/b testing
- customer development
- strategic alliances
- "Everyone in the crowd knew what it was but no one was actually doing it"
- about a/b testing for rails developers: "Vanity" gem for ruby on rails developers
  - statistically prove that users do or don't like it;
  - present two different forms and feeds them at random, and measures the success rate
  - you get a page showing which one converted more users
    - screencast got 9% more results; longer form got 16% more results!
- there is already an "organizer" product, which he could explore alliance with, cross-registering users, etc

Support
- the FAQ; direct people to the FAQ before it happens
- timely replies; people appreciate it; they appreciate that you care and are frustrated otherwise
  - always tries to respond in 24 hours if not sooner
- refunds?
  - maintains a pretty liberal policy on refunds if there is a bug he can't fix or feature he can't implement
- seen some really stupid stuff; add questions to the FAQ otherwise

The buck starts here
- payment systems
  - checks, credit card payment gateway;
- subscription based vs one-time
  - accepting credit cards is often the most challenging piece
  - had paypal, but wasn't very good
  - uses Spreedly now with paypal as the merchant account (Spreedly Nathanial Talbot's api for accessing gateways and auto-renewal, refunds, etc; Spreedly charges a percentage off each transaction.)
 - monetizing using adds was just not worth the time
 - switched to a monthly model; may switch to a fee to print the transcript; used to have a yearly fee instead;
- tracking expenses

Incorporated as an S-Corp; "Adeptware".

Summary
Set some goals; stake out some land; work, work, rest; relax - it's only ones and zeros!
"If you are building for a niche and it has value, then people should be willing to pay for it."

(* note that at the base rate, it is about $28k of income if everyone was a paying customer).
Read More
teascript.com
gettingreal.37signals.com
matthewbass.com
@pelargir

Conference Wrap-up

Sign up to http://groups.google.com/group/indieconf/ to keep up with what is going on.

Raffle give away
1) Carrboro co-working 1 month givaway
2) 2 weeks office space at DesignBox
3) two more "Money" books
4) Pearson Vue Books

Wow. Loved the conference Michael!