Tuesday, November 24, 2009

Mistakes of a freelancer

I have been inspired by a post by Soon Hui to write about my mistakes. I have evolved much on the programming side during these years, but my biggest mistakes have been social and economic: dealing with other people. Thus, I have collect a list of my errors committed as a php freelance developer.
  • Giving out your personal phone number: no matter what, use separate phone numbers for clients and friends. People have the tendency to call in awkward hours, and having a single number you can shut off after the workday has finished helps your work-life balance .
  • Lack of tests: every application you write will be maintained in the future, often by you. Even small tweaks (that you can't honestly charge for) can break an application and the safety net of a test suite will free you from the burden of manual testing.
  • Providing fixed estimates: estimates should be given in the form of a range, and the whole process of estimation and planning in software development is more complex than the average person thinks. Counting billable hours just does not work and an application's size should be assessed during the requirements gathering.
  • Tasks instead of features: one pillar of Agile processes is that features are the metric of success and accomplishment, and not tasks. Even if you're working on fixed-price waterfall projects, focus on giving out the features requested because no customer has the time to comprehend technical and infrastructure tasks such as "database modelling".
  • Thinking that a client knows what he needs: even in porting legacy applications, no customer really understands the kind of software he wants. It is our job to interact with him to distinguish between mandatory and exciting features and providing the highest value in an application, since we have great  programming skills but little domain knowledge. Often emphasis is put on gold plated features which are really not worth their cost and can cause disasters in the long run (and maybe you are even forced to prioritize features with high risk and little reward). Dialogue, dialogue, dialogue.
  • Not defining economic terms early: when you write the first line of code you should have an agreement on your reward. This rule of thumb can seem obvious to us, but remember that customers usually come from a whole different world.
It's a long list, but I feel that I have grown for more than five years and since I started my journey in computer science even before, I'm approaching the 10000 hours as a developer but still gaining basic experience in business. These errors are something I really had to try by myself.
Have you some freelance experience to share? What do you feel you could have done differently during your career?

Monday, November 23, 2009

Firefox without a mouse

As a developer I have made an habit of using the keyboard for the majority of tasks. Vim for example is my favorite text editor, which does not require point-and-click. This is a productivity requirement: the less my fingers move between the keyboard and the mouse, the faster I am in consulting documentation and other developers' blogs; vim even goes further and lets you scan a document without leaving the home row.

Firefox is also an application where I try to avoid mouse (or touchpad if I am using the EeePC). Unfortunately most sites are not really accessible and I have to resort to mouse for links and forms: it's not satisfying when you [Tab] trough a form and end up in some other place in the page.
Though, Firefox's user interface is really usable without resorting to the mouse. Here are some shortcuts I wanted to share with you:
  • <Ctrl>T: create a new, empty tab, and give it focus.
  • <Ctrl>W: close the currently selected tab.
  • <Ctrl><Shift>T: reopen the last closed tab.
  • <Ctrl>PagUp, <Ctrl>PagDown: move between the opened tab.
  • <Ctrl>L: give focus to the location bar.
  • <Ctrl>K: give focus to the quick search bar. If you set the browser.search.openintab directive in about:config to true, search queries will be opened in new tabs. Remember that often search engines and websites like php.net and Wikipedia implement the OpenSearch specification, allowing you to add them to the quick search list of engines.
  • <Alt>Down to select the search engine when you are typing in the quick search bar.
For instance, to search the strpos() function on php.net, assuming that you have stored it in the available engines:
<Ctrl>T, <Ctrl>K, <Alt>Down to select php.net, strpos<Enter>
Or, if browser.search.openintab is set:
<Ctrl>K, <Alt>Down to select php.net, strpos<Enter>
If php.net is already selected since you have already looked for other functions:
<Ctrl>K, strpos<Enter>
Or, given that php.net implements nice urls:
<Ctrl>T, <Ctrl>L, strpos<Enter>

Happy browsing with Firefox and the keyboard! :)

    Saturday, November 21, 2009

    Mocking static methods: the road to Hell...

    ...is paved with good intentions.
    On Thursday I came across the video presentation of a tool to mock static methods in Java:
    PowerMock can be used to test code normally regarded as untestable! Have you ever heard anyone say that you should never use static or final methods in your code because it makes them impossible to test? Have you ever changed a method from private to protected for the sake of testability? What about avoiding “new”?
    Horror. Not because of the technological revolution - maybe being able to subclass final classes only in the test suite would be fine, and this is just monkey patching - but because static methods have nothing to do with testability. Or, they make code untestable, but testing is not the reason why we want to avoid them.

    Dependency Injection is not about testing: it is about good, decoupled design and reusable units. Static calls represent hidden connections between your classes that are not listed anywhere, and they give access to global and usually mutable state. They help creating a misleading Api and constitute the procedural part of object-oriented programming.
    This is an example of bad Api:
    <?php
    class UserRepository
    {
        public function getAllUsers()
        {
              return Db::findMany('User');
              // this would be the same: 
              // return Db::getInstance()->findMany('User'); 
        }
    }
    If in different tests we use this code:
    $repository = new UserRepository();
    $users = $repository->getAllUsers();
    we probably get different results. But why? We had instantiated the same object and called the same method without any parameters. This Api is far from being referential transparent, and that's because it has a static reference that jumps to global state instead of having it injected.
    So the question is not How can I mock a static method?, but How can I avoid static methods?
    <?php
    class UserRepository
    {
        private $_db;
    
        public function __construct(Db $db)
        {
            $this->_db = $db; 
        }
        public function getAllUsers()
        {
              $this->_db->findMany('User');
        }
    }
    <sarcasm>It was very difficult, isn't it?</sarcasm> Dependency Injection is in fact very simple: ask for what you need, so that people that read your code know where collaborators are coming from and you are not secretly smuggling them in your classes.

    I once heard a talk by Misko Hevery where he was making a point about dangerous global state, and he described the following situation. Suppose you have your beautiful test suite, and some classes in it accesses global state, so the tests are not real unit tests but have a bit of integration in their hearts. Keep in mind that in this environment tests are not isolated, since they depend on some global variables, maybe masked as singletons or static classes. The order of execution matters.
    So you have MyClassTest, that is the last test case to run in the hour-long test suite, and it is failing. So you try to run it alone, and it pass. Then you run the suite again to figure out what is happening, and it fails again. The test is referencing some global state in which particular data is placed by the other tests before MyClassTest is run. The only way to hava a reliable failing is to run all the suite to set up the global state necessary.
    The conclusion is: good luck in finding what is making MyClassTest failing.

    Static methods are not object-oriented: they are a recipe for problems if they carry hidden state. They are global, because you cannot keep them on an instance you can throw away after tests. They make the Api difficult to grasp by hiding dependencies under the carpet. The solution is not "Let's open up the hood and wire these things differently so that we can mock static methods", but "Let's not use static methods."
    You should even write the tests before the production code if you can. We do not write them only because they catch bugs and regression, but also because real unit tests force to code in a clean and decoupled design. If you are able to unit test your application, its architecture and flow is composed of focused, reliable and reusable parts. If you use static methods and spread new operators everywhere, there are hidden connections between components and mocking these things it's only Action at a distance.

    Friday, November 20, 2009

    The best backup

    Yesterday I was reading some posts in my aggregator about backup techniques, and they reminded me of a (famous?) quote. Thus, I wanted to share my preferred technique for sofware projects backup.
    Only wimps use tape backup: _real_ men just upload their important stuff on ftp, and let the rest of the world mirror it ; -- Linus Torvalds, (1996-07-20). Post to linux.dev.kernel newsgroup.
      I know this is not applicable to every project, but usually open source is full of benefits:
      • if you follow the doctrine (everything not reproducible is kept under version control), there are free services like Google Code and SourceForge which will host the Subversion (or Git) server and care for automatic backup and disaster recovery. This means that if your old hard disk breaks your work is saved up to the last commit.
      • Obviously you can get collaboration and feedback from other developers.
      • It takes minutes to set up a working copy of your project for development and testing as long as you have an Internet connection available: it is globally accessible all over the world.
      There are cloud services for private projects, but they have a cost in money. Open source support is free and competitive today. Every management application you will need is provided and updated by SourceForge: trac, wikis, file release system...
      In general, sharing with the rest of the world your code and your writings is the way to save them from oblivion:
      Some years ago, two programmers at Cisco (the networking-equipment manufacturer) got assigned the job of writing a distributed print-spooling system for use on Cisco's corporate network. [...]
      The duo came up with a clever set of modifications to the standard Unix print-spooler software, plus some wrapper scripts, that did the job. Then they realized that they, and Cisco, had a problem.
      The problem was that neither of them was likely to be at Cisco forever. Eventually, both programmers would be gone, and the software would be unmaintained and begin to rot (that is, to gradually fall out of sync with real-world conditions). No developer likes to see this happen to his or her work, and the intrepid duo felt Cisco had paid for a solution under the not unreasonable expectation that it would outlast their own jobs there.
      Accordingly, they went to their manager and urged him to authorize the release of the print spooler software as open source. Their argument was that Cisco would have no sale value to lose, and much else to gain. By encouraging the growth of a community of users and co-developers spread across many corporations, Cisco could effectively hedge against the loss of the software's original developers. -- Eric S. Raymond, The Magic Cauldron
      What is your opinion on sharing your work as open source?

      Thursday, November 19, 2009

      More questions on controllers testing

      Sune wrote to me yesterday with some questions about testing Zend Framework controllers and proper dependency injection, which to me is a fundamental practice in object-oriented programming. I have already responded to similar mails in the past and this seems to be an hot topic nowadays, so as always I think other readers can benefit from this discussion and I'm sharing it here.
      Because of you I am trying to move my software to use factories and dependency injection, also removing
      singletons and Zend_Registry usage in controllers. But I am a bit confused, what is the right way to do this.
      My plan is to bootstrap the main factory in the bootstrapper, and then use
      $this->getInvokeArg('bootstrap')->getResource('factory') in controllers. Is this good practice?
      Summarizing, the best thing would be creating the controller by yourself (or having its creation configured someway), but it can be an overkill to set up a similar approach on a Zend Framework application, since it requires a third-party DI container and controllers should always be thin.
      Thin controllers means we probably want only to perform integration testing on them with Zend_Test, and not real unit testing as there is not much logic to exercise.
      Since we cannot create in the bootstrap all the collaborators that could be possibly needed (we want to lazy-load collaborators that may not be referenced), your approach is similar to a Guice provider and I think it is very valid. In integration testing you should then use a different factory or configure this one to provide some fake components when the real ones are not applicable. For instance, a mailing service object ca be replaced with a fake implementation that records all the sent mail and lets you assert on them.
      And in conjunction with that. Would it be good practice to inject a Zend_Config object into the factory?
      Some models requires options from the config file, smtp username etc. and the factory would need those information to create the models.
      Of course. It's up to you how to organize the config object, and you can and should change part of it in the testing environment. The power of DI containers is that during configuration you can specify not only scalars like database connection strings, but also different classes and implementation for the collaborators you inject.

      ShareThis