Wednesday, March 17, 2010

How improved hardware changed programming

This is a follow-up to the previous post, CPUs speed and technology innovations.

As we have outlined in the previous post, the memory size and computing power available to the average programmer has increased thousands of times from the first years of his art, at least in the boundaries of a single machine (network is a common bottleneck.)
This performance improvement has made radical changes to the style we use in writing software and in its development process.
The first notable change is the progressive introduction of higher-level programming languages. C is near the raw metal of a machine, but upon it portable languages have been written, such as Java and Python. They are still third-generation programming languages but they sacrifice performance for portability by providing a virtual machine and an interpreter respectively.
This is a general trait of higher-level languages: trading machine time to save the developers' time, which with the hardware improvements is now the most expensive resource. At the time of his release to the public in 1995, Java applications were considered slow programs with an extensive memory footprint (with reasons). However today this is no longer significant for a vast set of applications, and the same is true for other high-level languages like Python and Php. Premature optimization is now the evil, not the Java Virtual Machine.

Some people say that software bloats faster than Moore's law can help it: we went to the Moon in 1969 with 4 kilobyte of Ram, now we need 100-200MB to run an operating system. But the features and power of our machines is now much greater (discounted by the amount that runs software's bloated parts), we can do things that were only dreams in 60s.
Continuos integration of software project and immediate feedback via tests are two things that derive from a large amount of computing power available. Donald Knuth is a magician in algorithms, but back in the 60s he has to write a program by hand during the day, and let the machine compile it at night. Now we have the whole process of building and testing for a moderate size program run in minutes from every code check-in. Algorithms were proved on paper: now they are tested on large datasets.
Object-oriented programming is a practice fundamentally less performant than "classical" structured programming, because it stores pointers to virtual methods in every variable, even a wrapped integer. But it lets you have a real domain model in an application, where different entities, both represented as integers, cannnot be mixed up. Few of us will start a serious enterprise application without this paradigm available: the hardware improvements again made possible to simplify the programmer's life, even if sometimes bloat would be introduced.

And the list goes on: every best practices post you can find today (also mine) is in part generated by the continuous hardware improvements that have occurred, and it is a good thing, because it means we are leveraging the machines' power. Meaningful naming for entities? Try it with an 8 character limit. Iterative development, refactoring? Made possible by the insulation layers between components, which are a form of "bloat". Distributed version control? Thank you, cheap space on hard disks.
Moore's law won't save anyone introducing bloat in software. But it makes new programming practices feasible, directly borrowing them from your dreams.

Tuesday, March 16, 2010

CPUs speed and technology innovations

