Adventures in ASP.NET MVC: A migration experiment from Laravel

Back in early 2014, my office briefly put me in a production support rotation for our flagship application built on ASP.NET. I’ve been wanting to get out of the PHP ghetto for a while, and I’ve experimented with building desktop applications with the .NET framework in the past.

So I bought some books and snagged a copy of Visual Studio 2012 to practice on my own. I made some tentative step in porting the Observant Records Administration site from PHP to C#. Then my rotation ended abruptly because business needs pulled me back into the PHP ghetto. I haven’t touched ASP.NET since then.

A recent lull allowed me to pull out that old abandoned code. Since then, Entity Framework and ASP.NET under went some revisions. I also ported the Observant Records Administration site from CodeIgniter to Laravel.

During that conversion, I noticed how much Laravel resembled ASP.NET MVC, which probably owes a lot from Ruby on Rails. Even Laravel’s templating engine, Blade, is a knock-off of ASP.NET MVC’s Razor.

So what would happen if I attempted to convert a Laravel application to ASP.NET MVC?

I spent few weeks at the start of 2015 finding out.

And just to make things interesting, the application I was building in ASP.NET MVC connects to my development MySQL database, not SQL Server.

So how did it go? Well, I got far enough to get a gist of how much would need to be refactored, then realized I would never launch it since I don’t have a production environment.

But I learned a lot about crossing programming cultures, which would be easiest to enumerate in a list.

PHP vs. C#

I’ve long ago adjusted to switching between static and dynamic typing. In fact, PHP best practices have moved to emulate static typing, and type hinting certainly bridges the gap between the two language styles. Part of me even looks forward to the strict mode in PHP7.

Although namespaces have been available since PHP 5.3, many of my projects have a lot of legacy code that predate their usage. I’ve slowly gotten into the habit of using namespaces, but the differences in how they work in PHP compared to C# and JAVA tripped me up quite a few times.

For example, I wanted to parse some JSON input in my ASP.NET MVC application, but Intellisense in Visual Studio didn’t recognize the JSON library in my controller. It turns out a library in ASP.NET MVC has a JSON property, so to parse JSON itself, I needed to import a different library.

If I worked more with namespaces, I would have realized it sooner.

C# vs. .NET

In the beginning, I thought I hated JavaScript, until I used JScript with ASP 3.0. I realized I didn’t mind JavaScript at all. It was the Document Object Model I hated.

A similar distinction can be made between C# and .NET. Although they’re tightly coupled in terms of how they’re discussed, they’re actually distinct entities. C# is a language; .NET is a framework. You use C# to manipulate the .NET framework.

It’s not too difficult to jump from another language to C#. The larger leap is navigating the .NET framework.

That’s where I felt most out of my depth. I would jump on the MSDN Library to figure something out, then to whatever search results to which Google directed me. And even after getting something working, I would be left with a sense that I didn’t come away with a complete picture of how everything worked.

A lot of this conversion process involved gleaning the underpinning machinations of Entity Framework without diving too far into the innards. I wanted to get something working, and I didn’t want to sink so much time fishing for the documentation to get me there.

Microsoft vs. not-Microsoft

Laravel’s Eloquent is an active record ORM, while Entity Framework is a data mapping ORM. There’s no point trying to compare the two since they operate on different paradigms.

Most of the applications with which I’ve worked use active record ORMs. SugarCRM is the only data mapper I’d encountered till grappling with Entity Framework and its Fluent API.

There are a lot of tutorials and examples out in the wild to explain how model properties map to database columns, and just about all of them assume you’re working within the Microsoft ecosystem of Visual Studio/IIS/SQL Server.

So it took a lot of debugging and random flaling to hit on a pretty important aspect about mapping to a MySQL source.

Here’s a simple example.

public class ArtistMap : EntityTypeConfiguration

        public ArtistMap()
            // Primary Key
            this.HasKey(t => t.Id);

            // Properties
            this.Property(t => t.DisplayName).HasMaxLength(255);

            // Table & Column Mappings
            this.Property(t => t.Id).HasColumnName("artist_id");
            this.Property(t => t.DisplayName).HasColumnName("artist_display_name");

Most tutorial examples for the HasColumnName method plug in the name of a model property straight into the method without explaining that the column name and model property are spelled exactly the same. That doesn’t quite work if your database schema predates the code and already has its own naming convention.

