Programming

Selecting Your Next App Dependency

We often turn to open source or proprietary packages for adding functionality to our apps. Here are some key points and questions to ask when selecting your next dependency. This list can help compare multiple packages to determine which fits our needs better. The goal is to find well thought out packages because our apps depend on them.

Documentation

Documentation is often the first place we look when there are questions. If the package is well documented then developing a solution will be easier.

  • Does documentation exist?
  • Is the documentation up-to-date?

Community

An active community signals to us this package is adopted and being used by other people. Finding whether the community is active should be easy. My go to places are:

  • Stackoverflow (Are people asking questions about this package? Are the questions answered?)
  • GitHub (When was the last time the package was updated? How many issues exist? Do the maintainer(s) respond to issues? How many pull requests? Do the maintainer(s) respond to pull requests? Does the package follow semantic versioning? How many stars?)
  • Package specific forum (Does it exist? Is the forum active?)
  • Google

If the community is actively helping other people it’s a good sign. The chances of getting help with an active community are higher than if there was little to no community.

Extendability

Often times the package won’t meet our requirements 100% so we must add additional functionality.

  • How easy is it to build a module?
  • Are there hooks or events to add additional functionality without modifying core code?

Code Coverage

Well tested code can lead to less defects. Depending on a package that isn’t tested is risky.

  • Does the code base have tests?
  • How much of the code base is covered by the tests?
  • Are the critical parts of the package tested?
Tips

Trade-offs

As developers we work with non-technical people and we can do a better job connecting with them. Non-technical people don’t care about the technical jargon certainly don’t want to hear about how the repository doesn’t fit into the polymorphic inheritance. What they do want to hear are trade-offs or implications.

For example: If someone non-technical asks “Can x feature be developed and deployed within the next month?” The answer is of course “it depends“. Most likely the person asking if the feature can be developed doesn’t necessarily understand the trade-offs of building the feature within 1 month instead of 6 weeks.

Don’t blindly say yes or no with technical jargon. Find a way to connect that brings value to everyone in the conversation. Adjusting what you say depending on who the receivers are. In our example above we want to explain that we can finish the feature within the month, but recommend not to and explain.

Our answers may be:

Finishing the feature within a month will increase technical debt, make it difficult to implement features in the future, and push the limit on capabilities. If any other requests came through during the month we most likely would not finish the feature in time. 1 month is best case scenario and is risky.

If we take 6 weeks instead of 4 we can test our code maintaining stability, keep our sanity, and maintain application flexibility.

In both answers above we explain the trade-offs in a non-technical manner. Arming the person with information necessary to make a proper decision. The most important part is to actually give the person enough information to make an informed decision instead of making it blind.

* Keep in mind recommendations are not always adopted and certainly don’t take offense if the recommendation isn’t adopted. If you provided them enough information to make an informed decision that’s most likely all that can be done.

Life Pro Tip, Tips

Mental Snapshots

Think back to a time where you accomplished something you had no idea how to do or when you accomplished something and surprised yourself. If this hasn’t happened yet be on the lookout when it does happen and you successfully solve the problem create a deep mental snapshot of the wonderful feeling. Keep this in your head and refer to this when things are tough. It will help remind you that you are capable and to give yourself time.

I use this technique often. My mental snapshot I often dig up is during one of my internships, I was tasked to update a Java app. My Java experience at that time was limited to only the exercises the professors had us write. The Java app was bigger than any other app I had ever worked with. At the start of the summer my reaction was “How will I be able to do all of this?”. As the summer came to a close I ended up completing my work plus some additional items. I now use this experience as one of my mental snapshots. I refer to this when asked to things I have no immediate path or answer to.

This can be a frightening, but it’s important to take a step back and think back to your mental snapshot. This will give you the confidence to keep going and to believe in yourself. If possible break the ask down into smaller more manageable pieces. These smaller pieces will help keep your sanity as you attempt to figure out an approach.

Embrace what you don’t know and view it as an opportunity to learn, not something to be afraid of.

