Michael J.A. Clark
Michael Clark is a Computer Science student from England providing freelance programming and design when not studying at Cambridge. Skills: C#, Sitecore, PHP, XHTML, CSS, AS3, Java, ML, F#.

Sections

Contact details

Email
mjac@mjac.co.uk
Skype
mjacdotuk
Twitter
mjacuk

Articles tagged reading

Steve Job’s biography surprises and enlightens

“If you are not busy being born you are busy dying” — Bob Dylan

Steve Jobs is a tech inspiration. He had failings as a family man, being “too busy to flush toilets” let alone be a loving father to four children, but as a business leader he created revolutionary products with imaginative leaps that were “instinctive, inspirational and at times magical”. They were also profitable: in 2010, Apple took 35% perfect of the operating profit of the PC industry from 7% of the revenue.

Walter Isaacson’s biography of Steve Jobs reveals his passion, fire and obsession over 650 pages of personal anecdotes.

Simplicity in design

Steve “saw differently” and understood “the notion of tools for human use”, creating all products under Da Vinci’s guideline that “simplicity is the ultimate sophistication.” The gardens around Kyoto, physical manifestations of Zen Buddhism, were “the most sublime thing [he had] ever seen”, and Job’s only digital book was the Autobiography of a Yogi, a guide to meditation and spirituality that he read yearly.

Experiences on LSD were among his most important, and perhaps contributed to his intuitive understanding that all product components must combine to form a cohesive whole: Apple’s most successful products were seemless combinations of hardware, software and distribution. “Producing technology requires intuition and creativity” and “producing something artistic takes real discipline”.

