Big Name Blog http://heybigname.com/blog 2013-01-21T11:58:16+00:00 How to Become a Better Developer: Straight Talk http://heybigname.com/2013/01/21/how-to-become-a-better-developer-straight-talk/ Mon, 21 Jan 2013 11:58:16 +0000 Being a good engineer is a matter of experience, knowledge, and personal philosophy / attitude. Each of these things can be individually improved upon. Intentionally analyze where you are in your career and in the predispositions of your personality. Understand where you're most lacking and always work towards improving that area.

A developer who is constantly growing is a happy developer that other people want to work with and learn from. A depressed developer stuck in a dead-end learning cycle is a liability to their team and to any project in which they’re involved.

You are not just some code-monkey. You're a problem-solver whose influence significantly impacts (for better or worse) the quality of your organization.

Here are some tips on how to become a better developer. (Special thanks to the developers on FreeNode for contributing to this list of ideas.)

Learn from advanced engineers.

I come from a time pre-internet. My friend Jeremy was the only other person that I knew who was interested in creating software. We were starved for information. We’d scour bulletin-board systems to find source-code that we could read and learn from. Much of it was too advanced for us, but that’s what we had.

Now, the internet is full of guides, documentation is easy to find, and we have screencasts that show us step-by-step how to make new applications. These are great resources and we’re lucky to have them. But, many developers forget about the value of directly learning from the work of others.

Read the code of experienced engineers and aspire to truly understand WHY they made the choices that they have. Work with others to understand. Put away your ego and just study. You’ll be surprised at how quickly you change your tactics.

Fabien Potencier is a PHP heavyweight and he’s a big name in the Symfony scene (consequently the entire PHP scene). The Symfony source is some of the best material to learn from this is available in the world of PHP. Say what you want about Symfony (or better yet, just don’t say anything about it) but there’s a lot that can be learned here.

Taylor Otwell is the engineer behind the upcoming framework Laravel 4, which has been modularized into a suite of components entitled Illuminate. He’s utilizing the power of Composer to put real control into the hands of PHP developers and to improve the quality of the codebase and communities by refusing to lock developers into a specific set of functionality. The Illuminate source is a superb resource.

Take special care to look at unit-tests as well. There’s just as much to be learned here. Unit-tests can function exceptionally as documentation for the capabilities of a project.

Learn technologies that are specifically different from those that you already know.

Do you only know how to develop with PHP? Learn Python or C#.

Only ever use traditional server-side application development techniques? Learn a JS MVC framework like EmberJS. Only use MySQL? Learn ElasticSearch or PostgreSQL.

You don’t need a use case to learn a new technology. Chances are that once you learn them you’ll discover opportunities to use them. More importantly, if you have only used a couple of programming languages, then your mind is simply not thoroughly primed to understand the variety of solutions that you have the power to implement.

If you’re relying on a specific stack (LAMP, for example) then you are literally unable to use the "right tools for the right job." The saying is, "If you only have a hammer, you tend to see every problem as a nail."

An added benefit of learning new technologies is that with every bit of knowledge gained, the next becomes increasingly easy to acquire. This is why experienced developers can pick up a new technology in a day, where a beginner could spend months. Their brains are already primed with all of the concepts necessary in much the same way that learning a 3rd spoken language is often much easier than learning your 2nd.

Join a community by attending user group meetups and IRC.

This is one of the most important aspects of becoming a better developer. You’ll be exposed to new ideas via presentations, etc. But, most importantly you’ll be exposed to intelligent and motivated individuals that fill you with the kind of fuel that propels you through the next couple of weeks of enthusiastic learning. The more regularly you attend, the larger gains you’ll see.

Maintaining a high level of motivation and energy is one of the most important aspects of improving yourself as a professional engineer. If you feel like you don’t have the time to do this sort of thing then YOU are who I’m talking to. With proper management of your brain’s chemicals and natural human tendencies you can be a lot happier and a lot more productive doing what you do.

Take an interest in design patterns and agile development.

While it’s not necessary to buy the Design Patterns bible, it’s necessary to appreciate what design patterns are and what control they give you.

Design patterns teach you both solutions and problems. There’s a good chance that with each new design pattern learned you’ll realize problems that you never considered. You’ll realize how tightly-coupled your code has been and you’ll start to realize that good software design can significantly lower the cost and THE BUSY WORK associated with long-term maintenance of an application.

The best developers are able to quickly adapt their software to changing requirements without having to deal with a bunch of the most mindless and boring types of development.

Becoming a better engineer means being less bored, solving problems faster, changing codebases faster, and being able to do more without being as exposed to the negativities of the crunch.

Don’t create ignorant self-serving opinions.

How often do you hear things like, "I hate Symfony, it’s too bloated.", "I hate ORM because it’s not as fast as my raw SQL implementations.", "I hate Rails for all of the magic." or, "I really just don’t see the point of Coffeescript?"

Frankly, someone designed these technologies for a reason. They all have their advantages and disadvantages. There's a good chance that the decisions that define these projects were based on solving problems that you haven't yet encountered and don't yet know how to plan for. They may also have philosophical differences that lead them towards a different kind of solution than you. This doesn't make their solutions wrong.

The reality is that we have different opinions not only because of the differences in our knowledge and experience but also because of the differences in the problems that we have to solve.

It’s important for engineers to have experience with a wide array of tools and to understand why to use one over another. As stated earlier, if you don’t know more than one software stack then you have no way to use the best tool for the job.

It’s certainly reasonable to dislike a technology because of it’s negatives. But, unless you’ve real-world experience then it’s possible that you just have the opinion because someone that you trusted has it or because you want to give yourself the opportunity to not feel compelled to change. Either way, this is a really bad practice.

Realize what you don’t know and embrace it. Ignorance is a problem to be solved like any other. We're professional problem-solvers, after all.

Rely on your own intelligence.

I have been a provider of IRC / forum support for various technologies for over 3 years now. This is an important point that I feel very strongly about.

You don’t install a technology, play with it for a few minutes, hit a problem, then immediately rely on the help of people on IRC or forum. The people on IRC or the forums that have the knowledge to help you have time as a limited resource. When you’re being helped by someone, they’re not able to help someone else.

Have you ever gone into an active IRC channel for a technology, asked a basic question, and have been simply ignored while other people are around asking more complex questions and getting help? It’s because these people believe that you’re plenty competent enough to solve your own problem without too much trouble and that you shouldn’t be in IRC asking and waiting for a solution. You should be studying the documentation and codebase and creating one.

The hard and fast rule is that you must ask yourself "have I really tried?" and if the answer is "no" then start there.

The real advantage of having access to these experienced individuals is in gaining perspective. If you’re new to development and an experienced developer teaches you her approach to development over the course of a few hours a week that is SIGNIFICANTLY more important than them teaching you something rudimentary like how to use the authentication system or pass variables to a view.

Anyone can learn how to do that by reading the documentation, or diving into the source, or reading the code of other people’s applications.

Documentation is a great resource when it’s available. You can usually learn the API from the API documentation and you can usually get some important perspective on how to think about application development with a particular technology from a ‘getting started’ guide or a more general documentation format.

These resources are here and they’re important. It’s important that you read through the entire documentation for a technology before asking questions in IRC, maybe even multiple times.

If you can’t find what you need then read the API documentation. EmberJS has a good example of API documentation. Here you can see classes and methods and understand what each do.

Source code itself is good documentation. Maybe if you’ve read through the guide-based documentation, api documentation, and other people’s source and question / answers on stackoverflow.com and you’re still having routing problems then you can ask for help from someone else. But, if you’re asking how to make classes load from different folders or something similarly fundamental, you should be heading directly to the source to find your answers.

The source is far more accurate at answering questions than anyone in IRC, on forums, or anywhere else. The source is the part that actually means something.

Don’t short-circuit your intelligence. You’re an engineer. Some aspects of the source etc may be difficult for you to wrap your head around but you can do it and it’s not going to take the rest of your life to understand the code either.

You may say that it just takes too long and that you’re under a deadline. You may well be under the deadline because for much of your career you’ve relied on other people to do your work for you. If you dig in and learn things on your own then you’ll have real knowledge built-up and that knowledge will be yours forever, more or less.

How to Get Help

Now that you've tried to do a good job and have exhausted the other resources it may be time to ask for some help. When doing so it's important to realize that it's rare to find experienced people that are willing to answer your question. Respect the time that these people provide as a free service.

Prepare a list of things that you've tried, all relevant source code, and the exact errors or problems that you're seeing. Read the resources that you've compiled and make sure that they all make sense. It's rude to force someone who is providing free help to do all of the discovery work necessary to be able to sufficiently answer your questions. Give them the best possible set of information from which to work and you will be appreciated and respected by everyone involved. A combination of your work and the work that others expend trying to help you can help people who are otherwise unrelated to you and your problem learn new things.

You should read What Have You Tried?.

Never call anything technical "magic".

We’re engineers. We’re supposed to be the people who denounce witchcraft and explain the unknown with rational answers and utilize thorough analysis to provide pragmatic solutions to complex problems.

We have no business being afraid of the truth. Am I the best programmer? Are you? Are either of us even CLOSE? The answer is no, not by a long-shot. But, we’re professionals. We push forward and improve our philosophy and our toolkit. That’s our job.