Laravel, Programming

The Importance of Eager Loading Laravel Relationships

Problem

Page took over 30 seconds to load locally on a local Vagrant virtual machine. After investigating the results were astonishing, over 1,000 queries executed in order to load the page. Not only was there an extraordinary number of queries executing, but also no constraints on the number of records loaded from each relationship.

Test and production environments didn’t show noticeable signs of slowness, but was clear on my local virtual machine that something was wrong.

Research

My research began using the Laravel debugbar. The debugbar helped me discover the amount of queries running for each page. Laravel debugbar has a query collector that conveniently displays the query count. An additional bonus is the number of duplicate queries along with which class called the query. Using these pieces of information I began tracking down the cause.

Cause

The cause was the classic N+1 problem. Essentially a loop was calling a relationship that had not been eager loaded. Each iteration of the loop caused the app to query the database.

Solution

The problem was easily solved using Laravel’s eager loading along with eager loading constraints.  Eager loading is loading your data up front before accessing the relationship. Because the relationship data was loaded up front accessing the relationship now pulls the value from memory instead of querying the database.

Eager loading constraints tell Laravel to only load specific records within a relationship. When you don’t need every record that a relationship has. E.g. Authors have books, but you only need love and thriller book types.

Eager loading with constraints reduced:

  • Query count from over 1k queries to 50 a whopping 2000% decrease in queries.
  • Number of records loaded from 7200 to 24.
  • Memory consumed by page from 140MB to 14MB.
  • Page load from 30 seconds to 2.5 seconds.

Example

Record labels have artists and artists have songs. If you wanted to get all artists on a record label along with their songs, but only the songs that reached top 10 on the billboards

Non-eager loaded:

$artists = Artist::take(500)->get();
$artist->songs;

Eager loaded without constraints (returns all songs):

$artists = Artist::with('songs')->take(500)->get();

$artist->songs;

Eager loaded with only songs that made top 10:

$artists = Artist::with('songs' => function ($query) {
    $query->where('highest_position', '<=', 10); 
})->take(500)->get();

$artists->songs;

Consider the following loop. If we don’t eager load the songs then for each artist a query to the database will be executed. This example may be a bit over the top because in most cases paginating the data would also solve part of the issue in this specific example, but I wanted to outline the potential issue.

foreach ($artists as $artist) {
    $artist->songs->each(function ($song) use ($artist) {
        $song->fullName = $artist . ' - ' . $song->title;
    });
}

Website Launch: Champion Spotlight

I launched a new website dedicated to finding champion spotlights: http://championspotlight.lol for the game League of Legends (LoL).

If you haven’t heard of League of Legends:

League of Legends is a fast-paced, competitive online game that blends the speed and intensity of an RTS with RPG elements. Two teams of powerful champions, each with a unique design and playstyle, battle head-to-head across multiple battlefields and game modes.

100% of the website is built on Vue.js and the champions are loaded via an API.

Technology Stack

  • Amazon S3 (static website hosting)
  • Amazon Route 53 (DNS)
  • Amazon Cloudfront (CDN)
  • Vue.js

The goal was to start simple. I find it easier to iterate on something in production than to continuously add features without ever making it into production.

Biggest Challenge

Implementing S3, Route 53 and Cloudfront was the biggest obstacle. Every article on the internet seemed to be slightly different than what I needed. One thing I’ve learned over the years programming is that perseverance pays off. Eventually after spending hours configuring settings the website eventually worked!

 

Building Champion Spotlight was a blast and learning experience. Overall I learned about the AWS infrastructure, filters in Vue, and that I’m able to learn new technologies on the fly.

Vue.js

Introduction to Vue.js 2 Filtering with Lodash

Filtering in Vue.js is simple thanks to the filter function built into Vue. Let’s take a look at an introduction filtering with Vue.js and Lodash.

Setup

Each Vue app requires a HTML element to bind with. Generally the HTML element is a div with a unique id attribute. In this example the Vue instance is bound to simple-filter.