In my example, artist_display_name is the name of my column, and I want it mapped to the DisplayName property of my model. At first, I followed the examples — good old copy and paste! — and got nowhere because, duh, my database column is not named DisplayName.

This kind of assumption is reflective more of a culture than a platform. PHP programmers speak in a slightly different dialect than .NET programmers, even if we’re both speaking “programmer”. So when an interloper such as myself attempts to speak another culture’s dialect, subtext will always be missing in action.


How to customize controllers generated by Artisan in Laravel

I’m porting a web-based application I built in the office from CodeIgniter to Laravel, and I’m relying a lot on Artisan to generate REST controllers. I’m not doing anything terribly fancy with the generated controllers, so I end up copying and pasting a lot of code.

Yes, I could probably design this application to prevent all that copying and pasting, but it’s for a system that I intend to retire in the next 18 months. So I’m not hung up on cleverness.

Instead, I wanted to find a way to generate as much code as possible so the refactoring work concentrates mostly on refinement.

Artisan make commands generate very minimal scaffolds for models and controllers. What if you wanted Artisan to generate something with more meat on the bones?

That’s where the ControllerMakeCommand class comes in.

I found this class by performing a search of the Laravel vendor folder for one of the help strings in the php artisan list command. The class itself extends GeneratorCommand. By studying these classes, I could see extending ControllerMakeCommand and overriding a few methods could get me on my way to creating my own controllers.

Of course, you need to know a little bit about how to create your own Artisan commands before you can create your own controllers. I won’t go over that since the Laravel documentation does a good job of it already.

Here’s an example of an extended ControllerMakeCommand

<?php namespace App\Console\Commands; use Illuminate\Routing\Console\ControllerMakeCommand;

class CustomControllerMakeCommand extends ControllerMakeCommand {
     protected $name = 'example:controller';
     protected $description = 'Create a customized controller in Laravel.';

     protected function getStub()
         return __DIR__.'/stubs/controller.custom.stub';

     protected function buildClass($name)
         $stub = $this->files->get($this->getStub());

        return $this->replaceNamespace($stub, $name)->replaceScaffold($stub)->replaceClass($stub, $name);

    protected function replaceScaffold(&$stub)
        // Parse input name.
        $name = str_replace('Controller', '', $this->getNameInput());

        // Create replacements
        $viewPathName = strtolower(str_replace('\\', '.', $name) );

        // Apply replacements
        $stub = str_replace('dummyViewPath', $viewPathName, $stub);

