Why Aren’t You Speaking?

Earlier today, I asked on Twitter why technical conference attendees hadn’t been a speaker at a conference themselves. Here are a few of the responses and my advice.

I haven’t been willing and able to spend the prep time I feel that would deserve.

All I can say to this is, budget your time. If it’s important, you’ll make the time for it. All speakers have to. While speaking may not be for everyone, I do highly recommend giving it a try at least once.

Stage fright. Lack of competence (or impostor syndrome). Thinking my areas of expertise wouldn’t appeal to others. Basically, fear.

Not feeling I am enough of an expert or knowledgeable on a topic to get up and speak. (CFPs can be intimidating too.)

Speaking for 45min-1hr is intimidating; didn’t have subject I’m confident in and have that much content for.

My talk submissions have not been accepted, likely because I lack local practice.

Perceived lack of expertise comes from the Dunning-Kruger effect, specifically the aspect of when a relative (to the audience) expert underestimates the extent of their own knowledge. It’s a cognitive bias that has to be overcome.

The same applies to stage fright. I’ve seen people who would quite literally faint at the prospect of speaking in front of a group overcome their fear and go on to become great speakers. It takes practice and repeated effort, but it can be done.

There are a few ways to dip your toes in the pool of speaking:

  • Start by writing a blog post or article for a site like SitePoint or a magazine like php[architect] about the topics you’re considering speaking about. In addition to helping you build knowledge and practice presenting it off-stage, these can help you build credentials as someone familiar with the relevant subject matter.
  • When speaking, start small. Give a lightning talk for a group like Nomad PHP, which has a significantly shorter length than one for a conference. Attend a conference that hosts an unconference and volunteer to give a shorter talk there. Volunteer to speak at a local user group or your local Toastmasters chapter.
  • Need help developing your conference abstracts? Use a site like HelpMeAbstract to get help from successful speakers or use a site like PHP Mentoring to find someone who can provide more one-on-one help.
  • Read my post on speaking resources for help when you’re ready to start submitting to conferences and how to handle preparing when you get accepted.
  • Don’t let rejections discourage you. It can take a while to get accepted. Be persistent. Try to improve your proposals, write new ones, and keep on submitting.

If you’ve spoken at a conference before, what are your tips for prospective or first-time speakers? If you haven’t, why not?

On Remaining Employable

Following my post on changing jobs, I communicated with a friend who’s in the market for a job. His circumstances inspired me to write a post for a slightly difference audience. So, here’s some advice on remaining employable as a developer.

  1. There are some job sectors wherein it’s been common for a developer to remain employed with the same organization for years, sometimes even decades. Government is one example of these. These sectors have two notable qualities: a) they are few in number; and b) they are becoming fewer by the day.
  2. These days, it’s very difficult to survive in the tech industry without some sort of specialization. There are too many technologies for you to be competent with all of them. While there are some exceptions, most companies look for developers with a specific set of skills who can hit the ground running when they’re hired, as opposed to developers who may be generally savvy, but will take time to become acclimated to a new tech stack. Choose your specialization carefully and, once you choose it, immerse yourself in it.
  3. There’s a balance to be found between the extremes of being a niche specialist and being a jack of all trades. Too specific a niche will mean that people with your skill set are difficult to find. While this sounds good, the lack of supply can ultimately limit available positions. That’s not to say that job availability should be the sole factor in what tech stack you choose to specialize in, but market demand is a factor worth taking into consideration.
  4. Do not become complacent in any position you take. Do not become too content or comfortable, do not assume that you will have the same job indefinitely. Things happen, losses are suffered, organizations downsize, people end up out of work. You need to remain potentially valuable to other organizations to stay employed, which means you need transferrable skills.
  5. Do not stop learning. If you only deal with technology from 9 to 5, you are what’s called a “day coder.” It may earn you a paycheck, but it will not keep you employable. Technology is too massive and changes too frequently for you to keep a reasonable handle on it from what few opportunities most 9 to 5 jobs will afford you.
  6. Be prepared to take time off the clock and spend your own money for professional development. Do research on new tech, experiment, work on side projects, contribute to open source projects, attend conferences or local meetings of professional industry peers, etc. Sadly, few companies that I’ve encountered seem to have both the resources and interest in the professional development of their employees to contribute significant time or money to such efforts.
  7. Network with people, and do not wait until you need a job to do it. Go to user groups or conferences, make a point of talking to people, form relationships, and stay in contact. Get online, join IRC and Twitter, ask questions, participate in discussions, put your name out there, and maintain visibility in those communities.
  8. Put your work in the public eye. Write articles for sites like SitePoint or magazines like php[architect]. File issues and submit pull requests to open source projects, or start your own. Submit to and speak at conferences and user groups.
  9. Update your résumé frequently. Add descriptions of projects you’ve worked on, both at work and on the side, complete with the tech stacks you used. Include links to your profiles on sites like GitHub or Bitbucket. List any publications or speaking engagements you’ve had.
  10. If you haven’t already, give my friend Cal Evans’ book on the subject a look.

