Ronin Blog

How we’re making invoicing and time tracking better for everyone

Authorize.Net Invoicing

with 2 comments

We’ve recently added integration with Authorize.Net, one of the more popular payment gateways. For the impatient, there’s no need to read further - just log in to your account and the option will be waiting for you under the “PayPal/Auth.Net Integration” link.

Integrating with Authorize.Net is fairly straightforward - with one caveat - Authorize.Net only handles USD (United States Dollars) as the currency for every transaction. We’ve held back on the integration until now simply for the reason that we wanted solutions that would appeal to every Ronin user, of whom lots are international, particularly in the UK and rest of Europe. One of Ronin’s strengths is the ability to handle multiple currencies, even within one account and we wanted to make sure we “do it right, or don’t do it at all.” However, there were simply too many requests for Authorize.Net integration to ignore.

With that, we’ve decided to integrate Authorize.Net with the option to still fallback on PayPal (which handles more currencies). So, if you enable both, your USD invoices will simply accept credit cards via Authorize.Net and your other non-USD (CAD, EUR, GBP, etc) invoices will still go through PayPal. You’ll get paid sooner, your clients will be offered the convenience of paying online when applicable, and everyone ends up happier!

Start sending out those invoices! Enjoy!

Written by Ronin

July 7th, 2009 at 1:23 am

Selling Software to the DIY Generation

with 3 comments

I’m a software guy, not a historian, but I do know that software, historically, was once sold by guy and gals in business suits to other guys and gals in even fancier business suits.

It should come as no surprise, however, that the game has changed since, in that software is now more often sold by guys and gals in tee-shirts and shorts to people of all sorts. While in most cases, not much has changed for the Business-to-Enterprise (large company) sales-cycle, the landscape of selling software is dramatically different for software businesses selling to the world at-large via the web.

The guys at MailChimp describe themselves accurately in these terms:

MailChimp is a do-it-yourself email marketing service for ‘the Google generation.’

While I’m not sure how effective or well-received this description is to potential customers (who hate to be categorized), it tells me that they know exactly to whom they are selling their services. Although, I prefer to call this crowd the “DIY Generation”.

The Google Generation or the DIY Generation is not so much a traditional generation as it is the demographic that is experiencing gradual increases in accessibility of software to the average user. This is a demographic characterized by a willingness to get things done via a computer and a general understanding of how to do-it-yourself when it comes to solving problems via new techniques. This carries over to their receptiveness to purchasing software applications as a means to some end. No salesmen needed.

This transformation and the increased count of this crowd has made selling software to consumers, startups, and small businesses viable as a business. But, it’s important to have an understanding of what they are looking for when it comes time to craft a sales and marketing strategy to capitalize on this market. There are a few key subtle things to look out for, besides the obvious things that every one running a business on the web now understands (have good SEO/link-strategy, etc.).

Comparison shopping happens. Have strong marketing and branding.

When every competitor and their prices are a simple search engine query away, comparison shopping simply has no barriers. Couple this with the fact that the average DIY user tends to be more tech-savvy (and thus recognizes what he or she is looking for in a software application) and you’ve got customers that are often armed with alternatives.

You can fight this battle anyway you want, whether it’s by outdoing your competitors feature-by-feature or by underdoing them a la 37signals, but it is imperative that you have an answer to the question, “Why you and not competitor X?” Even if no one ever asks you this question straight up, you are implicitly answering it each time a visitor hits your website and make that 10 second evaluation of your product and features. Make sure your unique approach to solving the problem or other competitive strengths are visible and in full-display. This can be sometimes hard to grasp and unintuitive, especially for products that don’t have advantages that are easy to pitch as one-liner advantages. In some cases, even the pricing of the product is a differentiating message.

Work hard on the marketing on your site. Remember that it is very possible that your site home page could be the most used “feature”. Design and implement with thought, just as you would with any other feature in your software.

Oddly enough, in selling software to this DIY generation, branding plays an even more important role than it has traditionally. In the traditional sales cycle, you could strategically outsell the big-name competitors with a decent salesman/sales-pitch, in the new software sales cycle, your reputation is your heavy-hitter sales guy. This is probably why companies selling to this crowd are generally very protective of their customer service reputations and tend to leverage a devoted community.

Communicate with your users. Email can be a sales person.