Computer Science is too big a field for any of us. As time moves on, specialization becomes increasingly granular and we become increasingly specialized. However, in the end we ALL benefit from a healthy philosophical approach.

We must not be afraid of the unknown. We must embrace it. That is the only way forward and in this profession, if we’re not moving forwards then we’re steadily moving backwards.

]]>
One-Hour Makeover - DoggySnooze.com http://heybigname.com/2012/12/31/one-hour-makeover-doggysnooze-com/ Mon, 31 Dec 2012 13:59:23 +0000 Web designers never stop designing – even when we’re just browsing the web.

In my day-to-day surfing I’m always coming across sites that I’d love to redesign, whether they sell products I love, contain challenges I’d like to work with or just call to me for some reason.

That urge is the catalyst for a new series I’m calling One-Hour Makeover. In each One-Hour Makeover, I want to refresh a site and create a new Photoshop mockup in just 60 minutes. The results might be a little rough, but each site only gets one hour.

DoggySnooze.com

The site that launched the idea for this series is DoggySnooze.com.

I first saw this brand’s absolutely gorgeous dog beds via fab.com. When I checked out the DoggySnooze site, I noticed that the beautiful product photography was being dwarfed by a design that didn’t provide the sophistication that $150+ dog beds need. All of the great craftsmanship that had gone into the product was lost on the site.

My goal with the DoggySnooze refresh was to produce the same feeling of elegance as the product itself. The idea was to introduce the product, clearly list its unique features, and get people into the shop to discover more.

What I like about the makeover: It shows off the beds and put them at the forefront.

What I could have done better: I would like the call to action higher on the page, and the paw prints in the feature list should be replaced with something more sophisticated.

All in all, I’m pretty happy with this makeover.

Do you know a design that needs a One-Hour Makeover? Let us know!

]]>
We Wrote a Laravel Book! http://heybigname.com/2012/12/02/we-wrote-a-book/ Sun, 02 Dec 2012 10:56:44 +0000 We're proud to announce the release of our first book. Laravel Starter is a "getting started" guide to Laravel 3.

Laravel Starter Book Cover

I've been intending to write a book for some time. Packt Publishing contacted me and it seemed like a good time to get started. Being a Laravel team member and an active member in the Laravel community I have gained quite a bit of experience regarding the kinds of questions that developers new to Laravel have. I used this experience in determining what topics to cover as well as how thouroughly to cover each topic. I'm very happy with the results and am quite surprised at how much information I was able to pack into the book by the end of the project.

The primary chapter guides the reader step by step through creating an user administration system with authentication. It was also important to me to talk over Eloquent relationships, bundles, Laravel's authentication system, filters, and validation.

If you're new to Laravel check it out. I feel like it's a great way to get started getting into the mindset of Laravel developer.

The book is available for purchase in print or as an ebook here.

]]>
What We've Been Up To at Big Name http://heybigname.com/2012/10/05/what-weve-been-up-to-at-big-name/ Fri, 05 Oct 2012 09:41:00 +0000 Big Name has been pretty busy of late and we've updated our work section to reflect just that.

AccountsPortal.com

Big Name provided design services for this UK-based accounting software company. AccountsPortal.com was looking for a site design update that was simple, clean, and effective. We handed off our design and we think they did a nice job implementing our suggestions.

AccountsPortal.com

MomMeetMom.com

Mom Meet Mom helps busy moms discover new friends and schedule play dates.

We're developing the site now and just launched the sign-up page. We're very excited about the technical and interface challenges ahead. We won't be building a dedicated mobile app, so responsive design decisions will be at a premium. Shawn is pushing Laravel to its edge, and he's implementing a lot of great solutions to provide an optimum experience.

MomMeetMom.com

RealChangeNewYou.org

Real Change New You was built to provide recovery services for individuals with drug and alcohol addiction and/or HIV-positive lives. With Big Name's development help, case managers now can interact with participants via the site, text messages, forums, and video services.

RealChangeNewYou.org

ScreenCloud.net (Re-launching Soon)

Having recently converted to Linux, Justin found the ScreenCloud.net services to be very attractive. The ability to have a screenshot uploaded and a link automatically added to the clipboard was huge! So we reached out to offer a hand with the site's design and identity. We're wrapping up some of the last of the app assets and a full launch is imminent.

ScreenCloud.net

]]>
PHP Method Chaining http://heybigname.com/2012/10/03/php-method-chaining/ Wed, 03 Oct 2012 10:37:56 +0000 I wrote this up to answer a question on FreeNode #Laravel and I thought that someone else might find it helpful. A basic overview of how method-chaining works in PHP.

class QueryMaker
{
    $table = '';
    $field = '';

    // this is a static method, it doesn't 
    // run on an object, it only runs on a class
    public static function make()
    {
        // create an instance of class 
        // QueryMaker and return it
        return new static();
    }

    // this is not static, it doesn't run on 
    // a class, only on an object
    public function setTable($name)
    {
        $this->table = $name;
        return $this;
    }

    // this is also not static
    public function setField($name)
    {
        $this->field = $name;
        return $this;
    }

    // again, not static, just renders
    // the "query"
    public function flush()
    {
        return "select {$this->field} from {$this->table}";
    }
}

Here is the implementation with method chaining

$query = QueryMaker::make()->setTable('users')->setField('name')->flush();

Here is the implementation without method chaining

$object = new QueryMaker();
$object->setTable('users');
$object->setField('name');
$query = $object->flush();

// the output is: select name from users

The methods setTable() and setField() return $this. In that context $this is the QueryMaker object that was created by make().

Let's go step by step:

$query = QueryMaker::make()->setTable('users')->setField('name')->flush();

The static method QueryMaker::make() returns an object instantiation of the QueryMaker class.

$query = $object->setTable('users')->setField('name')->flush();

$object->table is set, setTable() returns the object instance.

$query = $object->setField('name')->flush();

$object->field is set, setField() returns the object instance.

$query = $object->flush();

The flush method is called on the object, returning the string.

]]>
Announcing bigto.do | FreshBooks Time Tracking For To-dos http://heybigname.com/2012/05/22/announcing-bigtodo-freshbooks-time-tracking-for-to-dos/ Tue, 22 May 2012 08:10:23 +0000 Today we are happy to announce bigto.do! bigto.do is a FreshBooks add-on for tracking time on your to-dos. We love FreshBooks, but we wanted to be more efficient when it came to incorporating our to-dos with time tracking. bigto.do is an add-on that will pull in all of the projects from a FreshBooks account and allow users to instantly start tracking time on any to-do item they create.

Currently, we're looking for beta testers to work with us and make this add-on something great for FreshBooks users! If you're interested or know someone that might be excited about this app, please sign up at bigto.do or share this post.

The app will be totally free! Many FreshBooks users are already subscribed to a paid plan and we didn't want to add to that line item.

If you have questions or something you'd like to share, feel free to reply below, tweet @bigtodoapp, or contact us directly at info[at]bigto.do.

]]>
Introduction to the Form Model http://heybigname.com/2012/05/22/introduction-to-the-form-model/ Tue, 22 May 2012 07:10:23 +0000 Forms are often used to interact with a specific model such as a user or a blog post. However, in many circumstances a form may collect data that is related to multiple data models.

It may also have special validation requirements that have little to do with the underlying data, such as captcha and password confirmation. Consequently, it often makes sense to create a form model.

A form model represents the data needs of a form. This may be validation alone, storing values for form select drop-downs, having custom methods to generate data for the form, or managing persistent data in a session to make multi-page forms simple.

In this video I discuss modeling forms and introduce a form base model for Laravel.

More documentation and information can be found on the project's Github page.

]]>
Why CodeIgniter is Dead http://heybigname.com/2012/05/06/why-codeigniter-is-dead/ Sun, 06 May 2012 10:06:49 +0000 I've written many CodeIgniter tutorials, recorded a dozen screencasts, and participated in the #codeigniter IRC support channel for years. Consequently, many people ask me why I no longer use it. I realize that this article is not particularly flattering. But, I've answered this question enough times to warrant a post, so here it is.

CodeIgniter has been the go-to framework for programmers new to PHP frameworks. It is relatively easy to use, the documentation is widely considered to be good, and there is a large support community (there are currently 140 people in the CodeIgniter IRC channel). It has stood as the most popular PHP web-development framework for years. Consequently, there are many screencasts, written tutorials, and third-party libraries available. CodeIgniter is built around the concept of legacy support. So, its design is structured around the capabilities of PHP4.