Steve preferred to go without than use a badly-designed product as “material possessions cluttered life instead of enriching it”. His preferred products included Henckels knives, Braun appliances (Dieter Rams “weniger aber besser") and Bang & Olufsen audio equipment.

Masterful communication

When criticized about the late release of NeXT Step, Job’s snapped “It’s not late. It’s five years ahead of its time.” His communication always had focus and exact timing. Another gem showed his clarity of thought: “God gave us ten styluses” was an instant logical rebuttal of Microsoft´s trust in the stylus. He noticed and reprimanded common mistakes in business communication like using “slide presentations instead of thinking”.

With personnel, he was both caring and harsh. His partner Woz had the skill of 50 average engineers and Steve aimed to build entire teams of these A-players (following Oppenheimer’s example). This helped the superstars, who only wanted to work with equally talented peers, but also brought the fear of being discarded.

Focussing on excellence

The motivation behind Apple was to “build an enduring company where people were motivated to create great products”. Profit was important to continue making these products and quality was enforced with a culture of brutal but empowering honesty.

Apple considers details other companies ignore, even the “tactile experience” of unwrapping the box sets “the tone for how you perceive the product inside”. “Deciding what not to do is as important as deciding what to do” when creating companies and products, time saved focussing on core features users wanted could be used to refine the entire product. Companies should “focus on five products” as more will not be beneficial.

Execution is as important as the ideas that drive innovation and successful execution requires an understanding of the principles behind a project. A project is not done until it ships and the journey to shipping is the reward.

Personal investment

The iPhone was created by a team who made themselves the perfect phone and the development of the iPod and iTunes was facilitated by Steve’s love of music. His personal collection contained the complete discography of Bob Dylan and The Beatles, with a few unusual choices such as the Benedictine “Spiritus Domini” and performances from Yo-Yo Ma, who played cello at his funeral.

After Henry Ford created the first mass-produced automobile, he remarked “if I had asked people what they wanted they would have told me a faster horse”. Steve Jobs drove change through his recognition of excellence.

Thanks for reading, please add your comments.

High Performance JavaScript techniques

High Performance JavaScript is a great introduction to performance considerations but the coding guidelines will become outdated as JS implementations advance.

Variable scope

Each JS function has an internal scope chain. When a function executes, the JS engine creates an execution context that defines the execution environment of the function. This initially contains the function scope chain, fixed on function creation, appended to the activation object, containing locals/arguments for this execution.

Elements at the beginning of the scope chain, like local variables, are accessed faster during execution. Storing a reference locally (though this has a smaller effect on modern browsers) can mitigate the depth penalty, producing a significant speedup in older browsers if the object property is read multiple times.

DOM manipulation is costly

DOM/JS browser implementations are often in separate modules, requiring an expensive ‘bridge crossing’ when communicating.

To improve performance stay within ECMAScript and consider converting HTMLCollections to arrays if they are going to be iterated over (always cache the length). Filter elements using native methods and use CSS query selectors for speed improvements over tree traversals (verbose checking). Old IE versions suffer significant performance degradation with :hover CSS selectors.

Event delegation improves performance by reducing the amount of event handlers. The event handler is added to the parent element and captures all related events on its children through event bubbling. Further propagation can be stopped if the event should not bubble (preventDefault/stopPropagation or returnValue/cancelBubble). Workarounds are required to delegate the the focus event in all browsers.

Causes of DOM reflows

  • Visible DOM elements are added or removed
  • Elements change position/size
  • Content changes
  • Initial page renders
  • Window resize

Reflow prevention

Avoid flushing the render queue to improve performance. It is flushed when offset*/scroll*/client* properties are accessed after the DOM has been manipulated.

When performing multiple changes it is more efficient to remove the element from the document flow by appending it to a DocumentFragment. Then apply all the changes and reappend to the main document.

If performing animation take the animated element out of the flow of the page so that the rest of the document is only resized once.

Code performance

Algorithms and loops

Lookup tables implemented with JS objects are extremely fast. Of all the C-style style loop constructs, for-in is the only construct that is significantly slower. Caching array.length can provide performance improvements.

Duff's Device decreases the number of loop iterations and increases performance (significantly past 1000 iterations) as the expensive of causing the function to become unreadable. On the other hand, functional iteration using arr.forEach is more readable but takes 8x the time to execute. It is a trade-off between readability/maintainability and performance.

The call stack size is only 500 in Safari 3.2. Avoid tail recursive functions for high iterations and opt for loops instead. As with most languages, memoization is a useful technique to reduce execution time by calculating results once.

Strings

Array.join on a number of strings has the highest performance in most browsers. Use native string functions to search for literal strings instead of regular expressions. The YUI compressor performs string folding at build time, improving performance and reducing code size. IE7 has quadratic running time for native string concatenation.

With regular expressions, backtracking can destroy performance (consider (A+A+)+B), especially when using non-greedy quantifiers. Atomic groups can be used to prevent backtracking (natively as (?>regex) or emulated with (?=(regex))\1). Many performance problems can be preventing by ensuring that two parts of a regex cannot match the same parts of a string (use an emulated atomic group as a last resort). Cause more failures (use cat|bat instead of [cb]at).

HPJ goes through a number of String.trim alternatives and proposes a hybrid solution. Browser performance characteristics differ so wildly that I recommend browser detection to pick between the solutions. Lazy loading replaces the method on first use so that subsequent calls only use the specialized version; conditional advance loading uses upfront detection and replacement before first-use.

Browser threading

Finish JavaScript tasks quickly because most browsers stop queuing tasks for the UI thread while the JavaScript is executing. The maximum length of time for a single JS call is then 100ms (due to Miller's usability research). If it cannot be executed within that time, yield control to the UI thread using timers with at least 25ms to allow for most UI updates.

Web workers are separate processing threads for JS with no ties to the browser UI.

Data transmission

To cache responses use GET and set an expires header (maximum length is a year RFC 2616). This can be set in Apache directives using ExpiresDefault. It is also possible to use a local URL to object cache in JS.

AJAX requests

XMLHttpRequest allows asynchronous sending/receiving of data. The server response can be interacted with while the request is still being transferred by listening for the readyState event. Use GET for idempotent requests that can be cached. POST requires at least two HTTP packets but is necessary when the parameters exceed 2048 characters.

Dynamic script tag insertion can be used to request data from a server on a different domain.

Multipart XHR uses base64 encoding, in conjunction with a delimiter not present in base64, to provide multiple resources from one HTTP request. readyState can be used to process completed sections in the XHR response before the entire response is downloaded. None of the resources can be cached by the browser.

Beacons are Image objects used to send GET data to the server. They have very little overhead but response data is limited to width/height. Usually there is no response, instead a 204 No Content header.

Data formats

Favor lightweight formats.

XML is extremely verbose and slow to parse. It has no place in high performance AJAX. Parsing XML can be made faster by using XPath instead of DOM methods like getElementsByTagName.

JSON is the cornerstone of high-performance AJAX. HPJ presents different JSON formats: verbose, simple and array. Array is the fastest but least readable. Custom formats are the fastest but require custom parsing for each format.

Loading JS into the page

Place <script> at the bottom of the <body> because browsers block until the head is completely loaded. JS also requires up-to-date style information and preceding CSS imports can prevent asynchronous downloading. The defer attribute prevents blocking, scripts are downloaded asynchronously and executed just before the onload event.

Dynamically created <script> elements begin downloading when added to the DOM without blocking other page processes. Add them to the head to prevent IE throwing exceptions. When the code is ready the load event is fired (readyState in IE), see the book for details about these events.

The recommended nonblocking pattern is to download code to dynamically load JS then use that to download and execute the rest of the JavaScript. This increases the perceived loading time of the page. Loaders in YUI 3, LazyLoad and LABjs take different approaches and are worth learning.

Building and deploying

Common portable build tools are Apache Ant and make. Apache Ant can be used to concatenate all the JavaScript code into a single file. The C preprocessor can be used with JavaScript to remove debug statements before release. YUI compressor can be used for JavaScript minification. The Closure Compiler from Google (2009) has advanced optimizations.

Packer provides decompression at runtime but this incurs a fixed cost of 300ms. smasher preprocesses JS files in PHP.

(read October 2011)

Thanks for reading, please add your comments.

Lessons learnt from The Pragmatic Programmer

In October 2011 I read The Pragmatic Programmer: From Journeyman to Master by Andrew Hunt and David Thomas. This article is a summary of the major points I picked up.

Read this book if you are serious about software engineering. Some of the sections apply to other areas of life too: all skills are progressed with small continuous improvements -- the Kaizen principle -- and over time these improvements accumulate, resulting in proficiency then mastery.

Being a pragmatic programmer

The book idealizes the idea of the pragmatic programmer. These noble individuals are inquisitive, think critically and care about their craft (including adopting early). Instead of making excuses, they provide solutions to problems and take responsibility for mistakes.

Programming is an intellectual activity and the value of a programmer is based on their knowledge portfolio. The portfolio must be built and maintained with regular investment and diversification: read at least one technical book per quarter and learn a new programming language every year; learn more and emerging technologies.

If you want to be a pragmatic programmer, actively participate in local user groups for career opportunities, and always think critically about what you read and hear. Develop catalysing improvements and let teammates marvel and join in instead of communicating without action. Your signature should be an indicator of quality.

Communication is imperative

Communicating is an important part of a programmer's role and effective communication results in influential positions. When discussing anything, always listen first. Before beginning your communication, plan and refine your statement/ideas to have the optimum value for your target. This includes adjusting the style of delivery to suit their understanding. Choose the moment of communication wisely, understanding audience needs/priorities. If in doubt, ask about their preferred delivery style. To understand an audience, learn the WISDOM acrostic:

  • What do you want them to learn?
  • What is their interest in what you've got to say?
  • How sophisticated are they?
  • How much detail do they want?
  • Whom do you want to own the information?
  • How can you motivate them to listen to you?

Rapidly respond to all emails and voicemails, even if it has to be a simple reply or that you will get back to them later.

Tools for pragmatic programmers

Tools amplify talent: productivity soars when you use a single editor well and understand the command shell. Always use source code control and utilize it to produce automatic, repeatable product builds. Binary formats divorce data from meaning; text formats are resistant to obsolescence and can leverage most computing tools.

Knowing a text manipulation language like Perl is useful for active code generation (generating structural source code from schemas) and passive code generation (create new source files, save typing).

Pragmatic projects

Successful systems are those that meet user requirements, thus use users to help decide whether a system is good enough to ship. Gently exceed your users expectations and delight them. Fix or comment on broken code immediately to prevent the Broken Window trigger mechanism, where the first signs of neglect cause entropy and decay.

A requirement is a statement of something that needs to be accomplished. Document business policies away from the more generic requirement, as policies change frequently and may end up as metadata in the final application. Solve the business problem and don't just meet the stated requirements. Work with a user to think like a user. Good requirements documents remain abstract as the simplest statements represent the business need best. Requirements are need. Abstractions live longer than details.

Point out the cost of each new feature against the project schedule to the sponsors of the project. This provides an accurate picture of requirements growth Use a project glossary that contains the specific terms you use. When faced with an intractable problem enumerate all avenues, even though that seem daft. Some things are better done than described. With specifications there is a point of diminishing or negative returns as they become more detailed. Don't be a slave to formal methods because these generally require explanation to end users (UML). Understand the whole system instead of specializing.

Estimate to avoid surprises. The best estimate comes from someone who has already created a similar project. Create a model of the product, break it into components with parameters, and give each parameter a value. Record the estimates and compare them to measured values as the product is created. The schedule should be iterated with the code to provide the most accurate scheduling estimate. Take time with estimates instead of producing them off-the-top of your head.

Assumptions that are not based on well-established facts are the bane of all projects. Do not program by coincidence, document assumptions and test them. Don't let existing code dictate future code, be ready to refactor because the impact will be less than cost of not making the change. Refactor when there is duplication, nonorthogonal design, outdated knowledge, or to improve performance. It must be undertaken slowly, deliberately and carefully. Have good tests before you begin refactoring. Always take short deliberate steps.

Team orthogonality is inversely proportional to the number of people who have to be involved when discussing changes, separating responsibilities increases efficiency. There are no final decisions in software construction and team leaders that ignore this have their eyes forcibly opened when the future arrives. Organize teams around functionality not job functions.

Pragmatic software principles

The DRY principle (Don´t Repeat Yourself) states that every piece of knowledge in a system must have a single authoritative representation. Low-level comments violate this principle by duplicating the information held in the code. Taking short cuts makes for long delays. To reduce interdeveloper duplication have a technical and capable team leader with a clear design for the system, so that code can be reused.

Aim for orthogonal components. When components are orthogonal, their execution is independent, providing more combined functionality. Modules should be self-contained, independent and have a well-defined purpose. When creating classes, normalize data representations according to the business model and use accessor functions to decouple the internal class data from external calls. Singletons can lead to unnecessary linkage when they are used as global variables.

Put abstractions in code and details in configurations, outside the code base. Configuration files allow an application to be customized without recompilation, extremely important in critical live systems and useful when distributing the same core app to different clients (only changing metadata). Long running processes should have a method to dynamically reload metadata while running to prevent downtime.

Be careful about how many modules you interact with and how you came about interacting with them. The Law of Demeter prohibits accessing a third object's modules and reduces errors by reducing the response set size (direct function invocations). Instead of digging through a hierarchy, ask for what you need directly. Note that performance can sometimes be improved by coupling modules, sharing information about class internals.

Programming methods

Tracer bullets are partially functioning code modules that can be adjusted iteratively with feedback from users. They provide the client with early demonstrations and can be changed rapidly, being lightweight compared to a full (perhaps incorrect) implementation.

Prototypes are disposable modules that reduce the cost for correcting design mistakes by analyzing and exposing risk at the start of a project. Anything critical or difficult should be prototyped. Prototypes do not have to be correct, complete, robust or styled. With architectural prototypes, ensure that module responsibilities and collaborations are well defined and that coupling is minimized. Estimate the order of the algorithms and test these estimations against measured data from the prototype.

Domain languages can be used express business needs and allow programming close to the problem domain; this results in specialised code that is adaptable to changing business requirements. Domain languages can be compiled using existing tools like Yacc/Lex into C or another target language. Complex workflow requirements can be encoded in a rule-based (expert) system embedded in the application so it can be configured by writing rules instead of code.

Use automatic procedures like cron and makefiles. Web content should be generated automatically from information in the repository and published without human intervention. Teams with automated tests have a better chance of success.

Comments should discuss why something is done. Code is read more times than it is written, spend time writing clear commented code (sensible variable names). Always put a date on documentation so users can see when it is updated.

Concurrency and resources

Always design for concurrency. An important part of this is decoupling time and order dependencies. The hungry consumer model provides quick and dirt load balancing. Resources should always be allocated in the same order and freed in the opposite order to reduce the possibility for deadlock.

Events are used to signal changes about an object minimizing coupling with the other interested objects (thereby increasing reversibility). To prevent spamming use a publish/subscribe protocol. In MVC, models have no direct knowledge of views or controllers, views subscribe to changes in the model and logical events from the controller, and the controller controls the view and provides the model with new data. Always consider having a separate debugging view.

Blackboard solutions decouple objects completely: shared information is stored in a central place so that contributors and arrival order is irrelevant (based on tuples spaces). JavaSpaces are an example, supporting read/write/take/notify operations.

Pragmatic paranoia

Do not trust or expect yourself to write perfect software, you cannot. Debugging is just problem solving. When a bug occurs do not panic and prioritize on fixing the problem. The fault may be several steps removed. The best way to start fixing a bug is to make it reproducible; this also means that you know when it is fixed. Data visualization can reveal far more than simple data display and rubber ducking, explaining the problem to another individual, can cause the solution to become apparent. Usually the fault lies with your code not well tested 3rd party software. Once the bug is fixed, determine why it was not caught earlier.

Design and deployment

Design by contact verifies that is a program is correct, that it does no more and no less than it claims. It also forces requirements to the forefront. Each contract contains preconditions, postconditions and class invariants. The latter two are guaranteed if the preconditions are obeyed. Attempt to write lazy code, code that has strict preconditions and return the minimum possible. Assertions can partially implement contracts in languages without native support. Crash early at the site of the problem.

Errors should always be on the side of not processing a transaction instead of duplicating it, err on the side of the consumer. Always have a default case, because the impossible can happen. The code is no longer viable if the impossible just happened so it must be terminated.

Always leave error checking (assertions) turned on. Use exceptions for exceptional problems.

Testing

Build testing into the software from the beginning then test each piece of the project independently, then together. Unit testing should attempt to ensure that a given unit honors its contract. When you design a module or even a single routine you should design both its contract and the code to test that contract. Accessible test code not only provides an invaluable example of code use, but also a means to test regressions and validate future changes.

Develop a standard testing harness for the project. Test early, often and automatically.

Unit testing verifies individual modules. Integration testing shows major subsystems interact successfully. Regression tests compare current output with previous (known) values. Use real world and synthetic data to test and stress boundary conditions. Saboteurs can be used to test testing. Coverage analysis tools can determine the lines of code that are hit with tests. If a bug slips through the net, add a new test to trap it next time -- find bugs once.

Inspiring quotations

  • "It's easier to ask for forgiveness than it is to get permission" Grace Hopper
  • "An investment in knowledge always pays the best interest." Benjamin Franklin
  • "The limits of my language are the limits of my mind." Ludwig Wittgenstein
  • "Perfection is achieved, not when there is nothing more to add, but when there is nothing left to cut away." Antoine de Saint-Exupéry

In conclusion

The Pragmatic Programmer should be a constant figure on the bookshelf (buy from Amazon). This short summary does not do it justice. I hope you enjoy it as much as I have.

Thanks for reading, please add your comments.