One of the earliest models of selling DIY software was shareware, which usually came with a 30-day trial. This model works. In fact, even with the web being all the rage, there are plenty of software vendors doing it tried-and-true way. What isn’t often recognized is that the 30-day part is just as important as the free trial part of that model. While the free trial got users to get comfortable with a software application, the 30-day part provided a nice reminder, a communication channel of sorts, that the user should purchase the application if they were satisfied.

The point here is that it’s important to be in communication with your customers because it’s vital that you give your software every chance to be remembered. Utilize email for this. Make email a sales person for you by being in communication with your users. In a freemium model, this can lead to conversions for all sorts of reasons (new users who forgot to give the app a try after registering, old users who come back, existing users who decide to upgrade). In any model, this can be an opportunity to teach users about new features, announce new versions and upsell upgrades, plug-ins, services, and packages. (And of course, in return, you should comply with standard email rules/laws like CAN-SPAM, just like when a sales person should know when to stop bothering a cold lead.)

Very few products just sell themselves, especially when it comes to software. In fact, a purchasing decision might have nothing to do with whether or not a potential customer liked your application. For example, in a freemium model, there are many hundreds of reasons why a perfectly satisfied user does not end up converting into a paid customer, including simply forgetting to continue to use your software altogether, or never really finding the time to incorporate your software into their everyday workflow. Being in communication helps mitigate lost users.

It’s OK to be niche. In fact it’s probably good.

If you think about the typical discovery process, the DIY user probably learned about your application through some method involving a need that you address specifically. Unless we’re talking about the iPhone games market, it’s very rare that a user stumbles across your app and decides to purchase it on a whim. We’re not in the fashion industry - it’s just not that simple here.

It’s more likely that they had a specific need that needed to be addressed, and in search of a solution, they found your software site or application. This can be from something as direct as a Google search for keywords you’ve bought or something as indirect as tweeting for a recommendation on Twitter.

Specific needs are often addressed not by a general product, but by a niche product. No one ever has a problem finding Photoshop when they want to buy it. But, they will look for niche products like Photoshop filters or a web-based photoshop alternatives. This is when being niche gives you sales leverage - you could be the only provider (or the only dominant provider) that sells specifically what that user-base wants.

Simplicity sells, but selling isn’t simple. Measure everything.

Simplicity is a feature. It is something you sell to your users, especially DIY users who have no incentive to spend hours learning your system inside and out. Simplicity is king in a market where the lowest barrier-to-trial and lowest barrier-to-use often means the lowest barrier-to-sales. However, simplicity is user-facing and that should be where it ends.

Under the hood, it’s important to remember not to get carried away with over-simplifying everything, especially your business process. Good business processes should be advanced, well thought-out and, for lack of a better term, complex. Measure everything. Iterate on everything. This is especially true for sales. Don’t avoid A/B testing sales pitches because they’re too complicated to implement. Don’t avoid implementing complicated site analytics because it ruins some holy simplicity.

At the end of the day, simplicity is an abstraction you provide to your users. Any given users will probably only need any one simple feature. But you must be able to understand all sorts of users with all sorts of requirements. You’ll need access to all the numbers to analyze all of the possibilities. Don’t shy away from the complicated because you’re caught up with keeping your business simple.

It’s about being better.

At the end of the day, there’s no getting around the fact that the DIY generation knows what they want, and there are no shortcuts in selling to this demographic.

They’re looking for specific solutions to specific problems; they’re likely to go with brands they recognize through word of mouth; they have ample access to your competitors; they are hard to quantify and understand en masse; and they want it all in a simple package. When you put it in those terms, the task of selling to this group seems downright dire. And yet, the reality is this is good.

You don’t need a large sales force to sell to this crowd. You don’t need to play politics. You don’t need expense accounts. You don’t need a big-wig attitude. You just need a small team that believes in delivering a great product to a very savvy audience.

You need to be better and recognizably so. In some respects, this is a meritocracy and I (and Ronin) wouldn’t have it any other way.

Written by Lu Wang

March 30th, 2009 at 4:54 am

Posted in Entrepreneurship

Tagged with

Recurring Invoices - Back to Basics.

without comments

We’ve been asked many times whether or not recurring invoices was possible with Ronin. For a while, we’ve had to say “No” or “This feature is under development.” We always planned to build in this feature, but we wanted to make sure it felt right - that it felt no less intuitive than creating a single invoice.