<div id="simple-filter">
</div>
var app = new Vue({
    el: "#simple-filter"
});

Basic list unfiltered

Next let’s add default data and display the list.

You’ll notice v-for on the li element. This essentially means for each element in the array do something. In our case print the element between the li element.

<div id="simple-filter">
    <ul>
        <li v-for="animal in animals">{{ animal }}</li>
    </ul>
</div>

var app = new Vue({
    el: "#simple-filter",
    data: {
        animals: ['Zebra', 'Lion', 'Shark', 'Dog', 'Bear', 'Monkey']
    }
});

Produces the following list:

  • Zebra
  • Lion
  • Shark
  • Dog
  • Bear
  • Monkey

Filtering

Vue.js has built in functionality to filter arrays. The basic idea is to iterate over each element with a condition. If the condition is true the element stays in the array. If the condition is false the element is removed from the array.

Within the v-for instead of using the regular animals array in the previous example it is referencing a computed property filteredAnimals. Using the computed property ensures the list is always up to date when searchText is updated.

<div id="simple-filter">
    <input type="text" v-model="searchText" />
    
    <ul>
        <li v-for="animal in filteredAnimals">{{ animal }}</li>
    </ul>
</div>
var app = new Vue({
	el: "#simple-filter",
    data: {
    	searchText: "",
        animals: ['Zebra', 'Lion', 'Shark', 'Dog', 'Bear', 'Monkey']
    },
    computed: {
    	filteredAnimals: function() {
        	var self = this;
        	return this.animals.filter(function (animal) {
            	    return _.includes(animal.toLowerCase(), self.searchText.toLowerCase());
            });
        }
    }
});

filteredAnimals updates itself when searchText changes due to the nature of Vue. The filter function on this.animals is provided by Vue. Each iteration of this.animals passes an animal element to the function. Within the function a true or false value should be returned. Returning true indicates keeping the element and false instructs Vue to remove the element.

In the filter function notice _. this is Lodash. In short Lodash is a library that contains commonly used utility functions such as the includes function. The includes function searches an array, object, or string for a given value. The value in this example is the user provided text searchText. In addition I’ve added a toLowerCase() because users may not always include capital letters. Forcing the compare to be case insensitive is useful for this use case but may not in every case.

Filtering the array does not actually update the animals array. Instead a new array is returned which is then returned from the filteredAnimals computed function.

Working example below:

How To Bind An Interface To An Implementation In Laravel

Binding an interface to an implementation promotes good coding practices. As a result the code is less coupled, more maintainable, and testable.

Why might someone want to bind an interface using Laravel? To put an abstraction between the application and the concretion. A concretion is a class that implements the interface. It is a specific implementation, in our example it will be Amazon S3 file storage provider. The application doesn’t care which implementation it receives just that it receives an implementation with the guaranteed functions.

Lets build functionality to interact with files on a storage provider such as Amazon S3. Initially all files will be uploaded and deleted on S3 only. There are other ways to accomplish this and the main goal is to demonstrate how to bind an interface to an implementation and not so much the actual code to upload to a storage provider.

Create An Interface

The interface will determine which functions are available on the concrete implementation through the binding.

Create The Concrete Implementation

The concretion is an Amazon S3 file storage provider. This file is where Amazon specific upload/delete functionality goes.

Create The Laravel Service Provider

The Laravel service provider is the mechanism that binds the FileStorageInterface to the S3FileStorage class implementation. This means if we use dependency injection for the FileStorageInterface or use App:make it will automatically resolve to the S3FileStorage class.

Using The Interface

In the below example we are not using the implementation directly. Instead it is automatically resolved through the service provider which returns the concrete implementation. Laravel will automatically resolve dependencies if they are in the __construct() functions. We can see below that the controller doesn’t know about Amazon and nor should it. I am only using the controller in this example to provide a demonstration. There are other places where we would use the storage provider that might better organize the code.

Final Thoughts

If we wanted to swap out for Dropbox or some other provider the impact is minimal, create a Dropbox implementation and change the provider. The application would now use the Dropbox implementation instead of the Amazon S3 implementation.