Good luck!

On Changing Jobs

An apprentice recently sent me an e-mail:

For the past month or two my work has been a not fun and I’ve been very unhappy. I felt like I was being mismanaged, being setup for failure, thrown under the bus for things that were out of my control, and the lack of on-boarding really hurt my ability.

Two friends have asked to join their companies and I have interviewed but have not completed them. The company I am at is pretty good and it would be a positive step in my career but I’m quite miserable. I was working 14 hrs/day for a few days out of the week and a min of 9/10 hrs. It just caught up to me.

Then my boss quite and now I’m being managed by people in [redacted]. They discovered my work hours and cut it back to a normal day, sprints push back when feature creep happen, but I still have that bad taste in my mouth. Things have gotten a little bit better but the idea of working with my old boss from a previous company is tempting. Plus the code I’d be writing would be relevant and not just for profit.

Do you have any advice?

He later told me my response to his question was blog-worthy, so I thought I’d publish it for posterity.

Here are my observations:

1) Burnout is a very real thing. If you’re doing 50-60 hour weeks, that can be a fairly good sign of mismanagement. It’s good that you aren’t doing this anymore, but obviously that alone isn’t going to determine whether or not you’re happy.

2) In terms of money, most people ultimately work for someone else’s gain. You’ll be hard-pressed to find a job where you aren’t the source of another person’s dollar. In terms of having an impact on the world around you, whether or not you’re making the impact you want to make is something only you can decide for yourself. That said, I can definitely appreciate working for a cause you believe in and I very much think that’s an idea you should consider further.

3) Working for people you interact with mostly online or with a significant time difference can definitely be challenging. (Some other thoughts on that here.) It sounds like your new managers are at least trying to make circumstances better. Not all managers do that. Just something to consider. If there’s anything they haven’t improved that you think could stand improvement, try to approach them about it in an open and honest fashion.

4) There is definitely a “grass is greener” bias when it comes to your current job versus a prospective job, especially when friends are involved. (Side note: working with friends isn’t always what it’s cracked up to be.) The trick is learning to recognize that bias in your own thinking and to judge each job as objectively as you can. One method that’s helped me is making a list of pros and cons for each job that I’m considering, current and prospective. This forces you to really consider what matters to you.

5) Every job change is a risk. It’s possible the place you’re going to will be worse in some aspect, be it personal happiness, job security, or something else. There are many things you won’t necessarily know unless you actually make the job change. Make a point of asking as many questions as you can of prospective employers during the interview process to get a sense of what working at a new job would be like. This may give you food for thought.

6) If you do decide to quit your current job, I would definitely avoid doing so before you have a new job lined up complete with an official offer letter. Also, depart from your current job as amicably as you can. You never know what bridges you may need to cross again; burning them can limit your options in the future.

7) To paraphrase Cal Evans, if you’ve tried to make positive changes in your job such that you can be happy, to little or no effect, you’re ultimately left with only two other options: a) suck it up, get on board, and do your job to the best of your ability; 2) leave. Again, that’s a choice only you can make.