We eventually built the feature, but decided to hold off on releasing it until we did enough user testing before releasing the feature. As it turns out, the first iteration of it, indeed, wasn’t ideal. What we had designed was a “schedule” that you could assign to many clients. The idea was that freelancers and firms would have standard packages (say a retainer for $x/month) and that you could then put clients into that schedule. Furthermore, it was thought that this would allow the most effecient way of managing the schedules - you would never have to create too many, there would only be a few that you assigned to clients.

After some testing, we realized being technically neat didn’t necessarily make a product more intuitive. In fact, it often works in reverse. The end result just didn’t fit a typical workflow. There were a whole host of issues, but chief among them were that:

  1. It made recurring schedules feel like too much of a “first-class” feature. We want Ronin to revolve around clients, but the initial design made it feel like schedules owned clients, not the other way around.
  2. Maintenance of schedules was actually harder, not easier. Once we started considering the ability to “pause” and “resume” schedules, it became a nightmare to display the status of the combination of a schedule and its clients in an intuitive way.
  3. It was overkill. We realized that it wasn’t very common to have two clients share the exact same schedule (including date, item naming, price, etc.)

Instead, we eventually went back to basics. Creating a recurring schedule is as easy as creating a normal invoice and it’s tracked just like one as well.

Finally, you can now create recurring invoices with Ronin. Enjoy.

Written by Lu Wang

March 28th, 2009 at 3:18 am

Posted in Ronin Product

Usability Study Pitfalls

with 2 comments

The best way to improve an application’s usability is to run extensive studies - they allow you to get an idea of what it’s like to walk a mile in your users’ shoes. Sometimes, just the practice of sitting down with another human being and verbally walking through your application’s features brings out certain perspectives you may not have considered before. This is especially true if you wear many hats during the development cycle.

At Ronin, we run a usability study every few weeks, focusing on new features. We’re usually very considerate of our users throughout our application design process, but you’d be surprised how much slips through when you’ve looked at the source code of your application longer than you’ve looked at the actual interface. Running a usability study is an exercise that usually brings in a large list of low hanging fruit and a moderate list of long term application improvements.

That said, from our experience running these studies, there are a few things we realized you can never fully understand from just the studies themselves.

User patience

When a study participant sits down next to you to walk through your application, they’re in no hurry. They’ve committed the next 30 minutes to 1 hour of their lives to the purpose of completing the study. Compared to the average 9 second attention span you’re likely to get from a real world user, this is too distant from reality to simulate.

Unfortunately, there isn’t much you can do to recreate a frantic in-the-wild scenario. This negatively affects the ability to learn about edge-cases and error handling the most. A usability study user is likely to run into some errors that they are patient enough to figure out during a study, but would otherwise cause them to throw their hands up in disgust. To counteract this, its best to read between the lines when it comes to negative reactions. Multiply observed frustration during studies by many magnitudes to really understand how a user may react.

Also, try to develop an understanding of how user patience can be a big factor. Spend time testing your home, promo, and marketing pages with an emphasis on asking for a stream of consciousness verbal description of what they see with a time limit. After all, if they stick around long enough to try your application, you’ve won half the battle when it comes to user patience.

User attentiveness

Another problem is that study participants are usually more alert and attentive than their real-world counterparts. They’re willing to take their time and figure out a problem. They’re willing to devote their undivided attention to the task at hand. Compare this to the more likely scenario of an actual user trying out your application at 2 a.m. with the TV running in the background and after surfing to your promo page by coincidence. It’s night and day.

To counteract this, make sure you get immediate verbal feedback after each action they take, to get a sense for what they’re thinking before the interface has had time to soak in their consciousness.

User skepticism

Most deceiving of all is the mindset of a usability user. Depending on what your relationship is with the user (stranger, guest, friend, acquaintance, co-worker from another department, spouse, child) you need to realize they’re walking into the study with some intentions. Sometimes they’re participating because you’ve promised to pay them; other times they’re participating because they want to help you out. Whatever the case, nothing simulates user skepticism.

When a random user hits your site or application (say from Google), they’re coming with a guarded mindset. They’re cautious more than curious and they’ll immediately look for warning signs. A poorly designed interface with no obvious indications that there is active support or lack of no-obligation demos or screenshots are an immediate turn off. If they eventually try your application or dig deeper into your site, they’ll probably be less willing to try anything but the most obvious of features.