        return $this;

ControllerMakeCommand reads a text file and substitutes strings in the file with values based on the namespace. To customize our controllers, we want our Artisan command to use our own text file instead of the one used by the parent class. So we override the getStub method in CustomControllerMakeCommand to point to a text file we prefer. In this example, it’s the directory in which our customized class resides, i.e. app/Console/Commands.

The controller.custom.stub file, then, contains your customized controller code.

The overridden buildClass method reads the .stub file and performs string processing. It usually processes the namespace (replaceNamespace) and the class name (replaceClass). You can inject additional string processing between these method calls, which is what replaceScaffold does. Note that the method returns the object reference ($this), not the processed string. Returning the object reference allows for chaining. replaceClass returns the final processed string.

The fire method in the grandparent GeneratorCommand class then generates the actual controller files with the string created by CustomControllerMakeCommand. All that’s left to use your custom command is to register it.

Models can also be customized in a similar fashion by extending the ModelMakeCommand class. Since it too extends GeneratorCommand, the same methods, particularly getStub, can be overridden.

Using namespaces in WordPress themes and plugins

I consider myself a relative newcomer to WordPress plugin and theme development, but I have programmed in PHP for more than a decade. That said, my first attempts to create a theme and plugin consisted of taking someone else’s work and tweaking it till it did what I wanted it to do. In short, the classic hacker’s learning process.

I’ve now moved on to the next phase of the learning process — applying ideas from work in other applications to WordPress. That means getting rid of stuff in my themes and plugins that I thought I needed but don’t really need, and tailoring each kind of project to their specific requirements.

One idea drilled in the WordPress documentation is namespacing. It’s not called that specifically because WordPress has been around long enough to predate PHP’s support of namespaces. But in exploring tutorials on theme and plugin development, I saw a lot advice about giving functions a unique prefix. In other words, use naming conventions to enforce a namespace.

Many enterprising developers have encapsulated their plugins with object-oriented programming, a practice to which I adhere myself. But the first versions of my plugins resulted in some unwieldy and oftentimes long-winded naming.

For example, the Artist Connector for WordPress prefaced class names with Musicwhore_Artist_Connector_, Musicwhore_ or some variation of the two. The file names followed suite, with such names as musicwhore_artist_connector_db_driver.php and musicwhore_artist_connector_post_meta.php.

To reign all this verbosity, I looked to the PHP Framework Interop Group standards for a bit of guidance. WordPress doesn’t follow the PHP-FIG recommendations, but it doesn’t mean there aren’t any good ideas there. One of them is the use of PHP namespaces.

The WordPress plugin environment is rightly concerned about naming collisions — my function named setup should have no effect on someone else’s similar function named setup. At the same time, something cryptic as mwac_setup is hardly readable.

PHP namespaces allows me to carve a place where my readable names won’t collide with anything else, perhaps even WordPress core itself!

This example is a very abbreviated form of what I use in the Artist Connector.

namespace VigilantMedia\WordPress\Plugins\Musicwhore\ArtistConnector;


I’ve encapsulated my initialization tasks as methods in individual classes and gave them simple names. Without namespacing, I would have had to resort to a naming convention.


A classic WordPress example would forgo namespaces and classes altogether.

function musicwhore_artist_connector_setup() {
     add_action('init', 'musicwhore_artist_connector_init');

function musicwhore_artist_connector_settings() {
     add_action('admin_init', 'musicwhore_artist_connector_settings_init');

function musicwhore_artist_connector_init() {
    // Initialization tasks go here.

function musicwhore_artist_connector_settings_init() {
    // Initialization tasks go here.

The example with namespacing demonstrates an idea common to web frameworks: don’t repeat yourself. Time-honored WordPress naming conventions tend to be very repetitive.

Namespaces work well with organizing widgets, template tags and the functions.php file in a theme. The twentyfifteen WordPress theme, for example, uses traditional naming conventions to emulate namespacing.

function twentyfifteen_entry_meta() {
    // ...

function twentyfifteen_categorized_blog() {
    // ..

Object-oriented programming can simplify this organization.

class TemplateTags {

    public static function entry_meta() {
        // ...

    public static function categorized_blog() {
        // ...

Now say you have a child theme based on twentyfifteen. You can still create a TemplateTags class without having to use naming conventions to distinguish itself from the parent theme.

namespace WordPress\Themes\TwentyFifteen {
    class TemplateTags {
        public static function entry_meta() {
            // ...

        public static function categorized_blog() {
            // ...

namespace WordPress\Themes\TwentyFifteenChild {
    class TemplateTags {
        public static function entry_meta() {
            $output = \WordPress\Themes\TwentyFifteen\TemplateTags::entry_meta();
            // ...

Namespaces have been available in PHP since version 5.3, which reached end-of-life support back in August 2014. So they should be very well supported on servers keeping up with PHP upgrades.

All in with WordPress

About a year ago, I described a massive relaunch of all my personal web projects from a custom solution to WordPress and Drupal. At the time, I said Drupal code had better readability than WordPress, and I also said Drupal’s strict naming conventions in the global namespace emulated object-oriented programming.

Today, Drupal is no longer part of my stack.

I moved all my blogs over to WordPress back in November. Part of it is professional need — my office is migrating a particular Drupal site to WordPress, and I wanted to get a feel for how such a migration would happen. Mostly, I just prefer the user interface of WordPress over Drupal.

I’ve also created custom plugins for both systems, and while the “Drupal way” has far more structure, the WordPress system of hooks is incredibly versatile. It took less time to create a connector plugin to the artist database in WordPress than it did to create a similar connector in Drupal for my record label Observant Records.

Drupal loves abstractions and does everything it can to shield developers from its inner workings. That can really get in the way if something goes wrong far below the surface of the abstractions. It also makes its database schema probably more complex than it should be.

WordPress, by contrast, has a surprisingly compact database schema. So compact, in fact, that the opposite problem occurs — database tables doing multiple duties. In some instances, WordPress code is too tightly coupled to its database.

Neither Drupal nor WordPress has a particular good template system, but I found WordPress to be slightly more readable than Drupal. Or maybe the widget system in WordPress has a better user interface than the block system in Drupal. Conceptually, they operate very similarly.

As a result of all this work, I find myself getting drawn deeper into the WordPress platform. Am I slowly becoming a specialist in one application instead of being a general PHP developer? And should I be reluctant to adopt such a role?


A music notation workflow: NotateMe to Notion to Sibelius

When I’m not wrestling WordPress and Drupal to do my bidding, I sometimes hunker down in my home studio to record music.

Cakewalk SONAR is the bedrock for this computer-based studio, with a lot of assistance from Native Instruments KONTAKT and Propellerhead Reason. I’ve recorded four albums and numerous EPs with this set-up. The Achilles heel, however, has been notation.

I’m most comfortable when I can perform with a score, but so far, my “scores” have consisted of printed-out lyrics with chord markings scribbled between lines.

At the moment, the music notation space is dominated by two packages: Finale and Sibelius. The top-of-the-line products of both companies are akin to Adobe products in the publishing space. Both applications can produce amazing results but have steep learning curves. They’re packed with features that command a large initial investment.

And for the kind of music I record, they’re probably overkill.

I bought a copy of Finale back in 2006 as part of a going-out-of-business sale at an instrument store. I spent a month and a half getting acclimated to it, and I decided it was the most antagonistic user interface I’ve ever encountered. Every action was placed in a hierarchical silo that required endless scrolling through menus.

The user interface looked state-of-the-art for 1992, and the documentation was as byzantine as the software itself.

I’ve downloaded Finale demos in the subsequent years to see if anything has changed, and the answer is a resounding no. It’s telling the website has no screenshots.

So I switched to Sibelius and found the user interface far more intuitive and the feature set comparable. I thought I found my notation software of choice … until I would leave it untouched for months at a time.

Sibelius has some mighty powerful features intended to produce terrific-looking scores. But if you’re just looking to make turn a MIDI dump of a demo into a staff and chords, it might be more than you need.

A few weeks back, I browsed the Google Play store for a notation app I could use on my Android phone. I tried out NotateMe and was impressed enough by it to pay $40 for a full version. The handwriting recognition can get unwieldy at times, and you can’t exactly create the most robust scores with it. But if you just want to jot down a melody and chord progression, the convenience factor can’t be over-emphasized.

NotateMe can export to MIDI and MusicXML — straight to DropBox, even — which means another piece of software can pick up where NotateMe leaves off.

But which piece of software?

Hardware maker Presonus acquired a newcomer to the notation space called Notion. Rather than take on Sibelius and Finale, Notion offers speed and ease-of-use over a broad feature set.

Both Sibelius and Finale offer mid-priced versions of their products geared for musicians who don’t create orchestral scores, but these versions just remove features. They don’t change the workflow.

Notion actually feels like it was designed to get ideas down on notation quickly while still producing a great-looking score. Entering guitar tablature is a breeze, and the documentation is so clearly written that you’ll be working fast after an hour.

I did encounter a number of bugs, particularly where entering lyrics are concerned. The MIDI Export is absolutely borked when it comes to repeats.

Notion can also export to MusicXML, which can then be imported to Sibelius.

I still found myself reluctant to fire up Sibelius 6, and I traced my hesitation to the menu-driven interface. It’s really tough remembering where everything was. So I downloaded the demo for Sibelius 7.5 and tried out perhaps the most controversial change to the UI: the ribbon.

Some users dislike the ribbon. I’m not one of them.

I didn’t find the ribbon jarring when Microsoft introduced it in Office. I actually find it pretty convenient. But for Sibelius 7.x, the ribbon is a godsend.

The menus were getting just way too convoluted, and it was just too exhausting trying to internalize the layout. Oftentimes, I would think a particular function would be one place, when it turned out to be in another. My perception of how something worked obviously didn’t mesh with the UI designers of version 6.

But the moment I worked with the ribbon in Sibelius 7.5, I bought an upgrade immediately.

I anticipate doing more work in Sibelius now but not without doing some initial setup in Notion. It’s too bad that I need two or three pieces of software to accomplish notation, but the audience for notation is small and highly diverse. Notion has the potential to grow into a very under-served space and become the silver-bullet package for a mid-level audience.

Using Bootstrap with WordPress comments and pagination

One of the goals of refactoring my sites was moving from Blueprint CSS to Bootstrap. Blueprint CSS is no longer maintained, and Bootstrap supports responsive layouts. I wanted to make sure my sites were readable on mobile devices.

I would have preferred to use semantic class names in my markup, but since Bootstrap is new to me, I opted to follow example code as much as possible. In the future, I may get adventurous with using Bootstrap’s LESS source, but that day is not today.

Things were going great till I started using Bootstrap in my WordPress themes.

That’s when I ran into problems with the comment form.

I wanted to use a horizontal form, and that requires adding a Bootstrap class to the <form> tag. Unfortunately, WordPress doesn’t allow additional classes to be added to the function that renders a comment form.

Similarly, the function to paginate links doesn’t allow customized classes on the <ul> tag.

In a rush to get something out and working, I committed a grave sin — I hacked Core.

I added a few arguments to each of those functions to allow customized classes where I needed them, knowing full well those hacks would be blown away the next time I updated core. And that’s exactly what happened when I upgraded to WordPress 4.0.

I know what the correct solution is: replicate what Bootstrap does in style.css. If I were ambitious, I could create LESS aliases on the Bootstrap rules using WordPress class names. I’m not ambitious. Instead, I attempted to reverse engineer what Bootstrap was doing with its form-horizontal class and didn’t get far when I realized the time sink it would require.

So I opted for the less-wrong, still-lazy option — override those Core functions with a plugin.

Essentially, I copied the entirety of comment_form and paginate_links, renamed the functions with a bootstrap_* prefix so as not to collide with Core, then called those functions from my themes. The code for this plugin is available on Bitbucket.

bootstrap_comment_form adds four additional arguments to allow customization of the opening <form> tag and the submit button. bootstrap_paginate_links adds one argument to customize the pagination output when rendered as a list.

This solution opens up something of a maintenance nightmare.

If the original functions in Core change, they won’t be reflected in the overrides. Unfortunately, comment_form and paginate_links render their outputs instead of caching them in strings. So my override functions can’t call their parents and manipulate their results. I would need to copy any changes to the parent functions manually.

Or I could avoid this nightmare and submit this change to WordPress.


Laravel and WordPress: Options to run both

When my sites used to run on CodeIgniter, I would integrate Movable Type by not allowing Movable Type to display my content. Sure, I used Movable Type to manage the content, but I would build a presentation layer in CodeIgniter.

I retired both CodeIgniter and Movable Type, which left me with the puzzling question of how to make Laravel and WordPress co-exist. I learned my lesson — let the content management system handle the presentation layer and preserve walls between systems. (You’re reading the wrong blog entry if you’re looking for a way to integrate WordPress with Laravel.)

I ended up with a few solutions, due to some design constraints held over from the CI/MT days.

Keep everything separate

This blog resides under the sub-domain of, and it runs on WordPress. The main portfolio site is run on Laravel, and the only way either is connected is through navigation.

I’ve even differentiated the look and feel of the sites to enforce that separation.

Run Laravel as the main site with WordPress as a sub-directory

The document root of a server running Laravel points to the public folder, which means WordPress could run in its own directory. is structured that way because the individual blogs are sub-sites under the domain.

Run WordPress as the main site with an alternate Laravel index

Now things get interesting.

Both index.php files in WordPress and Laravel want to control the document root. In this solution, something has to give.

In the case of Duran Duran Networks, the blog is the main site, and the Laravel pages are the off-shoots. So, WordPress gets to rule the document root. The Laravel index file gets renamed to lv.php.

Since the site doesn’t have much content, it’s easy to manipulate the RewriteEngine of Apache to redirect specific paths to Laravel, while letting WordPress figure everything else out.

Note how the WordPress installation itself resides as a sub-directory of the Laravel public folder.

The following RewriteRule is added to the RewriteEngine section of the WordPress .htaccess file. It’s a regular expression looking for specific paths to route to lv.php.

RewriteRule ^(tour|album|login|logout|admin|signin)(|\/) /lv.php [L]

At some point, this solution is going to get unwieldy as the Laravel content grows, but for now, it works.

Paying off the Vigilant Media Network technical debt

The purchase of my Mac spurred me on to face the reality of my aging web stack. My technical debt had accumulated to the size of my financial debt, and it was time to pay up.

Back in 2012, I laid some groundwork by moving to WordPress and all my music-related projects to Drupal. I did that out of professional necessity since I had to support those applications at work, and I had no experience with either.

Newer things started to edge into my consciousness — Laravel, Bootstrap, Composer, PHPStorm — but I hadn’t felt the need to deploy them on my personal web stack since I knew it would require at least a number of weeks of refactoring.

Then the older stuff started getting older. EllisLabs wants someone else to own CodeIgniter. Blueprint CSS froze development. Finally, Movable Type stopped offering an open-source version.

The Mac made it enjoyable to code, so I rolled up the metaphorical sleeves and went to work.

First, I retired Movable Type by moving all my blogs — most of them defunct — to WordPress. In the case of the Archive, it meant learning how to build a custom plugin to connect to the artist database.

Next, I retired Blueprint CSS in favor of Bootstrap. Now my sites are mobile-friendly.

Finally, I moved some administrative sites off of CodeIgniter and into Laravel.

I’m kind of amazed by how much I got done in the past seven weeks. Ten years ago, this same amount of work would have taken at least three to four months.

Some of these migrations aren’t feature complete, but another thing I’ve learned in the last few years is done is better than perfect.

I also took an unprecedented step of shutting down a site. Austin Stories had been running as an archive, and I couldn’t justify the effort to migrate it.

I’ve reached a point now where everything is moved, and I can take a breather. My hope is to write a few entries about this migration.

Movable Type Mystery: UTF-8 headers and still showing question marks?

It’s been years since I’ve done anything with Movable Type, and I thought it was high time to migrate all my defunct blogs to WordPress. So I logged into Movable Type for the first time in a long time, and I discovered Japanese text in various entries were showing up as question marks in my Movable Type interface.

That was odd.

I have a configuration file from the early 2000s that should have addressed that problem. My config file specified the PublishCharset value to “utf8” and SQLSetNames set to true.

I tried a few solutions I found online, but none of them worked for the simple reason that the Movable Type admin interface was indeed rendered with a UTF-8 content header.

To make matters even more confusing, I queried the database directly through both phpMyAdmin and through the command line. (Hint: start MySQL with the option --default-character-set set to “utf8”.) The Japanese text was showing up fine.

What was going on? Why was it broken now when it worked in the past?

It seemed the key lied in those configuration variables PublishCharset and SQLSetNames. So I searched through the code base to find instances where PublishCharset and SQLSetNames were used.

PublishCharset returned a lot of results, but SQLSetNames appeared in only a handful of files — most notably in the drivers for MySQL and Postgres. With some strategically placed print statements, I discovered that SQLSetNames was being set with a “latin1” character set.

How could that be?

As it turns out, the MySQL driver in Movable Type queries the database for the value of the setting variable character_set_database. I suspect a server move by my host may have reset this value from “utf8” to “latin1”. All I had to do was change the value of this variable, and the question marks disappeared. For example:

ALTER DATABASE `{your database name}`
COLLATE utf8_general_ci

Key take-aways: Movable Type executes a Set Names command in MySQL based on the configured character set of your database. If the character set is not set correctly, your Movable Type admin interface may display characters as question marks, even though UTF-8 headers are being sent to the browser.

I’m a Mac. Finally.

It finally happened. I put thought to deed and bought a MacBook Pro.

The University of Washington Bookstore Tech Center holds a Tax Free Day on Apple computers every so often, and I decided to take advantage of one.

I went with the cheapest option: a rustic MacBook Pro with ye olde hardde drive, and a slot for optical media. None of this Retina display or flash memory business. Air is something you breathe.

The primary aim for this machine is for web work. It’s not my first time using a Mac.

As previously mentioned, I worked in a dev shop run on Macs from 2010 to 2011. Now that I’ve had this Mac for a week, I remember all the little conveniences that made web development easier. Namely, the Terminal.

In Windows world, you need a separate program to make a secure shell connection — Cygwin or PuTTY. I find myself dreading the Windows DOS prompt when I do work in the office. Switching back and forth between back-slash and forward-slash is a few microseconds of mental friction that adds up over the course of a work day.

The Terminal on my Mac gets rid of that friction and actually makes development … pleasant.

So pleasant, in fact, I’ve actually gotten quite a bit of work done. I created some new WordPress themes for this site and, learning Bootstrap in the process.

As I type this, I’m lying on my futon instead of sitting at the kitchen table. My current Windows laptop is a Dell I bought in 2007, and it’s a hulking piece of metal I wouldn’t consider setting on my lap.

I doubt this MacBook Pro is going to become my primary machine. I definitely wouldn’t use it to run Cakewalk SONAR, the digital audio workstation I use for my music projects. And I’m debating whether I want to sully this machine with Parallels and Windows.

For now, I’ll enjoy the productivity this machine is enabling.