PHPUnit + XHProf = BOOM!

I ran into an issue recently while trying to run PHPUnit tests in an environment using XHProf. Google didn’t prove to be much help, so I thought I’d document the problem and solution here for posterity.

When I ran my tests, each failed with the same cryptic error and no backtrace.

Attempted to serialize unserializable builtin class PDO

The cause was the culmination of two rather unfortunate circumstances.

First, XHProf uses a global array variable to contain its configuration in its auto_prepend_file, which includes a PDO instance. Yet another reason to add to the list of reasons why global variables are bad.

Second, PHPUnit has a setting called @backupGlobals that is enabled by default. For reasons of which I’m uncertain, the library used for this applies and reverses serialization to variables in the global state for the purpose of creating a snapshot of it.

The method used for detecting serializability in this library unfortunately doesn’t presently detect that PDO can’t be serialized when an instance of it is contained within a global array variable. As a result, when PHPUnit attempts to snapshot the global state after a test has run and it encounters the PDO instance from the XHProf configuration, the error above is the result.

There appears to be a pull request with changes to this serializability detection, though I can’t speak to whether it would improve it or cover the use case causing this problem. I’ve filed a related issue against the appropriate repo. Until it’s addressed, I’d recommend either disabling @backupGlobals in your phpunit.xml file or disabling XHProf when running PHPUnit tests.

Hope this helps someone else. Thanks for reading!

So Long, Blopboard

I began an amazing journey with Blopboard when I joined them in October 2013. Unfortunately, it looks like that journey is coming to an end. For reasons unrelated to the quality of the team (which has been awesome) or the product (which has also been awesome), the decision has been made to cease operations at the end of June. As such, I will be investigating new employment opportunities within that time period.

I’ve published an updated version of my résumé at http://elazar.github.io. I’d very much appreciate it if you, my dear readers, could review it, share it on social media, and point me to anyone who may have opportunities that would be a good fit for me. It’s worth noting that I’m located in New Orleans and have obligations that will keep me there for the foreseeable future, so opportunities I’m able to consider would have to be either local or remote-friendly. Thanks in advance for your help.

Positive thoughts and moral support that have been and will be given are appreciated. Here’s to the next chapter…

Speaking Resources

I was fortunate enough to recently be accepted to the inaugural php[world] conference. Shortly thereafter, a friend of mine within the community inquired about submitting to and speaking at conferences. I thought I’d post the resources I shared with them here for others interested in the same topic.

Getting Accepted

Whether you’re accepted to speak involves several factors. Being known within the associated community certainly doesn’t hurt, especially for the topic you’re submitting about. However, some conferences do like to have an infusion of fresh blood sometimes, so being new can also be a good thing.

One thing that often helps is submitting several proposals to the same conference. Conferences generally try to minimize the number of speakers they accept to keep costs down, so the more talks you’re able to give, the more conducive you are to that end goal.

Also related is your distance from the conference site or, more specifically, what it will cost to physically get you there. If you’re just starting out, aim for conferences that are held within your geographical area. Try to find a local user group at which to present your session. This can help in crafting the proposal and improving the presentation itself. After you’ve done so, post the slides online. In your proposal, link to them and mention which user group received your session and when. This helps give credibility to your session and your skills as a speaker.

The quality of your proposals is also a factor. Make sure you put adequate time and focus into crafting them. Keep them concise, but mention the objectives and high-level points of your session in sufficient detail to communicate your expertise in and enthusiasm toward the subject matter. Ensure they’re relevant to the conference’s target audience. Calls for papers often mention specific topics of focus; be sure to look for and review these.

Resources

Customizing Codeception Database Cleanup

Recently, I was looking into ways to speed up the runtime of the test suite at Blopboard. We use the Codeception framework to write functional tests for our REST API, part of which entails putting the database into a known state using Codeception’s Db module. The behavior of this module is similar to that of the PHPUnit Database extension with one exception: where PHPUnit only truncates tables and leaves their schemas intact, Codeception removes the database structure and expects the SQL dump it uses to recreate it between tests.