When a user hits your site or application from a referral or other more qualified method, they’re coming with a curious mindset. They want to dive right in and see what all the fuss is about. They’re also likely to be the ones who have heard of alternatives or are currently using an alternative and now they’re using your application to do some feature comparisons.

When a user participates in your user study, you get none of this. They’re neither overly guarded nor overly cautious. It is more likely that they feel you are working together in unison towards a common experimental cause. You really don’t get the stinging skepticism that a real world user carries.

It helps to keep these things in mind when conducting usability studies. Sometimes it’s too easy to pretend that you’ve aggregated all the feedback you can by running a well-designed series of studies. Even armed with that data, keep in mind that the best feedback is silent feedback. Make sure to analyze your logs. Don’t dismiss your analytics tools. Look over real user data from real users in the wild. Couple that data with usability studies and only then do you have a good macro- and micro- level understanding of your own application.

Written by Lu Wang

January 16th, 2009 at 2:13 am

Die IE6!

with 2 comments

IE6 (also affectionately called Internet Exploder by some) has been a huge burden on the web as a whole for several years now. While the average web consumer might not notice it, the ubiquity of IE6 has forced web developers and designers to jump through many arbitrary hoops in the past to support the non-compliant browser.

This has meant that precious development and design resources over the last several years have been slaving away at making IE6 look good, instead of focusing on making web sites/apps/designs work better. This also has meant that one major strength of the web (portability) was hampered by the need to address a specific platform.

The good news is, several companies are beginning to drop support for IE6, in favor of more recent browsers, most recently Google. This is not surprising for Google as they have been pushing alternative browsers like Firefox and, more recently Chrome for a while now.

For web developers, this comes as great news - there is now a major web player moving the masses away from IE6, which hopefully accelerates the adoption of newer generation browsers.

Traffic distribution across browsers.

For Ronin, we’ve never really supported IE6 to begin with and we’ve seen no reason to really bother with bending over backwards to begin supporting IE6 now that it’s hopefully on its way to the grave. Analysis of our traffic shows that only 16% of our traffic comes from Internet Explorer, and of that 16%, roughly 20% use IE6.

The chart on the left shows that the majority of our users prefer Firefox and the rest use Safari. Surprisingly, this doesn’t mean most of our users are on Macs - instead, Firefox/Windows is still the most popular combination.

This certainly has to do with our audience. We primarily attract high-tech professionals (whether its freelancers, design firms, small businesses) and with that tech-savvy crowd comes the preference for newer, more standards-compliant browsers. In fact, it would be a lie if I told you we didn’t have this fact in mind when we first started Ronin.

Here’s to a new year and leaving behind old worries!

Written by Lu Wang

January 2nd, 2009 at 4:29 am

Posted in Uncategorized

Support for more currencies

without comments

We’ve recently added support for four more currencies: JPY (Japanese Yen), INR (Indian Rupees), CHF (Swiss Francs) and NZD (New Zealand Dollars). You can now send those invoices in 10 different currencies.

In adding support for more currencies, we wanted to make sure we included currencies that are “the most popular” (whatever that means). Surprisingly, there was no definitive resource that lists out the most popular currencies by any decent metric, unlike say, languages, where the list is easy to find. We did run across this discussion which seems to indicate that this is a question that people want answered.

Eventually, we ran into the list of the top 8 most traded currencies in the foreign exchange. Not surprisingly, that list looks very similar to the list of supported currencies in Ronin. Oddly enough, the Russian Ruble and the Brazilian Real were not present, despite being high up on the top economies list.

Written by Ronin

December 23rd, 2008 at 2:47 am

Posted in Ronin Product

Lazy Loading JavaScript

with 3 comments

Most of us know it’s best practice to load your JavaScript at the bottom of the page for performance reasons. The Yahoo! developer network explains the reasoning as follows:

It’s better to move scripts from the top to as low in the page as possible. One reason is to enable progressive rendering, but another is to achieve greater download parallelization.

What typically is not discussed, however, are the potential issues that arise when you follow this development rule-of-thumb. I hope to talk a little bit about this issue and a nice workaround that I like to employ to side step the landmines.

Uh-oh, JavaScript errors

Consider the following code block:

<body>
  <div>
    <a onclick="foo(); return false;" href="...">click me</a>
  </div>
  <script src="...defines foo..." type="text/javascript"></script>