However, CI has aged poorly due to a combination of legacy support between major versions and a virtually complete lack of leadership. Despite the emphasis on legacy support, recent versions of CI require PHP 5.2. PHP 5.4 is the most modern stable release and 5.3 is now available on any reasonable host. (If your host doesn't support PHP 5.3 then jump ship as soon as possible.) By providing legacy support (changes to the framework rarely require any changes to your code-base) CodeIgniter has been unable to implement any of the features available in 5.3 that give developers more flexibility to create elegant solutions to problems.

Since CI doesn't use any of the new features, best-practices suggest that its users should avoid them in order to provide standardized code. It should be easy to find and hire a PHP developer who is versed in CodeIgniter and mismatching a bunch of code-styles is a bad way to approach that goal.

When it comes to code modularity CodeIgniter is one of the worst performers in the industry. CodeIgniter is not built using any modular design pattern so all solutions are after-thoughts that were developed by members of the community. Out-of-the-box CI supports libraries (basic classes), helpers (global function declaration), and plugins (the same as helpers, these are not used). These are all different versions of the same concept separated by intent.

There are some third-party modularity solutions available. The oldest and most powerful of these is Modular Extensions by wiredesignz. It allows the implementation of HMVC modules. Unfortunately, in order to implement this he was forced to permanently alter core system files and this makes the code brittle. Issues can easily arise from upgrading CodeIgniter. As a long-time member of the #codeigniter IRC support team I can attest to the amount of issues that users end up running into as a result of this implementation. The fault is not so much on the code that drives Modular Extensions. But, on the fact that it's essentially a hack designed to expand a system that fundamentally rejects modular code.

Another third-party system released for CodeIgniter is Sparks (getsparks.org). I was a big proponent of Sparks at first and made a number of screencasts that encouraged its use. But, it quickly became apparent that Sparks is the worst form of code modularity currently available for popular PHP frameworks. The core concept seems reasonable enough. It's a command-line tool for installing packages that pulls from git repositories, supports server caching (removal of the original repo doesn't kill the spark), and versioning. These are all good things. However, it falls flat on its face due to the fact that it can't offer more than CodeIgniter itself does. Sparks can only provide libraries, helpers and config files. This limits its function to a central repository for CodeIgniter libraries. Unfortunately, it fails at that as well due to the fact that CI developers cannot rely on the libraries that they need being available within the Sparks system. A Google search ends up being the go-to method in the end, rendering Sparks useless. It is now apparent that modular code solutions have no place in the world of CodeIgniter. These are symptoms of a greater problem.

CodeIgniter was conceived by Rick Ellis of EllisLab. It is now community supported to some extent, but still seems to wilt under its creator's needs. CodeIgniter is the platform on which EllisLab's flagship product (ExpressionEngine) is built. In part due to the preoccupation of EllisLab with ExpressionEngine change to the CodeIgniter framework has come infrequently and the magnitude of the changes have been insignificant.

CodeIgniter Reactor was released so that the community could make changes and improve the framework. Unfortunately, due to the fact that there is no strong or dedicated leader, improvement to the framework has not occurred. One could easily argue that CodeIgniter 2.0 brought only minor usability improvements at the cost of dropping PHP4 support entirely. The CodeIgniter development team is either too busy with their other projects or just not sure what CI should become. It's no longer the framework for legacy support and it begs the question, "what was the purpose of dropping that support?" as users have seemed to have gained little in exchange.

When it comes to community participation only the most daring need apply. CodeIgniter is not well unit tested. This means that there is no way to responsibly make pull-requests as you're unable to test whether or not your changes have unexpectedly broken something. There was a time when this was the standard in PHP but as a community and as an industry we're past the point where that is acceptable. The community has been trying to catch up and to create tests for CI but in the last few years very little real progress has been made as the task of retrofitting CodeIgniter with unit tests is Herculean.

In summary: CodeIgniter has proven its inability to change and it can no longer compete with the feature-set or practices found in any other modern PHP framework. When I say that CodeIgniter has died. I don't mean that nobody is using it. I'm saying that CodeIgniter has nowhere to go and can become nothing more than it is.

Solution: Don't be content exploring only a single framework. CodeIgniter is lauded to be easy to learn. It is that. But, so are other frameworks. Do your due diligence and find what best serves you and your organization. Without experimenting we can't truly understand what we prefer. It's far easier to identify strengths and weaknesses when you have something with which to compare.

I use Laravel.

UPDATED 5/21:

There has been a lot of response to this post, some of it negative. I'm going to take some liberty to clarify my position.

I made a few key mistakes while constructing this post. The first is that the title distracts from the actual information in the post. The second mistake was to advocate Laravel in this post as some have assumed political motives, which is simply not true. These mistakes have distracted and confused the issues.

The assumption that I simply became bored with CodeIgniter isn't the case, and it ignores the issues that I discuss in the post.

I acknowledge that there is responsibility inherent when one provides and promotes educational resources. However, I disagree that responsibility should embargo unpopular ideas.

I'm not interested in intellectually or emotionally strong-arming anyone. I express my ideas because I believe that there is value in that. I believe that the otherwise warm response to this post is due to many users having similar experiences and perspectives on the subject.

I value the perspectives of others and you should feel free to contribute to the lively discussion in the comments.

]]>
Learning from Laravel's Source http://heybigname.com/2012/03/14/learning-from-laravels-source/ Wed, 14 Mar 2012 15:30:39 +0000 In this video I discuss using the Laravel source code as a valuable educational resource.

]]>
Application Logic in Laravel Using Routes http://heybigname.com/2012/03/13/application-logic-in-laravel-using-routes/ Tue, 13 Mar 2012 14:58:05 +0000 In this video I discuss the basics of embedding your application logic into Laravel's routes. We revisit the topics from the the application logic in controllers screencast and approach them a bit differently.

]]>
Application Logic in Laravel Using Controllers http://heybigname.com/2012/03/13/application-logic-in-laravel-using-controllers/ Tue, 13 Mar 2012 14:34:03 +0000 In this video I discuss where to put your application logic when using Laravel Controllers. I discuss registering controllers with the router, creating a route with a wildcard to send parameters to a controller action, and restful controllers.

]]>
Configuring Your Laravel Application on a Per-Environment Basis http://heybigname.com/2012/03/13/configuring-your-laravel-application-on-a-per-environment-basis/ Tue, 13 Mar 2012 11:01:04 +0000 An application will usually be deployed to many environments over its lifetime. From the team's own development environments to a staging environment to the production environment configurations will likely need to be changed.

Laravel provides a simply way to enable different configurations on a per-environment basis.

]]>
A Walk Through Laravel's Folder Structure http://heybigname.com/2012/03/12/a-walk-through-laravel-folder-structure/ Mon, 12 Mar 2012 20:23:20 +0000 In this video I walk through the Laravel folder structure and share some of my thoughts about Laravel.

]]>
Unit Testing Laravel's Core in Windows http://heybigname.com/2012/03/08/unit-testing-laravels-core-in-windows/ Thu, 08 Mar 2012 12:32:21 +0000 Testing Laravel's core is a critical part of making and submitting changes to the codebase. Without testing it's incredibly difficult to know if your changes break something. It's possible that your seemingly perfect modification could cause an error in something obscure that few people would ever use. It's important to test for an increased level of confidence.

A few preparations must be made when unit testing Laravel's core in Windows. In the video I walk through updating PEAR, PHPUnit, enabling the fileinfo PHP extension, and pulling down the framework / core tests.

1. Clone Laravel and the tests bundle.

Clone the Laravel framework.

git clone https://github.com/laravel/laravel.git

Clone the laravel-tests bundle into the bundles folder.

cd laravel/bundles

git clone https://github.com/laravel/tests.git laravel-tests

2. Upgrade PEAR.

Change directories to your PHP installation folder.

cd xampp177/php

Upgrade PEAR.

pear upgrade pear

Upgrade PHPUnit.

pear upgrade phpunit/PHPUnit

3. Enable the fileinfo extension in php.ini.

Laravel's File class uses the fileinfo extension. This is generally not enabled by default in Windows packages.

In your php.ini file find the following line.

;extension=php_fileinfo.dll

Uncomment the extension by removing the semi-colon.

extension=php_fileinfo.dll

Then restart your apache.

4. Run the tests against Laravel's core.

Change directories into the folder that you cloned Laravel into.

cd laravel

Then, run the tests against the core.

php artisan test:core
]]>
Mass-assignment Security Vulnerability Explanation http://heybigname.com/2012/03/08/mass-assignment-security-vulnerability-explanation/ Thu, 08 Mar 2012 12:27:12 +0000 Using Laravel and Eloquent I explain Mass-assignment and how it can create an easily exploitable security-hole in your code.

I have modified Eloquent to add mass-assignment white-list functionality and have submitted the following pull-request: https://github.com/taylorotwell/eloquent/pull/19

Edit: this functionality has been merged into Eloquent

]]>
Google Closure Compiler Bundle for Laravel Released http://heybigname.com/2012/02/28/google-closure-compiler-bundle-for-laravel-released/ Tue, 28 Feb 2012 12:11:30 +0000 We use the Google Closure Compiler to compress our JavaScript files in order to reduce page load times. When writing HeyBigName.com using Laravel 2.x it was implemented as a library. After having converted the code-base to Laravel 3.x we're repackaging much of our functionality into bundles.

Laravel's bundle system allows for developers to package libraries, models, migrations, routes, collections of MVC components, or entire sites into modular components that can be installed from a call on the command-line.

I highly encourage you to check out Laravel as 3.x is stable and production-ready. The documentation is good and the community is growing very quickly. In all honesty I see Laravel as the new baseline in which all other PHP frameworks should be judged. (not including full-stack frameworks such as Zend or Symfony)

Check out our bundle on the Bundle Page or on GitHub.

]]>
CodeIgniter Conference 2012! We're so there! http://heybigname.com/2012/02/13/codeigniter-conference-2012-were-so-there/ Mon, 13 Feb 2012 15:33:04 +0000 Excitement is building as CIConf 2012 gets closer! This weekend --the 19th and 20th of February-- I am going to be in London, England meeting a bunch of fellow CodeIgniter developers and checking out some great speakers.