I must admit to not understanding this design decision of Codeception, nor attempts to clarify it. Be that as it may, I had a hunch that subverting it might lead to a faster runtime for our test suite, so I set about trying to find a solution to facilitate that. I found one, and while it’s a bit hacky, it works.

<?php

namespace Codeception\Module;

/**
 * Extends the standard Db helper to override cleanup behavior so that tables
 * are truncated rather than dropped and recreated between tests.
 */
class DbHelper extends \Codeception\Module\Db
{
	protected function cleanup()
	{
		$dbh = $this->driver->getDbh();
		if (! $dbh) {
			throw new ModuleConfigException(
				__CLASS__,
				"No connection to database. Remove this module from config if you don't need database repopulation"
			);
		}

		try {
			if (! count($this->sql)) {
				return;
			}

			/** Start **/
			$dbh->exec('SET FOREIGN_KEY_CHECKS=0;');
			$res = $dbh->query("SHOW FULL TABLES WHERE TABLE_TYPE LIKE '%TABLE';")->fetchAll();
			foreach ($res as $row) {
				$dbh->exec('TRUNCATE TABLE `' . $row[0] . '`');
			}
			$dbh->exec('SET FOREIGN_KEY_CHECKS=1;');
			/** End **/

		} catch (\Exception $e) {
			throw new ModuleException(__CLASS__, $e->getMessage());
		}
	}
}

The above module class is used in place of the Db module. To come up with it, I started by digging into the logic of the Db module class itself. Codeception has several hook methods for modules that it calls internally. One of these is _initialize(), which is called after the module class is instantiated and configuration for it is loaded but before any tests are run.

Looking at the _initialize() implementation in the Db module class, I found that it makes a call to a method to obtain a driver object for the particular database in use. This driver object implements a cleanup() method that the Db module class’s own cleanup() method calls between tests to handle resetting the database state.

There’s a problem here, though: the call to obtain the driver object is to a static method, which means there’s no way for me to specify my own logic for how to obtain a driver object rather than the logic that Codeception uses by default. This inhibits extensibility as well as testability.

I could have gotten around this by extending the Db module class and overriding its _initialize() method to call out to different code to obtain an instance of my own driver class. However, that would have meant duplicating most of the logic of that method, which is not of a trivial size. This would raise the likelihood that my code would not work with subsequent versions of Codeception if the method I was overriding changed.

In the end, the alternative I found was to instead extend the Db module class and override its cleanup() method. While this still results in duplication of code, the code being duplicated (which is demarcated by /** Start **/ and /** End **/ comments in the above code sample) is shorter, simpler, and less likely to be changed such that it impacts my code’s functionality. It is worth noting, however, that the above code sample will likely only work with MySQL, and would need modifications to work with other database servers.

Had the Db module class encapsulated its call to Driver::create() within an instance method, I could have simply overridden that method in my subclass and had a cleaner solution.

Alternatively, Codeception could have supported a solution like this:

<?php

namespace Codeception\Module\Db;

interface DriverFactoryInterface
{
  public function create($dsn, $user, $password);

  // ...
}

class DriverFactory implements DriverFactoryInterface
{
  public function create($dsn, $user, $password)
  {
    // The contents of Driver::create() would go here.
  }
}

namespace Codeception\Module;

class Db extends \Codeception\Module
{
  protected $driverFactory;
  protected $driver;

  public function _initialize()
  {
    // ...
    if (!isset($this->config['driverFactoryClass'])) {
      $this->config['driverFactoryClass'] = '\Codeception\Module\Db\DriverFactory';
    }
    $this->driver = $this->getDriverFactory()->create(
      $this->config['dsn'],
      $this->config['user'],
      $this->config['password']
    );
    // ...
  }

  public function getDriverFactory()
  {
    if (!$this->driverFactory) {
      $driverFactoryClass = $this->config['driverFactoryClass'];
      $this->setDriverFactory(new $driverFactoryClass);
    }
    return $this->driverFactory;
  }