</body>

This complies with best practices for performance, but the astute developer will note that there is a small interval of time between the rendering of the a tag and the script tag. This means for that interval of time, a user could click the link and trigger an undefined function. That’s no good.

This problem is actually more pronounced than you might think. If you’ve ever watched users over the shoulder, you’ll know that some of them can be very click-happy (and they’ve every right to be). They don’t expect to wait for the full page to load before taking an action. Why should they? Isn’t that the whole point of progress rendering?

Also, this is a bug that tends to slip through the developer radars. We tend to wait for the entire page to load when we’re going through our code, save, refresh RAD cycles, probably because something inside us knows to wait for the page to “stabilize” before attempting to test that one feature we just coded up.

Wrong answer (sorta):

Purists will note that the best solution to this is to remove the onclick attribute from the HTML and instead load it during the onload (or DOMLoad) event within JavaScript. This frees up the HTML so it is just content and moves all the interactive stuff into JavaScript (the application layer) where it really belongs.

I’m actually not opposed to this reasoning, but for the purposes of shaving off every millisecond of lag, this solution will not work. There is still an interval of time between the rendering of the link and when the JavaScript attaches the onclick handler. Clicks during this time won’t register JavaScript errors, but they’ll either trigger the actual link or do nothing, depending on what you have set in the href attribute.

If you’re happy with that, great. If not, read on.

An example workaround:

Supposing that foo is a hefty function, we really do want to load it last on the page. This is especially common when foo is part of a larger framework or rides on top of said larger framework. This is because beastly libraries like prototype ought to be loaded last on the page if possible.

We can try the following:

<head>
  <script src="workaround.js" type="text/javascript"></script>
</head>
<body>
  <div>
    <a onclick="bar(); return false;" href="...">click me</a>
  </div>
  <script src="...defines foo..." type="text/javascript"></script>
</body>

and in workaround.js:

function bar() {
  var closure = function() {
    if (typeof window.foo == 'function') {
      foo();
    } else {
      setTimeout(closure, 100);
    }
  }
  closure();
}

Oooh, self referencing closures. That’s got to solve the problem just from sheer awesomeness, right? Let’s break down what’s going on.

Instead of calling foo directly, we’re calling bar, a function that we hope is lighter-weight than foo, since we’re allowing bar to be the exceptional bit of JavaScript that is loaded in the header. bar simply checks for the existence of foo every 100 milliseconds until it is loaded, at which point foo is called. Alternatively, onload could be employed, which is typically not as fast as polling every 100 milliseconds. Yet another alternative would be to employ DOMLoad, but you’d have to include extra JavaScript to get a cross browser friendly version.

But wait, there’s more

bar and foo are cute for example purposes, but we really want to generalize the concept.

Try this instead:

function safecall(func) {
  var closure = function() {
    if (typeof func == 'function') {
      func();
    } else {
      setTimeout(closure, 100);
    }
  }
  closure();
}

The calling HTML should be:

<a onclick="safecall(foo); return false;" href="...">click me</a>

If you want to pass parameters, you’ll have to employ closures, not that you don’t want to.

<a onclick="safecall(function() { foo(arg1, arg2)}; return false;" href="...">click me</a>

Geez. JavaScript is powerful. The closures I mean - not the part where I just spent several paragraphs detailing what is essentially a hack.

Conclusion

We’ve defined a function safecall that can be defined as the sole script in the head tag which can be used to protect unloaded JavaScript that is sitting at the bottom of the page. Hopefully this will solve someone’s development headaches trying to fix all those new JavaScript headaches when someone in the office decided it would be cute to move scripts to the bottom of the page.

Written by Lu Wang

December 12th, 2008 at 5:49 am

Posted in Development

Tagged with , , ,

New Product Feature: Estimates

without comments

We’re always looking to improve our offering here at Ronin, and one feature we’ve received several requests for was the ability to send estimates. Unfortunately, everyone’s daily workflow is different - drafting and sending estimates is no exception. We’ve tried to incorporate as much feedback as possible, and while we’d love to including every feature detail from numerous email threads about this feature with our customers, sometimes we have to call the shots that make sense.

So log in to your Ronin account and you’ll notice a new estimates tab. Hit the “New Estimate” button and you’re on your way. After drafting the estimate, hit “Send Estimate” and your client will receive the estimate in his or her email. The client can then respond by leaving comments, accepting or declining your estimate.