If you see me there make sure you say hi! I'm so very lonely.

http://ciconf.com

]]>
Interview with Laravel Creator, Taylor Otwell http://heybigname.com/2012/02/11/interview-with-laravel-creator-taylor-otwell/ Sat, 11 Feb 2012 14:49:00 +0000 I was given the opportunity to interview Taylor Otwell about his PHP web development framework Laravel.

We love Laravel (this site was built with it) and we think that you will love it, too.

You can learn more about Laravel at http://laravel.com. There you can find the Laravel forums which are great for checking out information about new releases and asking questions. You can also join the #Laravel IRC channel on irc.freenode.net is full of smart people who can help to answer any questions that you have.

]]>
Big Name Turns One http://heybigname.com/2012/01/24/big-name-turns-one/ Tue, 24 Jan 2012 05:24:53 +0000 It's been a fun and exciting year for us. We worked with a lot of great people, released our first web app (Picofin.com) and Shawn moved to the Netherlands where he established a Dutch branch for Big.

We've learned a lot about running our own business over these past 12 months and we're looking forward to another year.

Thank you all for supporting us and helping us grow!

Birthday Cake Costume Photo Credit: mediamolecule

]]>
Big Name Designer Hangout - Episode 1 http://heybigname.com/2011/12/27/big-name-designer-hangout-episode-1/ Tue, 27 Dec 2011 00:00:00 +0000 Here is Episode 1 of our Designer Hangout where we talked about Design Processes. We’ve noted discussion topic changes in the player if you want to skip around. If you weren’t able to join us for this one, don’t worry, we’ll be hosting more of them.

]]>
Big Name Designer Hangout Announced http://heybigname.com/2011/12/09/big-name-designer-hangout-announced/ Fri, 09 Dec 2011 00:00:00 +0000 The first Big Name Designer Hangout will be Dec 16th from 2PM to 3PM Central (8PM to 9PM GMT).

We'd like to know what you want to chat about. Head on over to our Google+ post and check out some ideas and suggestions for topics.

Hope you can make it!

]]>
Big Name Developer Hangout - Episode 1 http://heybigname.com/2011/12/08/big-name-developer-hangout-episode-1/ Thu, 08 Dec 2011 00:00:00 +0000 Here is Episode 1 of our Developer Hangout where we talked about Walking the Line Between Performance and Ease of Development. We've noted discussion topic changes in the player if you want to skip around. If you weren't able to join us for this one, don't worry, we'll be hosting more of them.

We'd like to give a special thanks to the talented designer and electronic music producer +Scott Weber (Line 47) for putting together some awesome intro/outro music for us.

]]>
Big Name Hangouts http://heybigname.com/2011/11/21/big-name-hangouts/ Mon, 21 Nov 2011 00:00:00 +0000 Google+ Starting in December, we'll be hosting some Designer and Developer Hangouts.

The first Big Name Developer Hangout is on December 2nd from 9pm to 10PM GMT and open to anyone that wants to stop by. So grab your webcam (or just a headset) and join us for a mostly on-topic discussion.

The topic for our initial Developer Hangout is: Walking the Line Between Performance and Ease of Development

Some potential areas of discussion include:

  • ORM Data Models vs ActiveRecord Query Builders
  • Convention Over Configuration Design Philosophy
  • Development Workflow

Add our Google+ page to your circles to get more information about future hangouts.

We'll be announcing the Designer Hangout shortly!

]]>
Sublime Text 2 Review http://heybigname.com/2011/11/03/sublime-text-2-review/ Thu, 03 Nov 2011 00:00:00 +0000 We're consistently asked about the software that we use to develop websites. Recently, both Justin and I have made a change that we both found exciting. We're using the new IDE Sublime Text 2. We've been using it for close to a month now and we thought that it'd be nice to tell people about it.

Read more about Sublime Text 2 on their development blog.

The current version of my syntax highlighting theme, "Soylent Theme."

To install: open ST2, choose 'preferences', 'browse packages', choose 'user', and drop the file there. You can then change to the theme by going to 'preferences' and choosing it under 'color scheme -> user'. In addition I highly recommend installing "Package Control" and use it to install the "Dark Soda UI Theme" as it compliments my syntax highlighting theme very well.

]]>
CodeIgniter 2 + Sparks + PHP ActiveRecord Part 6: Form Input and Model Validation http://heybigname.com/2011/09/27/codeigniter-2-sparks-php-activerecord-part-6-form-input-and-model-validation/ Tue, 27 Sep 2011 10:27:45 +0000 This screencast is the sixth in a series utilizing CodeIgniter 2 (Reactor) and PHP ActiveRecord. I'm fundamentally focusing on PHP ActiveRecord due to the dramatic improvement it provides over raw CI models. I'm using Sparks (getsparks.org) in order to install extensions that will be used throughout this series as I think that it's a system with merit that should be utilized at every opportunity.

In this episode we go discuss creating input forms, using flashdata, validating data at the model level, accessible attributes, and a number of other concepts.

Be sure to watch in HD.

Download the source for part 6.

]]>
Are You Developing with Your Clients' Best Interests in Mind? http://heybigname.com/2011/09/16/are-you-developing-with-your-clients-best-interests-in-mind/ Fri, 16 Sep 2011 11:52:08 +0000 Software and Database engineering / architecture are difficult jobs. It's absolutely necessary to constantly learn more design patterns and to keep up with new developments so that one can implement best-practices. Frequently, web developers who are under-qualified for database architecture jobs end up in that role due to team size constraints or due to management not realizing that there is a need for experienced professionals. We end up with developers obsessing over every small performance hit while remaining somewhat oblivious to the big picture.

It's important to choose the right tools for the job. By observing basic practices such as reducing the number of queries per page, reducing the number of hits to the server per page, and intelligently caching our data we can keep performance quite high under a heavy load. Should the site become a massive success and performance starts to become an issue then that is a GREAT problem to have. We're building successful web applications and we're making some money. You can then start load balancing your web servers and using data storage patterns such as the "data warehouse" in order to kick your system's performance back up to the top.

The biggest issue that our clients come against tends to NOT be performance. Instead, it tends to be their ROI (return on investment). The less money that our clients spend developing (or paying us to develop) and paying for maintenance (adding features and generally just making changes to keep up with their business) the more income becomes profit. I submit to you that our primary goal should be to reduce the lifetime cost of the products that we're either building in house for a company or are turning over to clients.

We can reduce the lifetime cost of our products by:

  1. Using industry standards across all aspects of our development (from database architecture to variable naming conventions).
  2. Keeping our code small and easy to read (code should read like a sentence, variable names should be easy to understand).
  3. Using technologies that are established and have strong community support.
  4. Properly refactoring code when the need presents itself.

Your Choices Directly Influence Your Clients' Costs

It's important to remember that code you write is going to eventually enter into the hands of another developer. You may hand a product off to a client who then hires an internal development team. The experience level of that development team is an unknown. It's quite possible that they hired inexperienced developers in order to reduce their costs. The more difficult it is for these developers to understand and maintain your code the more likely the modifications that they make will be of the "hacked up" persuasion. This can violate the integrity of the project's conventions, reduce performance, and reduce readability and maintainability. This turns your product into a long-term challenge for the company involved. It's easy to blame your client for not having hired experienced development, but our profession is one that is easy for amateurs to enter into and is difficult for many business people to understand. Sometimes the budget for an experience developer simply does not exist. It is not our job to predict or judge the failings of our clients but to improve their experience with the product that you created for them.

By developing your code by standards and intentionally making sure that your code is self-documenting (easy enough to read that you don't need to generate as much documentation) you're reducing the lifetime cost of the software for your client. By using established technologies you're giving yourself and others access to free community support.

This is the philosophy that leads Big Name's web development decisions. Do you agree with us or does your organization subscribe to a different philosophy?

]]>
CodeIgniter 2 + Sparks + PHP ActiveRecord Part 5: ORM Associations and N+1 http://heybigname.com/2011/09/15/codeigniter-2-sparks-php-activerecord-part-5-orm-associations-and-n1/ Thu, 15 Sep 2011 14:35:04 +0000 In this episode we'll start creating associations between models by creating a belongs_to / has_many relationship between users and blog posts and we'll talk about accessing the related data in multiple ways. We'll also discuss the N+1 query problem and how to resolve it using PHP-ActiveRecord.

Be sure to watch in HD.

Download the source for part 5.

]]>
The N+1 Problem and ORM Data Modeling Performance. http://heybigname.com/2011/09/14/the-n1-problem-and-orm-data-modeling-performance/ Wed, 14 Sep 2011 04:38:53 +0000 A Brief Explanation of N+1

N+1 is an expression that represents a popular pitfall in data modeling for web applications. I'm going to briefly explain N+1 using an example involving the following database tables:

mysql> describe songs;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int(11)      | NO   | PRI | NULL    | auto_increment |
| album_id | int(11)      | NO   | MUL | NULL    |                |
| name     | varchar(128) | NO   |     | NULL    |                |
| filename | varchar(128) | NO   |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+

mysql> describe albums;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | PRI | NULL    | auto_increment |
| name  | varchar(128) | NO   |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+

In this example you need to loop through the albums, creating a container, then loop through the songs providing links to each of them.

How do you approach this from a data modeling perspective?