Following this pattern can also help separate the application from Laravel which could make reusing this code in other projects easier than if the Amazon S3 code were included in a model directly. Definitely think about how to best structure your code and not to fall into the framework convenience trap of putting everything in a model, controller or view. In most cases there are better places for code than those 3 areas.

Magento

Magento Upgrade 1.7 to 1.9

Recently I upgraded a Magento site from 1.7 to 1.9 and recorded the steps I took to upgrade. This should work for other versions as well, but in my case it was 1.7 to 1.9.

Before the upgrade backup entire site so you can rollback if necessary.

Upgrade

  1. Visit <yoursite.com>/downloader and login with your regular admin credentials.
  2. Select “Put store in maintenance mode” in the Settings section.
  3. Click the check for upgrades button.
    1. All items that can be upgraded will display in a different color.
  4. Select items you wish to upgrade using the dropdown next to the installed version number.
  5. Click “Commit Changes” button to start the upgrade.
    1. Text should begin to appear in the console as Magento is finishing the tasks.
  6. Upgrade is finished.
  7. Check the site is up and running properly.

Post Upgrade

A few minor errors occurred after the upgrade and here is how I solved them.

  • If the maintenance flag is still active remove the maintenance file by rm maintanence.flag
  • Apache was complaining that index.php and downloader/index.php were group writeable. Change permissions on the index.php and downloader/index.php to 644.
  • PHP threw an error in file app/code/core/Mage/Core/Controller/Varien/Front.php saying Call to member function rewrite() on a non-object. If you are using a cache restart the caching mechanism. E.g. sudo service memcached restart
  • Admin URL displayed a blank white page also commonly referred to as the “White Screen Of Death”. This was fixed by downloading the Magento zip file from Magento and uploading the necessary files to app/design/adminhtml/default/default and skin/adminhtml/default/default. The upgrade appeared to have deleted those files so they needed to be re-uploaded to their respective locations.

Framework Convenience Trap

The idea is “x” framework provides a level of convenience that can make developers sloppy.

This often happens because frameworks tend to make developing easier. So easy we forget to take a step back and figure out how all the pieces come together.

If the framework is modeled on the model view controller (MVC) pattern. The convenience trap for developers is adding unnecessary amounts of logic into controllers or models. It’s easy to do and get the work “done” and out of the way if no testing is involved. Generally the problem with putting unnecessary amounts of logic in controllers or models is hard to test which subsequently causes the application to be brittle.

For example:
Oh looky here something database related this needs to go in a model or hey this interacts with the user’s input this probably goes in the controller.

The framework should not be the application, but a portion that compliments the development.

Note: The above generally applies to larger apps and not small apps that may have a short lifecycle.

How to mitigate the framework convenience trap?

  1. Write tests for the application. If tests are written chances are the structure of the app is designed better.
  2. Learn software best practices.
  3. Don’t code in a silo. Talk to other developers.
  4. Realize no one has perfect code and let someone critique your code. DON’T TAKE IT PERSONAL.

Simple Techniques To Influence Your Future

The future is unpredictable, however many techniques can influence your future to put you where you want to be.

Knowledge Is Power

Educate yourself. Knowledge is power.

Network

Personal and professional networks are invaluable. Put yourself out there, talk with people.

Listen

Become a great listener. Listening well is a difficult skill to learn, but can yield amazing results. Listen a fraction longer than what feels comfortable and you will hear things you normally wouldn’t. People love to be heard.

Read

Read blogs, books or what ever sparks your interest.

Hard Work

Put in the hard work upfront and receive the benefits later.

Positive Attitude

Use a mistake to your advantage. A mistake can be a learning opportunity to better yourself. Check and adjust.

Proactive

Go out there and seize the opportunity. Don’t wait for an opportunity to find you.

 

“You miss 100% of the shots you don’t take” – Wayne Gretzky

Lastly be true to yourself. Live your life with honesty and integrity. People will feel the aura that surrounds you.