Estimates can easily be accessed from the main interface

Estimates can easily be accessed from the main interface

Send estimates to clients

Send estimates to clients via email

Clients can accept or decline estimates right in the web interface.

Clients can accept or decline estimates right in the web interface.

It’s all very simple (we hope) and there isn’t too much different about drafting an estimate and an invoice. We hope we’ve nailed it, but we’d love to hear any feedback.

Written by Ronin

December 8th, 2008 at 4:38 am

Posted in Ronin Product

Tagged with ,

Entrepreneurs wear many hats

without comments

The recent trend of new businesses moving towards software or, more specifically, the web, seems to lead more and more would-be entrepreneurs into falling victim to the myth that building a solid product is necessary and sufficient for success. Some would go so far as to believe that cool technology alone does the trick. Many from-thesis-to-market product failures demonstrate the naiveté of current entrepreneurial thinking. All to often, we are led to believe that awesome products sell themselves.

Conversely, the other end of the spectrum finds no shortage of MBA’s looking for “code-monkeys” to implement their visions. The mode of thought here centers around the million-dollar idea, from which execution supposedly willingly falls into place. Here we are led to the believe that awesome ideas lead to awesome products that sell themselves.

The code-monkey and MBA both fall prey to the instant-noodle brand of business development: “1) idea 2) build 3) ??? 4) profit.” Battles are fought over whose position is more important, the tech guy or the biz guy. Techies are all too-often devoted to proving themselves to be in no need of the MBA types, while the business minded are just a lost looking for hired guns to prototype a lost cause. Lost in all this back and forth is the unerring truth that none of it matters.

For centuries on end, entrepreneurship as been defined outside the lines of technology. Look up “define: entrepreneur” on Google and the common theme that arises in each definition is the word “risk”. Not “new hot technology”. Not “brand new business idea”. While it can never hurt to have new hot technology that powers a brand new business idea, it is neither necessary nor sufficient to get a business off the ground.

The age old fact of entrepreneurship is that there is so much more to “risk” than the product and its development costs. Establishing or building your market, generating or growing revenue, finding distribution channels, building a sales pipeline, hiring the best talent, and all the other caveats that come with building a business are just as important as product development. A true entrepreneur must wear all these hats, not just the product one. A recent blog entry by Tony Wright talks about the product guy vs. business guy with the conclusion that a good product entrepreneur should grow into a business role. While I agree, I would have to say a great entrepreneur can never take off either hat.

Be a business that sells a product, not a product that happens to be a business. Be an entrepreneur that builds business, not a product person that happens to be an entrepreneur.

Written by Lu Wang

November 16th, 2008 at 9:17 pm

Posted in Entrepreneurship

Freelancing for Money

with 3 comments

There was an interesting article I came across titled “12 Killer Ways to Make Extra Income On the Web“. The article is interesting because there was only really 1 killer way that is even worth mentioning, and that is “Freelancing”. All of the other recommendations are either a waste of time or require much more effort than simply getting paid to produce good work. The age old “do-work-for-money” will never go out of style. If you’re good at what you do, of course you should be getting paid well to do it.

However, like all marketable things, your personal time is something that you should price with careful consideration. Unfortunately, there is one business model that is cropping up across the web that is counter to this. These sites (typically targeted towards logo or web design) allow you to submit entries for a chance to win a small cash amount ranging from several hundred bucks to maybe a thousand dollars for a winning entry.

Without being religious about NOSPEC, my advice is to steer clear of these “contests” unless you are simply trying to get your feet wet with design (or whatever industry you’re jumping into). There are various reasons that people throw around, but in my opinion, if you don’t value your time and effort, why should the client? If you really undervalue your work that much, maybe it’s because you consider yourself an amateur and not a professional. Also, on the flip side, clients that flock to these sites typically have no appreciation for the good work that professional designers can produce. As a friend of mine once aptly described it, it is like these folks couldn’t tell the difference between interior design and interior decoration.

Show respect to your own profession, lest you sarcastically post a blog entry entitled “Why I hate freelancers.” Whether it is web design or software development the good clients out there are looking for real professionals, not amateurs.

Written by Lu Wang

November 12th, 2008 at 5:46 am

Posted in Design, Development