You could query to pull back all of the albums, then, loop through them. For each album you could query to pull back the songs for it. Consequently, you'd have the initial album query (+1) and then add another query to the pile for each album in the database (N). This means that the number of queries that you need scales with the amount of content in the database. To pull back songs from 10 albums you'd do 11 queries. To pull back songs from 100 albums you'd do 101 queries. This is not good.

select id, name from albums
select id, name, filename from songs where album_id = 1
select id, name, filename from songs where album_id = 2
select id, name, filename from songs where album_id = 3
select id, name, filename from songs where album_id = 4
select id, name, filename from songs where album_id = 5

An alternative would be to select all of the albums, then aggregate the returned album ID's. Then, you can query for all of the songs like so:

select id, title, filename from songs where album_id in (1, 2, 3, 4, 5)

With 2 queries we have pulled back all of the data that could have taken us anywhere between 2 queries and (total database album count + 1) queries.

The problem here being that you must now arrange the data in a format useful for you development. You might do something like this:

$album_songs = array();

foreach($songs as $song)
{
    // create array container
    if(!isset($album_songs[$song->album_id]))
        $album_songs[$song->album_id] = array();

    // push to array
    $album_songs[$song->album_id][] = $song;
}

This will allow you to do something that more or less does this in your view:

foreach($albums as $album)
{
    echo "$album->name";

    // loop songs if they exist
    if(isset($album_songs[$album->id])
        foreach($album_songs[$album->id] as $song)
        {
            echo anchor('download/' . $song->filename, $song->name);
        }
}

There's a bit of extra processing as you're combining everything into an array that is indexed by album id.

Compare and contrast this with using an ORM ActiveRecord model.

You'd have a model called Albums and a model called Songs. You could do something like this:

$albums = Album::find('all');

foreach($albums as $album)
{
    echo "$album->name";

    // loop songs if they exist
    if($album->songs)
        foreach($album->songs as $song)
        {
            echo anchor('download/' . $song->filename, $song->name);
        }
}

We pull back a list of all albums as one query. However, then we take the amount of records returned and instantiate that many album model objects. In this case $album is an array of Album model objects. Each of those objects contains the member variables and methods defined in the model as well as those in the model's parent class (ActiveRecord\Model).

As you look through them you call if($album->songs). If there are no songs tied to an album then using the foreach() loop without this if() statement will result in an error. The error is that foreach expects an ARRAY and we're sending a boolean (false). So, we simply check to see if it's set at ALL, and if it is we know it's populated as an array of Song objects, so we can pass it into the foreach() loop.

Well, at this point the ActiveRecord model has not yet run any queries relating to songs. This is due to a pattern called 'lazy loading'. There is no reason to populate every relationship in an ORM model by default (and indeed, you'd sometimes create infinite loops by doing so). Only when you make a call against $album->songs does the model then query against songs.

It goes something like this:

  1. Query for all albums
  2. Start to loop through all albums
  3. Query for all songs belonging to an album
  4. Start to loop through all songs

As you can see, we're dealing with N+1 here again. However, It's actually much easier to resolve with PHP-ActiveRecord.

$albums = Album::find('all', array('include' => 'songs'));

foreach($albums as $album)
{
    echo "$album->name";

    // loop songs if they exist
    if($album->songs)
        foreach($album->songs as $song)
        {
            echo anchor('download/' . $song->filename, $song->name);
        }
}

By passing the additional parameter to include the songs models we're telling the ORM that we want "eager loading" for the albums to songs association. This means that instead of waiting until we make a call against $album->songs to pull back the data, we'll just go ahead and do it right now. Since the model has far more information about how you're going to want to use the data it can take steps to make the entire process more efficient. In this case, it'll query for albums, then query for all songs that have the returned album_ids. 2 queries, much like our solution above. We are avoiding N+1 and we can easily and cleanly loop through the results.

An Argument Against ORM

Here is where opponents of ORM argue that you're introducing unnecessary overhead into your application. It's true that we're adding additional memory requirements and some amount of additional processing requirements. Each returned record will require an instantiated model object, after all. The data still loops in the background to assign the values (as we did manually earlier in the article), so that's pretty much the same. So, in the end we're dealing with the overhead of the ORM model's infrastructure (sanity checks, etc) and then we're dealing with the instantiation of returned result objects. It is true that the ORM data model pattern has these extra costs.

In my opinion ORM data models should be used by MOST projects on the web as it reduces the complexity of development, makes avoiding unpleasant challenges (N+1) easier, and improves readability and maintainability.

What is your opinion on this topic?

]]>
CodeIgniter 2 + Sparks + PHP ActiveRecord Part 4: Views and Layouts http://heybigname.com/2011/08/26/codeigniter-2-sparks-php-activerecord-part-4-views-and-layouts/ Fri, 26 Aug 2011 11:00:32 +0000 In this episode we'll take a few minutes to improve the infrastructure of the project. We'll add functionality that will allow our controller to automatically determine which content view should be loaded. We'll also add the ability to have multiple application layouts (aka templates) and to be able to easily switch between them.

Be sure to watch in HD.

Download the source for part 4.

]]>
Big Name Releases Design Sharing App Picofin http://heybigname.com/2011/08/22/big-name-releases-design-sharing-app-picofin/ Mon, 22 Aug 2011 12:53:47 +0000 Sign up now for a *FREE* lifetime subscription.

We're excited to announce the release of Picofin. Picofin is a fast, simple tool for online proofing and sharing. We needed a little more and a little less from a design sharing app. We made our own and invite you to use it as well.

]]>
CodeIgniter 2 + Sparks + PHP ActiveRecord Part 3: Login http://heybigname.com/2011/08/17/codeigniter-2-sparks-php-activerecord-part-3-login/ Wed, 17 Aug 2011 12:53:57 +0000 In this episode we'll use the user model that we created to enable our users to login to our site. We'll refactor the user model a bit, extend the CI_Controller class, and create the forms necessary to have a completely working login system.

Be sure to watch in HD.

Download the source for part 3.

]]>
CodeIgniter 2 + Sparks + PHP ActiveRecord Part 2: The User Model http://heybigname.com/2011/08/03/codeigniter-2-sparks-php-activerecord-part-2-the-user-model/ Wed, 03 Aug 2011 08:52:04 +0000 In this episode we create a user model and focus on securely storing passwords in a database table by using sha256 encryption. We go over the reasons why using MD5 is no longer acceptable and we create a password validation method.

Be sure to watch in HD.

Download the source for part 2.

]]>
Quickly Add SwiftMailer to Your CodeIgniter 2 Application http://heybigname.com/2011/07/29/quickly-add-swiftmailer-to-your-codeigniter-2-application/ Fri, 29 Jul 2011 09:43:50 +0000 SwiftMailer is a powerful library for sending mail written in PHP5. SwiftMailer supports SMTP, Sendmail, Postfix, or your custom transport implementations. There are many advantages to using SwiftMailer in your application as opposed to simply using PHP's mail() function.

Sparks are small packages that can be quickly installed into your CodeIgniter 2 application.

We have created a swift-mailer spark that enables developers to install swift-mailer with a single command.

php tools/spark install swift-mailer

If you don't have Spark installed into your project you can find instructions here.

You can find more information about our swift-mailer Spark on the official Spark page or on the Github page.

]]>
CodeIgniter 2 + Sparks + PHP ActiveRecord Part 1: Installation http://heybigname.com/2011/07/28/codeigniter-2-sparks-php-activerecord-part-1-installation/ Thu, 28 Jul 2011 06:30:50 +0000 This screencast covers the installation of CodeIgniter 2 and the PHP ActiveRecord model library.  We install and use CodeIgniter Sparks to simplify the installation of PHP ActiveRecord and any compatible functionality that we wish to add in the future.

Be sure to watch in HD.

Download the source for part 1.

]]>
HTML5 Boilerplate Adds Normalize.css http://heybigname.com/2011/06/23/html5-boilerplate-adds-normalize-css/ Thu, 23 Jun 2011 22:48:19 +0000 We're big fans of HTML5 Boilerplate. It's a great starter and the project is constantly being refined. The latest version now incorporates Normalize.css in the main style sheet. This refreshed file no longer includes the classic CSS reset or a myriad of default styles. What's left is a very lean and sexy style sheet.

html5 boilerplate

What is Normalize.css? From the authors at the Normalize.css project:

Normalize.css is a customisable CSS file that makes browsers render all elements more consistently and in line with modern standards. We researched the differences between default browser styles in order to precisely target only the styles that need normalizing.

The new HTML5 Boilerplate style.css file is now much lighter and is documented very well. Currently, this updated version is only available via the GitHub repository and the developers are looking for feedback on the latest commit at their Google Group.

We're excited to try out the updated boilerplate. Anyone worked with the new files yet?

]]>
Shawn In Dutch http://heybigname.com/2011/05/30/shawn-in-dutch/ Mon, 30 May 2011 11:02:40 +0000 We have some big news. Shawn and his family are moving to the Netherlands! More specifically, Utrecht. They traveled all weekend long and have made it to their destination safely. Their next step, among a lot of others, is to find a place to live. So, if you have any friends across the pond that can recommend real estate in Utrecht, they'd be much obliged. You can keep up with Shawn and his experiences at Shawn in Dutch.

alt text

Just so we're clear, Shawn isn't leaving the company. In fact, he'll be opening the Dutch branch of Big Name! We're very excited about this opportunity and we're looking forward to the challenges ahead.