The number of transistors that can be placed inexpensively on an integrated circuit doubles approximately every two years. (Moore's law)
This empirical law is primarily known for the increasing trend of processors speed, which is widely influenced by the capacity of miniaturizing transistors in silicon-based chips. However, the general formulation of the law affects all semiconductor technologies, such as CPUs and electronic memories.
We may also note that similar laws exist for magnetic disks, which storage density doubles annually, and for network capacity (optical fiber's bandwidth doubles every nine months.) This set of empirical laws describe the exponential growth that we have been experiencing for many years.

But do limits to these exponential laws exist?
When miniaturization is involved, atomic limits are usually the ultimate frontier. The current most advanced production process for semiconductor devices is the 45 nanometer technology, which length refers to half of the average distance between memory cells. Each cell consists of two or four transistors, whose size is in the range of 100-200 nm.
For comparison, the size of an hydrogen atom is roughly 0.1 nm, and it is indeed the smallest existent atom. The average distance between silicon atoms arranged in a crystal like the ones used in chips is about 0.5 nm.
The predicted technology for 2015, according to the International Technology Roadmap for Semiconductors, is the 11 nanometer one. This means miniaturized components will be electrically insulated by a layer of... twenty atoms.
The consequences for the inner working of these devices are disastrous. As you may know, the physics models that govern modern integrated circuits are not classical: their design follows quantum mechanics. At such a small scale, quantum tunneling (the same process that charges flash memory cells) can make insulated cells interact. Silicon (and its doped derivates) usage cannot scale to the atomic sizes.

But limits are made to be infringed. For example, the integrated circuits are manufactered by photolithography. Without descending into the details, let's just say that a photoresistive material is "painted" over some area of the chip, which is then exposed to a light flash so that excess material is somehow eliminated from the chip, like if it were a chunk of photographic film. What remains under the shielding layer are the tracks and soon-to-be components of the integrated circuit.
Cool. What's the problem? The light used for this process, as all the other forms of light, has a minimal wavelength of about 200 nm. Thus transferring patterns of elements smaller than this size should not be feasible: it should be like revealing the presence of a 1-inch hole in a wall by launching basketballs at it, in the darkness. But it has been made possible with new techniques and tricks when the limit was reached.
And the same has been done with multi-core architectures: the power consumption of a CMOS cpu is proportional to its clock frequency, and the external components do not increase in speed as a cpu. So when an effective barrier in frequency was reached, the electronic engineers started increasing the processors in a single package instead of having them run faster. The result are the current dual- and quad-core architectures (and the new problem: how to parallelize tasks efficiently to keep all cores busy?)
Maybe Moore's law in its current form will cease to work in the future, but the technology level and the computing power it brings along are still likely to increase for a long time. There were, and still are, great business incentives to continue to enhance computing devices, and clever men always find another way to make money.

Monday, March 15, 2010

Coffee and programming

A mathematician is a device for turning coffee into theorems. -- (attributed to) Paul Erdos
Coffee is indeed an omnipresent drink in many different science fields - probably for its property of aiding concentration and focus over a short period of time. In the field of software development, just think about the Java platform and programming language, named after a coffee, whose symbol is a cup and certain constructs are called beans. Many programmers declare themselves coffee addicts, and present guides to coffee roasting and brewing.

As you probably now, high consumption of caffeine, which is the principal psychoactive component of coffee, is not very healthy. The reason is the substances in a cup of coffee are derived from coffee beans, and the Coffea plants have been naturally selected to produce hazardous chemicals. Plants generally do not want their seeds to be eaten: while the man-made cultivation, which favors the more productive varieties, dates back to some centuries ago, the natural selection of the Coffea plants has been a continuos process for thousands and thousands of years. That's why roses have spines and poison ivy is... well, a bit poisonous.
The overall effects of a moderate consumption of caffeine, as they have been exposed by scientific studies, are controversial. And the picture cannot be different: there are many types of coffee, also with different serving sizes, and possibly different effects (and side effects). Particular beverages such as tea and Coca Cola contain caffeine, but in a much lower concentration.

My current practice is avoiding influential substances as much as possible. I drink occasionally a cup of tea in the morning, mainly because of the cold season. I did multiple rounds of coffee in the past, but the benefits on concentration (and in recovering from hangovers) were not very significant on me, and I also had to add the side effects on my stomach and my sleep cycle, which is an important variable in my life.
Nearly every morning I see many students come in with hot, tiny espressos made by automatic machines. I guess it's more a placebo than a real help. In fact, they are usually not the most brilliant ones in the classroom, but the ones that sleep less.

Do you drink coffee? What is your idea of its benefits and disadvantages?
 

Image courtesy of Julius Schorzman.

Thursday, March 11, 2010

Standard Php Library and coupling

The Standard PHP Library is an object-oriented library, by default always included in the latest versions of php. Leveraging Spl in the right way is crucial to avoid compromising the design of an application and taking advantage of the most portable php library at the same time.
A wide use of the basic language structures is often the sign of a missing concept in the domain model. Passing around arrays and Iterators may be harmful if the implicit objects they represent do not fit with the operations available on them. We may have collections where elements can be removed, or repeated, in spite of business rules; queues and stacks that allow random access to all their elements, and so on. This contradicts the principle of defining and referring to the smallest possible interface.
Sooner or later someone will start calling a method that should not be here, and that by then could never be removed by substituting the object. Actually in php you can call methods even if they are not defined on the interface you are referring to (it's a dynamic language), but if you write unit tests passing in mocks and stubs, they will fail and tell you that the code is smelling.

Before looking for a remedy to these design issues, let's just analyze a little Spl classes and interfaces to put this discussion in context.
  • the Traversable interface and its Iterator extension would be perfect if php had generics capabilities built into the language: Iterator is a segregated interface that works well because it can be passed directly to foreach() constructs. The only issue is that Iterators that returns object of different classes can be mixed without type safety, so you may find code that expects a string Iterator and is passed a object Iterator.
  • Countable is a very good interface, with only one method. It's really hard to implement this interface with more than one semantic meaning.
  • SplQueue, SplStack, SplObjectStorage are only fast data structures, that have nothing to do with object-oriented design. So they're fine and perform well, but do not refer to them more than two or three times in your codebase (essentially wrapping them in explicit domain objects.) Really, a Queue or Stack that implements Iterator is a recipe for a disaster.
  • SplObserver and SplSubject are really... pointless. Patterns are solutions that are implemented with many variations every time they are taken into consideration. So it makes no sense to specify standard interfaces for patterns, and I see many problems in these ones: detach() may remain unused since php objects are short-lived. Also attach() may be implemented differently if there is only one observer, or a specific set of them. And notify() may be a private or protected method.
As was the case with Iterators, SplSubjects A which are meant for certain SplObservers accept other SplObservers that were meant to observe SplSubjects B, so that when they try to access the wrong SplSubject implementation they blow up because of calls to nonexistent methods. This is fake type safety and there is no language construct that takes advantage of these interfaces. You can just write This is a Subject in the docblock and it will be the same.
For a full analysis of the underlying design problems of Spl, see the related SOLID principles post.

As you may know, composition (and its specialization, wrapping) is usually considered the greatest friend of an object-oriented developer.
The basic Spl classes have too much methods and behavior. This is fine for them because they try to cover all the feasible use cases, but it's dangerous for Client classes because they may rely on operations that should not be available to them, becoming coupled to a large interface. A fundamental principle of type safety is that object should be interchangeable only if they are really interchangeable, not because they happen to have a similar structure.
This means that I would never pass an SplQueue in my class, because it has so many methods (22 public methods) that, for example, I cannot mock it consistently in testing. I would wrap SplQueue in a class that defines an (at least implicit) small interface, and that I can pass around without fear because only my explicitly defined methods can be called.
Long story short, try to wrap Spl data structures in your classes, that define the interfaces that you want, and never pass them around as-is. As all languages structures, they are catch-all objects: your code will suffer from a spreaded, large set of calls to their public methods, becoming pinned to them. They are a great tool to get something done fast, but hiding their existence from the rest of the codebase is fundamental.

Wednesday, March 10, 2010

Acceptance Test-Driven Development

I am halfway through reading Growing object-oriented software, guided by tests, a book that teaches Test-Driven Development in a Java environment. A review will come soon, since the process described in this work is really language-agnostic and interesting also for php developers.
However, the book's authors introduce a very productive practice, which consists in a double cycle of TDD:
  • a longer cycle, where you write acceptance (aka end-to-end) tests, deriving them from the user stories or formal requirements, and make them pass;
  • a shorter cycle contained in the first, which happens in the phase when an acceptance test is red: you write unit tests and make them pass until the related acceptance test does not fail anymore.

This approach is an implementation of Acceptance Test-Driven Development, and in particular makes you write several unit tests for every acceptance test (read for every feature) you want to add. Acceptance testing gives immediate feedback on the application's external qualities: simplicity of use and setup, consistency of the interface. At the same time, unit testing gives feedback on the internal qualities: decoupling, cohesion, encapsulation.
When I started employing the double cycle, getting in the zone suddenly became less difficult. The advantages of the TDD process were for the first time applied to the whole process, from the requirements formalization to the end of a feature's development:
  • test-first paradigm. By the end of the development phase, regression tests will be already in place, and the production code will be forced to be testable.
  • The definition of "done" is very clear (the acceptance test passes), and you are more likely to write only the mandatory code to get a green bar at the higher level.
  • measuring progress is easy: the number of acceptance tests that are satisfied (weighted by points). You can even write a set of acceptance tests for the whole iteration in advance and keep them in a separate suite, moving them in the main suite when they start to pass.
To be a bit more specific, the php technologies I use for the two cycles of development are Zend_Test for the acceptance tests suite and plain old PHPUnit test cases for the unit tests one.
Zend_Test is an extension to PHPUnit that lets me define a contract for the http interface of a Zend Framework application, assert redirects, check parts of the html response via css selectors, and even falsify request headers to simulate ajax requests. The unit tests usually have no dependencies on a particular infrastructure, so PHPUnit itself is a powerful enough tool to write them with.
By the way, triting an automated acceptance test suite is more difficult than writing unit tests, as there is more infrastructure that gets in the way and a large amount of details that may render the tests brittle. Fortunately Zend_Test takes care of almost all the infrastructure (aside from the database, which I reset in the setUp phase of test cases), and acceptance tests code can and should be refactored to avoid duplication of the implementation details. For instance, Css selectors used to assert on parts of the html response can be stored in constants with an expressive name, and the request creation can be wrapped in helper methods that are composed in actual test ones. Also custom made assertions are helpful in keeping the noise to a minimum.

I hope this technique will be useful for all test-infected developers. It certainly enhanced my productivity and will to get a green bar. :)

Tuesday, March 09, 2010

Practical Php Patterns: Observer

This post is part of the Practical Php Pattern series.

Today's pattern is the Observer one. The intent of this pattern is breaking a [usually one-to-many] dependency between objects by making the set of objects act as Observers of a Subject one, which notifies them when its state changes or is affected someway.
The result of the application of the Observer pattern is an effective reduction of coupling: often notifications are sent to disparate objects which are thus prevented to becoming entangled.
This pattern is a form of publish/subscribe, where a Mediator between publishers and subscriber is not involved.

The classic application of the Observer pattern is in maintaining synchronization between views of the same data (part of the Mvc paradigm).
Another useful application is the connection of external infrastructure whose existence the subject should not rely on at all. For example Subject can be an object from the domain layer, which accepts as Observer-implementors objects from the upper layers (or their Adapters), to send them events to catch. The Observer and Subject interfaces in this case reside in the domain layer.
There is a broad spectrum where the implementation of this pattern can fit, whose extremes are named push and pull styles.
  • In the pure push style, the Subject passes only the necessary parameters in the notification: this solution favors encapsulation of the Subject data.
  • In the pure pull style, the whole Subject is passed to the update() method: this solution favors reusability of the Observers on different implementations or subclasses of Subject.
Obviously implementations can be a mix of this two pure solutions, for instance using a ValueObject as the update() parameter.
Another variability factor in implementation is how references are kept between the various objects of the graph. The only mandatory field references are the Observer collection, which is maintained in the Subject. The only advantage of keeping a reference to Subject in the Observer implementations is to not pass it in the notification, or check that the passed object is the subject where it was registered. Though, a mutual association would have to be maintained, and this can be tricky.

Participants
  • Subject: interface that defines a protocol to set up a collection of Observers. Can sometimes be omitted by using the ConcreteSubject directly in method signatures.
  • Observer: interface that defines a notification protocol.
  • ConcreteSubject: stores the Observers and notifies them according to a contract, usually when its state changes (or when a notify() method is called).
  • ConcreteObserver: performs business logic operations upon a notification from a Subject is received.
The code sample implements a pull-version of the pattern, but without Observers keeping a reference to Subjects to avoid a cyclic graph, which would add unnecessary complexity to the construction process. I have not used Spl interfaces because they would not add any value here. The addressed problem is how to get status updates of a User object (domain layer) to be sent to external social networks by infrastructure services.
<?php
/**
 * Needless to say, the Observer participant.
 * The chosen style is pure pull, so the whole User object
 * is passed to update(). User is en entity in the domain model
 * so the Observer will be probably dependent on it anyway.
 * The gained advantage is that User do not know the concrete
 * class of any of its Observers.
 */
interface UserObserver
{
    public function update(User $subject);
}

/**
 * Subject interface is omitted. The ConcreteSubject
 * is used instead directly.
 */
class User
{
    protected $_nickname;
    protected $_observers = array();
    protected $_status;

    public function __construct($nickname)
    {
        $this->_nickname = $nickname;
    }

    public function getNickname()
    {
        return $this->_nickname;
    }

    /**
     * Accepts an observer. Note that we really don't need
     * a detach() method.
     */
    public function attach(UserObserver $observer)
    {
        $this->_observers[] = $observer;
    }

    /**
     * Updates the status of the user (and notifies Observers.)
     */
    public function setStatus($text)
    {
        $this->_status = $text;
        $this->_notify();
    }

    public function getStatus()
    {
        return $this->_status;
    }

    /**
     * May be public if you want the Client to control
     * the notification generation.
     */
    protected function _notify()
    {
        foreach ($this->_observers as $observer)
        {
            $observer->update($this);
        }
    }
}

/**
 * This ConcreteObserver is passed the User.
 * It can extract from the argument the data it needs (pulling).
 */
class TwitterStatusObserver implements UserObserver
{
    /**
     * We should send the new status to twitter
     * which will mirror it, but to keep this a standalone
     * code sample we'll simply print it.
     */
    public function update(User $user)
    {
        $nickname = $user->getNickname();
        $status = $user->getStatus();
        echo "$nickname has changed its status to \"$status\"\n";
    }
}

// Client code
$user = new User('Giorgio');
$user->attach(new TwitterStatusObserver);
$user->setStatus('writing PHP code');

Featured post

A map metaphor for architectural diagrams

It is a (two-dimension) representation of a pipe. The map is not the territory , but in software engineering terms they are models of it....

Popular posts