  public function setDriverFactory(DriverFactoryInterface $driverFactory)
  {
    $this->driverFactory = $driverFactory;
  }

  // ...
}

In the above solution, there is a DriverFactoryInterface interface with, among others, a create() instance method, and a DriverFactory class that implements this interface. The Db module class allows the specification of a class that implements this interface via its configuration. It then handles instantiating this class and calls that object’s create() method from its _initialize() method rather than calling Driver::create() as it presently does. With this code in place, I could write my own class implementing the interface to return my own driver. This would allow me to accomplish my goal without having to resort to subclassing.

In any case, my hunch and solution paid off: with the solution in place, we were able to cut our test suite runtime by roughly 30%. Another pleasant side effect was that I no longer needed to maintain a copy of our database schema apart from the one we already maintain using Liquibase.

I hope this solution and my thoughts on Codeception’s present design are helpful to someone. Thanks for reading.

ledger basics and habits

Some time ago, I wrote about the CLI accounting program ledger, specifically building ledger from source and a small pet project of mine for visualizing ledger data called ledger-stats. I’ve even given a short presentation on the subject. I thought I’d take a blog post to talk about some basics of using ledger and some of the habits I’ve cultivated in my own usage of it. For more comprehensive info, check out the ledger manual.

Journals

A journal is a file in the ledger format. It can be of any size, though I typically like to keep one per year. This keeps file size relatively small (my largest one to date is about 150 KB), so searching them is easy, and makes it easy to report on annual figures (e.g. business expenses that can be written off) without having to manually specify date ranges.

Accounts

An account is a label that represents a source or destination of money. A lot of people find this concept confusing because they associate it with an account at a bank rather than considering it as a more general concept. If you do any sort of computer programming, an account is similar in concept to a variable: it’s just a name with which a value (in this case an amount of money) can be associated.

ledger supports hierarchical organization of categories separated by colons, so you can have accounts like Expenses:Entertainment:Movies where Movies is under Entertainment and Entertainment is under Expenses. This allows you to have ledger report at various levels in the hierarchy so that you can see what you spend only on Movies or what you spend for all of your Entertainment.

Conventional top-level accounts are Equity, Liabilities, Assets, Expenses, and Income, but I only tend to use the last three myself. Assets are things I own that hold or are worth money, such as my bank accounts. Expenses are things I spend money on, such as food and housing. Income constitutes sources from which I obtain money, such as the salary I draw from my job or book royalty payments.

Transactions

An event in which an account accumulates a quantity, such as adding $36 to your Expenses:Auto:Gas account to represent when you topped off your car’s gas tank today, is known as a posting. Because ledger uses a double-entry accounting system, however, you also need a posting representing the source of the funds from which you obtained this $36, such as the Assets:Checking account representing the checking account you have at your bank.

A transaction is two or more postings representing a financial event, such as the above example of purchasing gas, where the amounts balance out to zero. In a journal file, a transaction is formatted like this:

; Comment
Date Description
    Account1  Amount1
    Account2  Amount2
    AccountN

If you don’t include an amount for the last account, ledger will automatically use whatever quantity causes the transaction to balance to zero. Most transactions involve two postings, so the second quantity will often be the same as the first but with the opposite sign (i.e. negative or positive). Here’s what a real world transaction might look like:

2006/10/15 McDonald's
    Expenses:Dining  $5.36
    Assets:Checking

In this instance, $5.36 is deducted (or debited) from the checking account and added (or credited) to the account for dining expenses. I often include things like initial posting dates (for which you can also use auxiliary dates) or transaction identifiers from paying bills in the transaction description (i.e. “McDonald’s” in the above example).

You may have a transaction where you’re spending money on several things that you want to track in separate accounts. Here’s an example of what that would look like:

2006/10/15 Exxon
    Expenses:Auto:Gas   $15.00
    Expenses:Cigarettes  $4.80
    Liabilities:MasterCard

Here, money is being spent on gas and cigarettes and the total of the two expenses, $19.80, is what’s debited from the credit card account.