Photo by Marcel030NL

]]>
Deconstructing Design http://heybigname.com/2011/03/31/deconstructing-design/ Thu, 31 Mar 2011 21:50:26 +0000 Deconstructing a design is a fantastic way to discover new ways of overcoming design challenges. When I encounter a unique approach to web design, the first thing I do is open up Firebug and break down what went into creating the effect.

Sometimes I find it was a clever combination of CSS and JavaScript and other times it's a graphic that has done a lot of the work. When it's the latter, I can only make assumptions as to how it was accomplished. I hate that feeling.

That's why I was interested to see Campaign Monitor's release of their Designer Email Templates a while back. Not only did they offer downloads of the HTML template, but they also included the original layered Photoshop docs. These documents give you a view of the techniques that were used to create those little touches that make a design really work.

Download and learn.

]]>
Setting Type on the Web - Tips http://heybigname.com/2011/02/08/setting-type-on-the-web-tips/ Tue, 08 Feb 2011 20:52:51 +0000 Copy on the web needs to be legible, accessible and consistent. No one wants to have to labor over copy. Our goal as designers is to get users through the content as quickly and efficiently as possible.

At Big Name, I'm always looking for ways to improve the typography for our sites. Here are some of the things I do to keep the content easy on the eyes.

Set font-size on the body to 100%

Setting the body font-size to a percentage ensures that your type will scale properly even if the user has altered the browser's default text size. This can't be accomplished with pixels or points as they are fixed-sized units.

I set the body font-size to 100% or greater. Some say this is too large, but I believe it creates highly readable text – especially when paired with a proper line-height.

When set to 100%, the browser will use its default setting for displaying text, normally 16-pixels. This is the equivalent to the standard print size of 12-points. 16px = 1em = 100% = 12pt

The alternative to setting a percentage is using EMs. Yes, the scalability is there, but IE 6/7 will disproportionately interpret the EM. This causes the size to be way larger or smaller when using the "Largest" or "Smallest" text-size settings, for example.

IE Font Size Comparison

Why not just rely on the browser's "zoom" feature? Zoom increases the size of everything on the page, not just the text. This can make other elements on the page look nasty. Not to mention, high resolution devices like the iPhone and some Android phones now sport super-high resolutions that make 12-pixel fonts tough to read.

Use EMs for setting type throughout the rest of the site

Yes, I know we just set the entire document to a percentage. You can obviously continue using percentages, but I prefer the EM because it's a true typographic unit and because it's the W3C recommended measure.

Regardless of your choice, remember that relative values like percentages and EMs are inherited and will cascade in a document. For example, setting an ordered list size to 1.5em and a list item to 1.5em will cause the text to be displayed at 1.5 x 1.5.

Be consistent with your font sizes by composing on a scale and utilizing an EM calculator. If you're coming from the pixel world, try starting with http://pxtoem.com/". This will help you come up with a set of default styles based on a default body font size.

Pixels     EMs         Percent Points
----------------------------------
6px     0.333em     33.3%     5pt
7px     0.389em     38.9%     5pt
8px     0.444em     44.4%     6pt
9px     0.5em         50%     7pt
10px     0.556em     55.6%     8pt
11px     0.611em     61.1%     8pt
12px     0.667em     66.7%     9pt
13px     0.722em     72.2%     10pt
14px     0.778em     77.8%     11pt
15px     0.833em     83.3%     11pt
16px     0.889em     88.9%     12pt
17px     0.944em     94.4%     13pt
--------------------------------
18px     1em         100%     14pt
--------------------------------
19px     1.056em     105.6%     14pt
20px     1.111em     111.1%     15pt
21px     1.167em     116.7%     16pt
22px     1.222em     122.2%     17pt
23px     1.278em     127.8%     17pt
24px     1.333em     133.3%     18pt

Note: As mentioned above, IE will mishandle the EM if a user sets their text-size "larger" or "smaller". However, once the body font-size is set as a percentage, IE won't continue adding the values of an EM cascade.

Keep measure in mind

Measure refers to the width of a body of type – or more precisely, the number of characters in a single line of a column of text. According to The Elements of Typographic Style:

Anything from 45 to 75 characters is widely regarded as a satisfactory length of line for a single-column page set in a serifed text face in a text size. The 66-character line (counting both letters and spaces) is widely regarded as ideal. For multiple column work, a better average is 40 to 50 characters.

We're able to read with ease when our eyes encounter line measures in this range. But trying to keep an ideal character-per-line count of 66 characters can be challenging on the web.

Liquid and elastic layouts can help address issues of text and browser resizing, but your design needs are going to influence your overall approach.

Here, I've used a pixel width for my columns (at the time of this writing) in order to retain control over the line length. It will throw off the measure when text is resized, but this layout presents an ideal line width to the vast majority of my audience.

Additional resources for setting type on the web

]]>
Hey Big Name! http://heybigname.com/2011/01/20/hey-big-name/ Thu, 20 Jan 2011 17:35:03 +0000 Hey everyone!  The talented designer Justin Seiter and I have joined forces to create the web design company Big Name.  In addition to our regular web design work we're excited to announce that we'll be creating articles and screencasts on numerous design and development topics.

You can learn more about us on the about page and always feel free to drop us a line.

As we get up to speed you can follow us here and on our twitter @heybigname.

]]>
Developing a Website with CodeIgniter Part 4: Admin Site CRUD http://heybigname.com/2010/01/30/developing-a-website-with-codeigniter-part-4-admin-site-crud/ Sat, 30 Jan 2010 01:25:43 +0000 This screencast continues a series with the goal of documenting the development of a functionally complete site using PHP with the CodeIgniter framework and jQuery for JavaScript UI Improvements including AJAX interactions.

This video covers the development of an admin user management system (CRUD) and includes updates to the authentication system including a method that is used allow only admins into specific sections of the site.

Download the Source Here

]]>
Managing Assets with CodeIgniter http://heybigname.com/2009/11/23/managing-assets-with-codeigniter/ Mon, 23 Nov 2009 17:16:32 +0000 This article discusses the reason behind the base_url() method and the creation of a helper file that will assist in managing images, css files, and more.

PHP code is far from the only content necessary for most web applications. Most frequently we need to include images, css files, flash files, and many other types of files. The CodeIgniter framework doesn't contain a built-in methodology for asset management, leaving the developer to their own devices when it comes to deciding where to put this content. Every developer is going to have their own personal preference, and for the most part they're equally valid.

The base_url() method

Imagine a scenario where you have developed a site that contains user profiles. Each user profile can have an image. The code in your view that would display the image may look something like this:


This works fine until your cool new site is bought up and now your application rests at http://www.bigcompany.com/mycoolsite. Now, you have to go through all of your code and search/replace "/images with "/mycoolsite/images while hoping that you've found everything and that something small won't be missed until 500 users have seen it.

Instead, we use the base_url() method for creating absolute links. base_url() simply outputs the value of the $config['base_url'] variable that is set in your application/config/config.php file. Your new code would look like this:

~~~

]]>
Developing a Website with CodeIgniter Part 3: The Login Process http://heybigname.com/2009/11/09/developing-a-website-with-code-igniter-part-3-the-login-process/ Mon, 09 Nov 2009 23:48:51 +0000 This screencast continues a series with the goal of documenting the development of a functionally complete site using PHP with the Code Igniter framework and jQuery for Javascript UI improvements including AJAX interactions.

In this video we utilize the user model that we've created to create a login process for our website. We'll use the code igniter form helper, database library, and session library.

I tried something different and recorded the video in HD.  The encoding left the dark background text a bit hard to read, so if I continue to upload HD videos I'll switch to using a white background.  Please let me know if you prefer the old resolution or the HD resolution.

Download the Source Here

]]>
Why Should I Use CodeIgniter? http://heybigname.com/2009/10/28/why-should-i-use-code-igniter/ Wed, 28 Oct 2009 12:33:18 +0000 CodeIgniter is a PHP development framework. You can think of it as a PHP web site without content. Instead it provides a structure and many methods that will be frequently used for most web sites.

So, why should I use CodeIgniter instead of just writing my own site from scratch in PHP?

1. Standardization and Popularity - Using a popular development framework reduces the development time and consequently cost of initial development and maintenance.

Hiring good developers is hard and adding developers mid-project is even harder. Dozens, maybe even hundreds, of hours are spent acclimating new developers to the code base. By hiring developers who are already familiar with CodeIgniter you're able to integrate them into the project much more quickly. CodeIgniter is very compartmentalized and finding / modifying various bits of code should be very easy for anyone familiar with the framework. Initial project development time can be reduced by partially bypassing the need for planning of a custom framework.

CodeIgniter is a framework that is widely used and it's easy to find developers who are familiar with it. There are many well made libraries and helpers created by users that will allow developers to integrate functionality into their sites without having to write it all from scratch. The CodeIgniter forums provide a centralized location for developers to get support from other developers.

2. Loose Coupling and Code Re-usability - The longer you develop your code base the quicker projects can be completed.

By keeping your database interactions in libraries and models, your html and display logic in views, and additional methods in helpers and plugins your resulting code becomes modular and is easily reusable on additional projects. Why rewrite your user authentication system from project to project when you can simply copy your database structure and user model and be done with it?