If you’re like me, most of your transactions will only involve two postings, like the first example of an expense above. Another common type of posting represents when you receive income, which might look like this:

2006/10/15 Employer
    Assets:Checking  $1000.00
    Income:Salary

These may look a bit odd when they show up in ledger reports because the quantities will be negative since you’re debiting the amounts from them. This is normal and you’ll get used to seeing it appear this way.

When a transaction clears your account, you can denote this by adding an asterisk delimited by spaces between the transaction date and description like so:

2006/10/15 * McDonald's
    Expenses:Dining  $5.36
    Assets:Checking

One small potential pitfall: the segments of account names between colons can have spaces in them. As such, in order to denote the end of an account name, you should place at least two spaces between the account name and amount in each posting.

Reconciling accounts

I use a bank that offers online banking, including a web site and mobile app that allow me to view activity on my accounts almost any time. ledger may seem redundant in relation to something like this, but there are a few reasons why this isn’t so:

  • Transactions may not show up in the banking interface right away because some vendors often post several days’ transactions in a single batch every few days.
  • Transaction amounts may not be accurate. For example, initial postings from some gas stations may only show an amount of $1 and won’t reflect the correct amount until they clear. Initial postings from restaurants often don’t include any added gratuity.
  • Some activity may be fraudulent, which may not be immediately obvious if your card information is stolen in a business you frequent.

Every time I spend money and am able to get a receipt, I do so. I save them until they clear or, for larger purchases, until the period in which I may return the purchased item expires.

Tracking these receipts with ledger solves all of the above issues: I know about transactions that may not be reflected in my online account activity yet, I know when transaction amounts are inaccurate, and I can identity potentially fraudulent transactions when my online account activity shows a transaction for which I don’t have a receipt.

Every few days, I record any new receipts in my journal file, update any transactions that have cleared, and compare the journal file to my online account activity to ensure the two are consistent. This is a process called reconciliation.

Pro-tip: tracking cash withdrawals and purchases can be a pain. I typically just maintain an Expenses:Cash account for these sorts of things. If I can remember how I spent a bit of cash, great: I can just debit Expenses:Cash and credit the appropriate account for what I spent the cash on after the fact. Otherwise, I just leave the amount attributed to Expenses:Cash. It’s often not worth the trouble of trying to keep finer track of cash purchases than that.

Register

The register command in ledger displays all postings from a journal file that involve one or more specified accounts. I typically use this to ensure that my journal and online account activity are consistent by listing all activity for those accounts.

$ ledger reg checking -f stan.txt
08-Jan-01 Opening Balances Assets:Checking     $1550.00 $1550.00
08-Jan-01 New Seasons Assets:Checking           $-60.91 $1489.09
08-Jan-01 Panda Express Assets:Checking          $-7.24 $1481.85
08-Jan-02 Sizzle Pie Assets:Checking             $-7.38 $1474.47
08-Jan-03 Kettleman Bagels Assets:Checking       $-7.60 $1466.87
08-Jan-03 Mio Sushi Assets:Checking              $-5.76 $1461.11
08-Jan-03 Eddie's Flat Iron P.. Assets:Checking $-22.26 $1438.85
08-Jan-04 Food Carts Assets:Checking             $-7.24 $1431.61
08-Jan-05 Burnside Brewery Assets:Checking      $-11.76 $1419.85
08-Jan-05 Tastebud Assets:Checking              $-42.13 $1377.72
08-Jan-07 Salary Assets:Checking               $1084.00 $2461.72

In the above example of register command output, “reg” indicates that the register should be used, “checking” is part of the name of the account being queried, and the value following “-f” indicates the journal file to be read.

The last column in the command output is a running sum of all quantities from postings for that account, where that column’s value in the last row of output is the account balance. The register command is useful when the balances of journal and online accounts aren’t consistent and you need to find where a transaction is missing or has an incorrect amount.

The output of the register command can be limited by transaction date (as well as many other options) using either or both of its “–begin” and “–end” flags like so:

$ ledger reg --begin=2014/02/01 --end=2014/02/28 -f stan.txt