CodeIgniter is written with object oriented PHP. Object oriented code is significantly less expensive to develop, debug, and maintain. Programmers can no longer get away with using global variables to pass data around the application and the project quality benefits significantly.

3. Built in Functionality - You know those hundred things that you rewrite every time you make a site? Yea, they're already done.

CodeIgniter comes out of the metaphorical box with libraries and helpers that reduce the amount of code a developer will have to write. Some examples of the functionality that comes bundled in are: benchmarking, html calendar generation, shopping cart management, email sending, file uploading, form validation, ftp transfers, html generation, form generation, internationalization, pagination, session management, trackback management, string / typography manipulation, and more than I can list here.

]]>
Using CodeIgniter's Active Record Class to Create Subqueries http://heybigname.com/2009/09/18/using-code-igniters-active-record-class-to-create-subqueries/ Fri, 18 Sep 2009 10:50:34 +0000 A good friend of mine recently asked me how he would create a subquery using Code Igniter's Active Record class.  This does present a challenge as Code Igniter's Active Record class does not natively support subqueries.

However, if you look into the code for the Database class you'll see that CI uses some handy utility methods to compile the SQL for processing.  These methods exist in all Code Igniter drivers (providing the cross platform abstraction that makes Active Record so valuable in the first place).

This algorithm is definitely far from perfect, but it DOES provide some level of abstraction that manually typing your subquery would not.  If you have any questions, concerns, or suggestions feel free to leave them as comments.

// Generate the subquery
$this->db->select('count(*)');
$this->db->from('users');

// Render the subquery to a string
$subQuery = $this->db->_compile_select();

// Reset active record
$this->db->_reset_select();

// Generate the primary query and include the subquery
$this->db->select('users.id as userId, users.fullname as userName');
$this->db->select("($subQuery) as userCount");
$this->db->where('users.status', 'active');

To break this down into smaller parts:

// Generate the subquery
$this->db->select('count(*)');
$this->db->from('users');

This code generates the query: select count(*) from users

// Render the subquery to a string
$subQuery = $this->db->_compile_select();

This code uses Code Igniter's Active Record class to generate an abstracted select statement. Whether we're using Oracle, MySQL, or PostgreSQL the statement will be rendered appropriately by Active Record.

// Reset active record
$this->db->_reset_select();

This method is usually called automatically by the Active Record class after a select statement is completed. This will clear the Active Record cache so that our "select"(count(*)) and "from"(users) commands will not appear in the NEXT active record statement that we create.

// Generate the primary query and include the subquery
$this->db->select('users.id as userId, users.fullname as userName');
$this->db->select("($subQuery) as userCount");
$this->db->where('users.status', 'active');

This code generates a select statement calling back the userID and the userName as well as aliasing the subquery variable string as 'userCount'. Using the MySQL driver the SQL that is output is as follows:

SELECT `users`.`id` as userId, `users`.`fullname` as userName, (SELECT count(*) FROM (`users`)) as userCount FROM (`users`) WHERE `users`.`status` = 'active'

Keep in mind that the developers of Code Igniter did not intend for you to use the _compile_select method. Therefore, it's possible that they may change the functionality in future versions and not bother letting anyone know.

]]>
Developing a Website with CodeIgniter Part 2: Users Database Table and the User Model http://heybigname.com/2009/09/06/developing-a-website-with-code-igniter-part-2-users-database-table-and-the-user-model/ Sun, 06 Sep 2009 18:46:01 +0000 This screencast continues a series with the goal of documenting the development of a functionally complete site using PHP with the CodeIgniter framework and jQuery for Javascript UI improvements including AJAX interactions.

This video covers the creation of a database table for storing users and the CodeIgniter model class for interacting with it.

Errata:

I've noticed a few errors in the screencast. When errors creep up (and they will) I'll audit them as they're discovered and keep this post up to date.  Errors will also be updated during the following screencast.

  1. The UpdateUser method "set password" line (line 80) contains the variable $options['userEmail'] instead of $options['userPassword'].
  2. The UpdateUser method is missing the line $this->db->where('userId', $options['userId']); This should be added before the line that contains $query = $this->db->update('users'); (line 84)
  3. The AddUser method's default value is set incorrectly (line 48). It currently shows array('userStatus', 'active') where it should read array('userStatus' => 'active').
]]>
Developing a Website with CodeIgniter Part 1: Development Environment and Framework Configuration http://heybigname.com/2009/09/04/developing-a-website-with-code-igniter-part-1-configuration/ Fri, 04 Sep 2009 21:29:28 +0000 This screencast begins a series with the goal of documenting the development of a functionally complete site using PHP with the Code Igniter framework and jQuery for Javascript UI improvements including AJAX interactions.

This video briefly covers the establishment of a local development environment and the configuration of CodeIgniter.

]]>
Understand the Structure of CodeIgniter http://heybigname.com/2009/08/29/understand-the-structure-of-code-igniter/ Sat, 29 Aug 2009 19:41:19 +0000 In this screencast I attempt to explain the structure and terminology of the Code Igniter MVC PHP development framework.

]]>
How to Write a Better Model in CodeIgniter http://heybigname.com/2009/08/28/how-to-write-a-better-model-in-code-igniter/ Fri, 28 Aug 2009 14:29:30 +0000 Developing using an MVC framework can go a long way towards increasing the reusability and robustness of your code. In this article I focus on writing model methods for the Code Igniter PHP MVC framework. The concepts themselves are not specific to Code Igniter, but some of the code will be.

CRUD methods

CRUD is an acronym that stands for Create, Retrieve, Update, and Delete. These are the most basic types of interactions that your code will have with a data source.

A few examples: Create - adding a user account to your website Retrieve - getting a list of available products Update - changing a user's password or the name of a product Delete - removing a user account or product

When writing models you'll generally start by creating CRUD methods for each of your logical types of data. If you're writing user authentication (login, logout, forgotten password, account activation) you'll want a method to add, update, and delete users along with the ability to pull back the user account information for a single user or for a group of users.

For example:

function AddUser()
function UpdateUser()
function DeleteUser()
function GetUsers()

Most of the interactions that we have with user accounts can be handled by these four methods. Instead of creating a model method "GetActiveUsers" we can just create a parameter for GetUsers that determines the user status of the returned set, more on this below.

The Options Array

Typically parameters for methods are sent in the following manner:

function AddUser($insertData)
function UpdateUser($userId, $updateData)
function DeleteUser($userId)
function GetUsers($limit, $offset)

Naturally, (especially for GetUsers) we'll find more and more parameters to add to our methods. This not only gets very difficult to read, but can create issues where we have to go back and alter the code that we've already written if we have to tack a new parameter onto the method.

For Example:

function GetUsers($limit, $offset, $status)

We would also need a singular GetUser($userId) method in addition to the GetUsers method. This is a problem because we're creating multiple versions of the same method. If we change the way we want information to be returned then we'd need to change code in two places, the GetUser AND GetUsers methods.

To overcome these issues I propose the usage of an options array, as such:

function AddUser($options = array())
function UpdateUser($options = array())
function DeleteUser($options = array())
function GetUsers($options = array())

If, in the past, we'd use GetUsers(5, 5, 'active') to return a list of users, we would now use GetUsers(array('limit' => 5, 'offset' => 5, 'status' => 'active');

Parameters passed using the options array can be sent in any order and can even be completely omitted. As you need to add functional parameters you simply change the model method and will not have to update code anywhere else.

Utility Methods

In order to create properly robust methods we're going to need to implement a few common bits of functionality. Namely, the ability to assign required fields and field defaults. For example, a required field when adding a user might be userEmail. For this we create the 'required' method.

/**
* _required method returns false if the $data array does not contain all of the keys assigned by the $required array.
*
* @param array $required
* @param array $data
* @return bool
*/
function _required($required, $data)
{
    foreach($required as $field) if(!isset($data[$field])) return false;
    return true;
}

In the 'AddUser' example our code might look like this:

/**
* AddUser method creates a record in the users table.
*
* Option: Values
* --------------
* userEmail            (required)
* userPassword
* userName
* userStatus        active(default), inactive, deleted
*
* @param array $options
*/
function AddUser($options = array())
{
    // required values
    if(!$this->_required(array('userEmail'), $options)) return false;

    // At this point we know that the key 'userEmail' exists in the $options array.
}

Now our AddUser method will bail out and return false if the 'userEmail' key was not sent in the options array. Robust!

Notice that in the PHPdoc block we mention that the default status for newly created users is 'active'. Naturally, if we wanted to create an inactive user we would be able to pass the 'userStatus' parameter with the value inactive. However, we are lazy and prefer to not have to explicitly declare 'active'.

Introducing the 'default' method:

/**
* _default method combines the options array with a set of defaults giving the values in the options array priority.
*
* @param array $defaults
* @param array $options
* @return array
*/
function _default($defaults, $options)
{
    return array_merge($defaults, $options);
}

That's it, this method consists of a single command. I decided to create a method out of this because I may want to add extra functionality to the defaults method, and don't want to have to change every single one of my model methods.

Let's go ahead and implement the 'default' method:

/**
* AddUser method creates a record in the users table.
*
* Option: Values
* --------------
* userEmail            (required)
* userPassword
* userName
* userStatus        active(default), inactive, deleted
*
* @param array $options
*/
function AddUser($options = array())
{
    // required values
    if(!$this->_required(array('userEmail'), $options)) return false;

    // default values
    $options = $this->_default(array('userStatus' => 'active'), $options);
}