Balance

Speaking of balances, ledger also has a balance command. This outputs balances for accounts at each hierarchical level. This allows you to see, for example, numbers as general as your total Expenses and as specific as what you spent going to the Movies.

$ ledger bal expenses -f stan.txt
$157874.79 Expenses
$5212.85   Entertainment
$21526.95   Food
$1377.36     Breakfast
$3174.59     Dinner
$11171.71     Groceries
$5803.29     Lunch
$8568.00   Insurance
$3948.00     Car
$4620.00     Medical
$5136.40   Interest
$4618.79     Car
$517.61     Student
$33600.00   Rent
...
--------------------
0

Budgeting and Bills

ledger offers support for budgeting that can forecast when bills come due based on an interval and compare entered transactions against budgeted amounts to show whether you came over or under budget for any given time period. While this is a really cool feature, I don’t really use it the way it was intended to be used.

The budgeting feature uses what are called periodic transactions. These are slightly different from normal transactions in that they use a period expression rather than a date and have no description. They are formatted like so:

~ Monthly
    Expenses:Rent      $500.00
    Expenses:Food      $450.00
    Expenses:Auto:Gas  $120.00
    Expenses:Insurance $150.00
    Expenses:Phone     $125.00
    Expenses:Utilities $100.00
    Expenses:Movies     $50.00
    Assets

I keep blocks of these at the top of my journal, organized by the pay period in which I pay the bills they each contain. When I sit down to pay bills, I make a copy of the appropriate block at the bottom of my journal and comment it out. Then, as I pay each bill, I uncomment the appropriate posting and move it out into an actual transaction. This gives me a way to easily check which bills haven’t been paid yet (e.g. if I’m waiting on a paper bill for the exact amount I owe).

I generally use vim to edit my journal files. There’s a contributed plugin for adding ledger format syntax highlighting, which is nice. I also use my fork of the visSum plugin for vim (the fork adds support for decimal quantities) to visually highlight and sum remaining bill amounts. I can compare the output of that with the balance of my account (from ledger’s register or balance commands) to determine how much I actually have left in excess of bills.

Benefits

Even though I’m only using a very small amount of ledger’s overall feature set, I’m gaining several benefits by putting in the time to maintain these journal files:

  • Peace of mind in knowing that I know where my money is and where it’s going, despite whatever records my online banking interface may yet be lacking.
  • Information I can use to forecast future financial events, such as how much I’ll spend on electricity to keep my house at a comfortable temperature during the summer and winter, how much I spend on average for gas and groceries, or how much I spend on sporadic luxuries like eating out.
  • At tax time, I can very quickly and easily provide exact figures to my accountant for business-related expenses without having to take time to compile them manually.

Some people have asked me what I think of services like Mint. While such services may offer a nice interface, those interfaces are often intentionally kept very simple, to the point where I’m limited in the ways I can report on my data in their system. Additionally, there’s rarely a way for me to easily get that same data out of their system and into a format I can use elsewhere. In short, I like having control of my data and what I can do with it. These services may work for others, but they just don’t suit me.

Hopefully this blog post has given you some perspective on the benefits of accounting with ledger and how you can go about adopting this approach yourself if that prospect entices you. Feel free to leave a comment if you have a question or would like to discuss the topic further with me.

Travis and Composer and virtPHP, oh my!

I recently ran into an issue with one of my repos on GitHub when integrating it with Travis. When I installed dependencies with Composer and ran the PHPUnit tests on my local system running Ubuntu 13.10 and its stock PHP 5.5.3 apt package, they passed. However, I’d configured Travis to also do this under current 5.3 and 5.4 versions as well.

In the first build, everything worked fine under 5.4 and 5.5, but upon getting to the composer install instruction to install project dependencies and PHPUnit, the job for 5.3 failed with some rather unintuitive output from Composer that implied it didn’t recognize the platform package requirement that I’d provided for the minimum PHP version.

Your requirements could not be resolved to an installable set of packages.
Problem 1
- The requested package php could not be found in any version, there may be a typo in the package name.

Side note: While Travis does support Composer, the version of it available by default when running a job is frequently behind the current build. I’ve brought this up with them, but it doesn’t seem they’ve addressed it as of this writing. In any case, it’s easy enough to work around by including a composer self-update instruction as part of the build like so. This ensures that you won’t be affected by any recently fixed bugs in Composer.

Since the cause of my issue wasn’t immediately obvious from Composer’s output, my first thought was that I needed to begin my attempt at troubleshooting the issue by replicating it on my local machine. My second thought was that seemed like an abysmally miserable prospect, as it would require that I have several different versions of PHP installed other than the current one on my system.

I’d heard recently about a new project recently via Twitter called virtPHP that purported to be PHP’s answer to virtualenv for Python or rvm for Ruby. Thinking that my situation seemed a great use case for it, I proceeded to install it.

First, you have to read a bit past the cursory installation instructions on the landing page of virtPHP’s web site, particularly the “Using phpenv and php-build” section of virtPHP’s README file including the portion on package requirements. virtPHP doesn’t accomplish this great feat all on its own. It actually builds on two other existing projects by Christoph Hochstrasser, phpenv and php-build, and functions (in a rather PHP-like vein) more like glue to make working with these projects and managing what they produce easier. More specifically, it provides support for things like differing per-project PHP, PECL, and PEAR configurations.

In reality, all I ended up needing for what eventually proved to be a rather quick-and-dirty sort-of use case was phpenv and php-build alone, though I suspect virtPHP will be indispensable when I inevitably need a more long-term setup like this. Installing all three based on the installation instructions in their README files was fairly straightforward. I used them to create three PHP installations of the versions used on Travis (5.3.27, 5.4.25, and 5.5.9 as of this writing) and to quickly switch between them to re-run the composer install command that had failed on Travis, which consistently failed under 5.3 and worked under 5.4 and 5.5 on my local system.

Eventually, I opened the composer.json file and realized the problem: I’d misrecalled the minimum PHP version I’d set for my project to be installed as 5.3 when I’d actually set it to 5.4. Composer appropriately, though perhaps not intuitively, reacted by outputting errors when the local environment was running 5.3, a PHP version that did not meet the requirement I’d set in composer.json. In poking around, I found that this sort of user error is not entirely uncommon. Once I changed the requirement to 5.3 and pushed it to GitHub, the next Travis build succeeded for all PHP versions I’d specified.

So, thanks to the folks behind virtPHP for producing this project. I suspect I’ll be making more use of it in the future. :)

Sunshine PHP 2014

Due to uncertainties in my work schedule, I decided this year not to submit to the Sunshine PHP 2014 conference. However, the schedule turned out such that I was able to attend the conference. Many thanks to my awesome employer Blopboard for providing the time and funding to make this possible.

I was a speaker at the inaugural Sunshine PHP conference in 2013 and enjoyed that experience, but being able to just be an attendee this year was a nice change of pace. I’ve enjoyed the awesome content presented by excellent speakers.

With this year’s Sunshine PHP came a new member of the elePHPant family: Sonny, the yellow elePHPant. The process of obtaining your very own Sonny was a rather novel idea thought up by the hosts of Sunshine PHP. Attendees were given a bingo sheet where each space was branded for a sponsor and would visit the sponsor’s booth to get that space stamped. Once all spaces were stamped, you could turn in the bingo sheet to get Sonny.

In going through this process, I spoke with some very friendly guys at AppDynamics. I was able to learn more about their product, which is an alternative to the New Relic service I currently use at work for monitoring the performance of our product. I noted that AppDynamics isn’t currently listed in the Heroku add-on marketplace, but they clarified for me that it can still be installed on Heroku and pointed out related documentation.

The interaction was great and I’ll certainly be checking out the product further, but this quest to get Sonny is what instigated that conversation, which I think is awesome. Many thanks to Zend for sponsoring this fun activity within the conference.

Thanks to everyone who made Sunshine PHP a spectacular event to attend. I hope to see you again next year.

Sonny the yellow elePHPant