// At this point we know that the 'userEmail' key exists in the $options array and if no 'userStatus' key existed before, it does now and with the value 'active'.

These methods go a long way towards making your code more robust while only adding a few lines to each method.

Active Record

Many database constructs (MySQL, Oracle, Microsoft SQL, PostgreSQL, etc) use variations of SQL syntax, but they all work a little bit differently. An active record class allows us to create a database query using abstraction. In other words we are able to create queries that will work on any database construct that our class supports. They also give the added benefit of allowing us to send bits of the query to the class one by one before executing the query.

A Code Igniter active record query might look something like this:

$this->db->where('userStatus', 'active');
$this->db->get('users');

Those two commands will create and execute the query, "select * from users where userStatus = 'active'"

Putting It All Together

Using the concepts that we've explored let's look at a simple example set CRUD methods.

/**
* AddUser method creates a record in the users table.
*
* Option: Values
* --------------
* userEmail            (required)
* userPassword
* userName
* userStatus        active(default), inactive, deleted
*
* @param array $options
*/
function AddUser($options = array())
{
    // required values
    if(!$this->_required(array('userEmail'), $options)) return false;

    // default values
    $options = $this->_default(array('userStatus' => 'active'), $options);

    // qualification (make sure that we're not allowing the site to insert data that it shouldn't)
    $qualificationArray = array('userEmail', 'userName', 'userStatus');
    foreach($qualificationArray as $qualifier)
    {
        if(isset($options[$qualifier])) $this->db->set($qualifier, $options[$qualifier]);
    }

    // MD5 the password if it is set
    if(isset($options['userPassword'])) $this->db->set('userPassword', md5($options['userPassword']));

    // Execute the query
    $this->db->insert('users');

    // Return the ID of the inserted row, or false if the row could not be inserted
    return $this->db->insert_id();
}

/**
* UpdateUser method alters a record in the users table.
*
* Option: Values
* --------------
* userId            the ID of the user record that will be updated
* userEmail
* userPassword
* userName
* userStatus        active(default), inactive, deleted
*
* @param array $options
* @return int affected_rows()
*/
function UpdateUser($options = array())
{
    // required values
    if(!$this->_required(array('userId'), $options)) return false;

    // qualification (make sure that we're not allowing the site to update data that it shouldn't)
    $qualificationArray = array('userEmail', 'userName', 'userStatus');
    foreach($qualificationArray as $qualifier)
    {
        if(isset($options[$qualifier])) $this->db->set($qualifier, $options[$qualifier]);
    }

    $this->db->where('userId', $options['userId']);

    // MD5 the password if it is set
    if(isset($options['userPassword'])) $this->db->set('userPassword', md5($options['userPassword']));

    // Execute the query
    $this->db->update('users');

    // Return the number of rows updated, or false if the row could not be inserted
    return $this->db->affected_rows();
}

/**
* GetUsers method returns an array of qualified user record objects
*
* Option: Values
* --------------
* userId
* userEmail
* userStatus
* limit                limits the number of returned records
* offset                how many records to bypass before returning a record (limit required)
* sortBy                determines which column the sort takes place
* sortDirection        (asc, desc) sort ascending or descending (sortBy required)
*
* Returns (array of objects)
* --------------------------
* userId
* userEmail
* userName
* userStatus
*
* @param array $options
* @return array result()
*/
function GetUsers($options = array())
{
    // default values
    $options = $this->_default(array('sortDirection' => 'asc'), $options);

    // Add where clauses to query
    $qualificationArray = array('userId', 'userEmail', 'userStatus');
    foreach($qualificationArray as $qualifier)
    {
        if(isset($options[$qualifier])) $this->db->where($qualifier, $options[$qualifier]);
    }

    // If limit / offset are declared (usually for pagination) then we need to take them into account
    if(isset($options['limit']) && isset($options['offset'])) $this->db->limit($options['limit'], $options['offset']);
    else if(isset($options['limit'])) $this->db->limit($options['limit']);

    // sort
    if(isset($options['sortBy'])) $this->db->order_by($options['sortBy'], $options['sortDirection']);

    $query = $this->db->get('users');
    if($query->num_rows() == 0) return false;

    if(isset($options['userId']) && isset($options['userEmail']))
    {
        // If we know that we're returning a singular record, then let's just return the object
        return $query->row(0);
    }
    else
    {
        // If we could be returning any number of records then we'll need to do so as an array of objects
        return $query->result();
    }
}

/**
* DeleteUser method removes a record from the users table
*
* @param array $options
*/
function DeleteUser($options = array())
{
    // required values
    if(!$this->_required(array('userId'), $options)) return false;

    $this->db->where('userId', $options['userId']);
    $this->db->delete('users');
}

Here are some examples of how we can use these methods to interact with your database.

Adding a User

$userId = $this->user_model->AddUser($_POST);

if($userId)
    echo "The user you have created has been added successfully with ID #" . $userId;
else
    echo "There was an error adding your user.";

Updating a User

if($this->user_model->UpdateUser(array('userId' => 3, 'userName' => 'Shawn', 'userEmail' => 'not telling')))
    // The user has been successfully updated
else
    // The user was not updated

User Authentication (Retrieving a Single User)

$user = $this->user_model->GetUsers(array('userEmail' => $userEmail, 'userPassword' => md5($userPassword), 'userStatus' => 'active'));
if($user)
    // Log the user in
else
    // Sorry, your user / password combination isn't correct.

Retrieving a Set of Users

$users = $this->user_model->GetUsers(array('userStatus' => 'active'));

if($users)
{
    echo "Active Users";
    foreach($users as $user)
    {
        echo $user->userName . "";
    }
}
else
{
    echo "There are no active users.";
}

Deleting a User

$this->user_model->DeleteUser(array('userId' => $userId));

I hope that this will continue a dialog on how to better write such commonly reused bits of functionality. If you have any suggestions or comments please let me know. I'd love to hear about the algorithms that you've been designing to handle similar problems.

William Rufino has translated this article to Portuguese. This translation can be found here: http://www.williamrufino.com.br/blog/como-escrever-um-model-melhor-no-codeigniter

]]>
AJAX with jQuery: A Simple Login Example http://heybigname.com/2009/04/15/ajax-with-jquery-a-simple-login-example/ Wed, 15 Apr 2009 17:04:23 +0000 In this screencast we explore the jQuery $.post() command in order to create a simple AJAX login script that also gracefully degrades and works for users who do not have JavaScript enabled.

You may want to check out my post "What Exactly is JSON?" if you're not familiar with the JavaScript Object Notation before watching.

]]>
What exactly is JSON? http://heybigname.com/2009/04/15/what-exactly-is-json/ Wed, 15 Apr 2009 16:04:19 +0000 JSON is short for JavaScript Object Notation.  It's a notation used to create JavaScript objects.

JSON looks like this:

    {
    name: "Shawn McCool",
    language: "English"
    }

When evaluated by JavaScript or decoded with another language you'd end up with an object like the one below.

person.name is equal to "Shawn McCool" person.language is equal to "English".

Since using JSON allows you to easily serialize arrays and objects, it's often used during AJAX calls and web services. Below are some examples of the JavaScript Object Notation.

    var myArray = ['cat', 'dog'];
    var myObject = {animal: 'cow'};
    alert(myArray[0]);  // outputs 'cat'
    alert(myObject.animal); // outputs 'cow';

A standard set of interactions for an AJAX login script might be:

  1. JavaScript client (browser) posts username and password to PHP.

    $.post('/ajax.php', {
    username: $('input[name=username]').val(), 
    password: $('input[name=password]').val()
    }, function(data) {}, 'json');
    
  2. PHP authenticates the information against the database then generates a response which is json_encoded and sent to the browser.

    $user = $this->auth_model->Login($_POST['username'], $_POST['password']);
    
    if($user)
        $data['success'] = true;
    else
        $data['success'] = false;
    
    echo json_encode($data);
    
  3. JavaScript client ‘eval’uates the JSON which creates an object. JavaScript client then determines behavior based on the data in the object.

    $.post('/ajax.php', {username: $('input[name=username]').val(), password: $('input[name=password]').val()}, function(data) {
        if(data.success)
        {
            // login succeeded
        } else {
            // login failed
        }
    }, 'json');
    
]]>
AJAX with jQuery: The Beginning http://heybigname.com/2009/03/26/ajax-with-jquery-the-beginning/ Thu, 26 Mar 2009 19:40:53 +0000 This is the first in a series of screencasts that I'm creating to highlight the AJAX functionality present in the open source Javascript framework jQuery. In this screencast I give a brief overview of AJAX as well as delve into our first jQuery command.

AJAX stands for Asynchronous JavaScript and XML.

]]>
CodeIgniter at the Nashville PHP meetup March 20th. http://heybigname.com/2009/03/10/code-igniter-at-the-nashville-php-meetup-march-20th/ Tue, 10 Mar 2009 07:14:37 +0000 I'll be making a presentation on the popular PHP development framework 'Code Igniter' on March 20th at the Nashville PHP meetup.  This will be the first presentation of many as they systematically explore each of the most used and most functional PHP development frameworks.  Come visit, ask questions, and save time by learning the basics from experienced developers.

]]>