I make extensive use of Laravel Debugbar to track performance of parts of my application. I sprinkle calls to Debugbar::startMeasure and Debugbar::stopMeasure to track the duration of certain segments of my code. However, when this code goes into production, this dependency isn't present. This cause the code to break since it cannot find Debugbar anymore.

To solve this issue, I thought I would create a dummy Debugbar class and have it added as an alias, so that any code depending on Debugbar would still work, but end up as a "no operation". I found the article Dynamic class aliases in package which introduced the necessary piece of information to accomplish this.

<?php

use Illuminate\Foundation\AliasLoader;
use My\SuperPackage\FooBar;

class ServiceProvider extends \Illuminate\Support\ServiceProvider
{
    public function register()
    {
        $this->app->booting(function() {
            $loader = AliasLoader::getInstance();
            $loader->alias('FooBar', FooBar::class);
        });
    }
}

In my desired use case, I simply implemented the following changes:

In app/Providers/DebugbarServiceProvider.php (a new file)

<?php

namespace App\Providers;

use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\ServiceProvider;

class DebugbarServiceProvider extends ServiceProvider
{
    public function register()
    {
        if (!class_exists('Debugbar')) {
            $loader = AliasLoader::getInstance();
            $loader->alias('Debugbar', NullDebugbar::class);
        }
    }
}

class NullDebugbar
{
    public static function __callStatic(string $name, array $arguments)
    {
        // Do nothing
    }
}

In app/config/app.php

    // under the 'providers' key, add
    'providers' => [
        [...]
        // This will take care of loading the service provider defined above
        App\Providers\DebugbarServiceProvider::class,
    ],

With those two changes, it is now possible to make use of Debugbar in most places and have it work even without the Laravel Debugbar dependency installed.

04 Feb 2020

Fighting over code style

History / Edit / PDF / EPUB / BIB / 2 min read (~277 words)

Why do developers fight over code style?

We are creatures of habits. We like when our code looks like we would expect it to look and not some completely different style. When the style is too different, then it creates cognitive load, which means that we're spending more energy than we would if the code looked the way we like it. Since we're machines that attempt to minimize the amount of energy we spend, we see code that is not styled our way as a bad investment of our energy and that it would either be better to reformat the code our way (minimizing our energy expenditure in the future) or simply to start from scratch.

As human beings, we're able to adapt. Adapting generally requires more energy than simply using the skills we already have, and we prefer to avoid having to adapt. Thus we fight with others so that they do the effort of adapting instead of us. We see fighting as being more effective than adapting. It may be an effective approach when no existing rules exist, however, in many businesses, code standards have been established, which means that if you are a new employee, you will have to adapt to those standards. You could always try to bring back the discussion of updating the code style, but if the standards have been established a long time ago, this effort is likely to be futile.

As such, even though adapting requires more of our energy, we should make that sacrifice upfront and use it on more important things, such as defining what tasks are important and which ones should be done first.

20 Dec 2019

Python profiling

History / Edit / PDF / EPUB / BIB / 1 min read (~66 words)

Run your program with python -m cProfile -o profile.cprofile my-script.py

Install snakeviz (pip install snakeviz) to visualize the generated profile.

snakeviz profile.cprofile

Alternative approach

Install pyprof2calltree to convert the cprofile to a kcachegrind compatible profile.

pyprof2calltree -i profile.cprofile -o callgrind.profile.cprofile

26 May 2018

Learning VS Code source

History / Edit / PDF / EPUB / BIB / 7 min read (~1305 words)

  • Read package.json to discover what packages VS Code depends on
  • Observe the root directory structure, and more specifically the extensions and src directories which contain the bulk of the source code
    • A lot of the code in the extensions directory appears to be dedicated to programming language support
      • The remainder of the extensions seem to provide functionality for things that aren't "core" to vscode, such as configuration-editing, emmet, extension-editing and some color themes
  • If you look at the .vscode/launch.json, you will find all the tasks that can be executed from within VS Code debugger. One task of interest is Launch VS Code which will take care of launching VS Code for us so that we may debug it
    • In this file you will also discover that it runs ${workspaceFolder}/scripts/code.bat, which is the next script we'll take a look at
  • In ./scripts/code.bat, we discover that this script will run yarn if the node_modules directory is missing, download the electron binaries if necessary and call gulp compile if the out directory is missing, then finally start the electron/vs code binary in the .build/electron directory
  • We then start to look for common entry points file such as index.ts/js or main.ts/js, for which we find a match in the src directory
  • We take a quick look around, trying to find where electron is likely to be instantiated... There's a lot of code in src/main.js that would be better elsewhere to make it easier to navigate this file
  • Close to the bottom of the file we discover the code we are interested in as a call to app.once('ready', ...)
    • Once the app is ready, we want to call src/bootstrap-amd and pass vs/code/electron-main/main as our entry point (per the signature of the exported function in ./src/bootstrap-amd)
      • Here we can go to two places, either src/bootstrap-amd or src/vs/code/electron-main/main
        • We take a quick peek at both files and we can quickly tell that src/bootstrap-amd is used mainly to load src/vs/code/electron-main/main which is the file we're going to be interested in
  • Once again, we quickly look around src/vs/code/electron-main/main and find that the main logic is at the bottom of the file
  • First the command line arguments are parsed
  • Then services are bootstrapped/instantiated
  • Finally the CodeApplication is started up
  • This leads us to look into src/vs/code/electron-main/app.ts
  • As the file is quite large, we start by skimming through it, looking at the available methods on the CodeApplication class as well as its properties
  • Looking at the constructor, we can see that a lot of objects are given to it. We also observe the use of the @... syntax (those are decorators)
    • In this case (and for most constructors), this is how VS Code does service (dependencies) injection
  • One will also notice that most, if not all parameters have a visibility assigned to it. What this does is that it will create an associated property in the class as well as assigning the parameter value to this property in the constructor. Thus, instead of writing

    
    class AnotherClass {
    private someClass: SomeClass;
    
    constructor(someClass: SomeClass) {
        this.someClass = someClass;
    }
    }
    

    you simply write

    
    class AnotherClass {
    constructor(private someClass: SomeClass) {
    }
    }
    
  • Upon its creation, the CodeApplication class will register various event listeners on the electron app object
  • If we remember, in src/vs/code/electron-main/main, after the CodeApplication object is instantiated, we call startup() on it. So, we want to take a look at what that method does
  • Without knowing too much about the VS Code source, it appears that we are instantiating an IPC server (inter-process communication) and then the shared process
  • After that is done, we initialize some more services in CodeApplication::initServices, such as the update service (which I guess takes care of checking for VS Code updates) and the telemetry (data about VS Code feature usage)
  • We finally get to the point where we're about to open a window in CodeApplication::openFirstWindow!
    • This leads us to go read the class WindowsManager in src/vs/code/electron-main/windows.ts. Once again, this file is pretty large, so we want to skim it to see what it contains (functions, classes, properties, methods)
  • There are a few large classes in src/vs/code/electron-main/windows.ts that I'd want to extract to make the file smaller and simpler (less cognitive load). However, the issue is that those classes are not declared as exported, and thus are only available in the local file. It would be possible to move these classes to other files and import them, but by doing so it would also "communicate" that others can use it, which is what having the classes as not exported prevents, at the cost of making single files larger and harder to comprehend
  • We know that the constructor is first called, then from CodeApplication::openFirstWindow, we see that WindowsManager::ready and WindowsManager::open are both called.
    • In the constructor we instantiate the Dialogs class (takes care of open/save dialog windows) and the WorkspacesManager class (takes care of workspace management, such as open/save)
    • In ready event listeners are registered
    • In open there is a lot of logic associated with the window finally opening

  • If you start VS Code using the debug feature, you will not be able to open the Chrome DevTools (at this moment, 2018-05-26) because only 1 process is allowed to attach to the Chrome DevTools instance, and that process is the VS Code editor that started the debugged VS Code instance

Today I want to find out how VS Code restores a windows sessions when you start it. Apparently, if you run it as code ., it will not restore the same set of windows than if you called it simply with code.

  • In src/vs/code/electron-main/launch.ts, the LaunchService::startOpenWindow appears to implement logic based on how many arguments were given. In all cases, we end up doing a call to the IWindowsMainService::open method.
    • Note that in both cases, the path we're opening is within the args variable, which is passed to the cli property of the IOpenConfiguration object.
  • The implementation of IWindowsMainService we are interested in lives in src/vs/code/electron-main/windows.ts.
  • In the WindowsManager::open method, we rapidly discover that the windows that will be opened will be retrieved in WindowsManager::getPathsToOpen. In there, we can observe that the windows that will be opened depend on whether something was passed from the API, we forced an empty window, we're extracting paths from the cli or we should restore from the previous session.
    • If we arrive at this last case, we can see that the logic is to call WindowsManager::doGetWindowsFromLastSession, which is pretty self-explanatory, and will retrieve the previous set of windows from the last session. This is what happens when you start code using code
    • In the case where we pass a path, this path is in openConfig.cli._. In this case, the windows that were previously opened, and part of this.windowsState.openedWindows (where this is a WindowsManager object)
      • Here we wonder how the windowsState.openedWindows state gets restored on VS Code start. To figure that out, we start at the WindowsManager.constructor method. There we find this.windowsState = this.stateService.getItem<IWindowsState>(WindowsManager.windowsStateStorageKey) || { openedWindows: [] };, which states to use get a IWindowState object from the stateService if one exists or to create an object with no opened windows. If we assume that this windows state is the same regardless of how we start VS Code, then it is not there that the difference in opened windows will occur.
01 Mar 2015

PHP Startup Internals

History / Edit / PDF / EPUB / BIB / 6 min read (~1021 words)
php startup internals
  • PHP
  • MySQL
  • Jenkins
  • Apache/Nginx
  • Linux (Ubuntu)
  • node.js/io.js

My goal with this post (and any subsequent posts) is to share my thoughts and current practices on the topic of developing PHP applications in a startup environment.

Starting a new startup means making decisions. Which framework to choose, what tool to use, which programming language, what task should be done before this other task, etc.

Starting is often overwhelming. What should be done first? If we ignore all the questions about the business (what sector? any specific niche? what sort of product?), then the first thing that an individual or a team should aim for is to prepare for iteration.

Many would start by working directly on their first project. It makes sense since it is the primary goal of your startup to produce results. However, writing code without establishing some sort of workflow framework will be inefficient.

My first step is generally to setup Jenkins, a continuous integration tool. It allows me to setup automated testing and automated deployment to a development/staging area/environment. This is useful for two purposes:

  1. Having an external "party" execute the test in their own environment (separate from mine). This validates that whatever is in source control will work on someone else computer.
  2. It deploys automatically "stable" (in the sense that they pass testing) version to an online facing server. With automated deployment, it is possible for me to keep on writing code, have it tested and then deployed to a server where I can ask others to take a look at and provide feedback.

There are a couple of way to get setup.

Everything will be setup on the same machine. Here is how it basically goes:

  1. Install jenkins
  2. Create two jenkins jobs, project-name-develop which takes care of building the develop branch of your repository and run the tests (basic continuous integration), and project-name-develop-to-development, which will again, build the develop branch of your repository but this time for the purpose of having it available online.

There won't be much to discuss here except a list of plugins that are almost mandatory (either because they make jenkins much more useful or allow you to more quickly diagnose issues).

  • AnsiColor
  • Checkstyle Plug-in
  • Clover PHP plugin
  • Credentials Plugin
  • Duplicate Code Scanner Plug-in
  • GIT client plugin
  • GIT plugin
  • HTML Publisher plugin
  • JDepend Plugin
  • JUnit Plugin
  • Mailer Plugin
  • Matrix Authorization Strategy Plugin
  • Matrix Project Plugin
  • Node and Label parameter plugin
  • Parameterized Trigger plugin
  • Plot plugin
  • PMD Plug-in
  • Self-Organizing Swarm Plug-in Modules
  • Slack Notification Plugin
  • SSH Credentials Plugin
  • SSH Slaves plugin
  • Static Analysis Utilities
  • Throttle Concurrent Builds Plug-in
  • Timestamper
  • Violations plugin
  • xUnit plugin

I'll now go into more details as to what each does.

  1. Pull the latest revision from the repository
  2. Download and update composer (if required)
  3. Install dependencies
    1. bower install
    2. npm install
    3. composer install
  4. Build assets to validate they compile
    1. Compile LESS into CSS
    2. Concatenate and minify JS
  5. Prepare the application environment
    1. Migrate database
    2. Seed database
  6. Run continuous integration tools to assert code quality
    1. phpunit
    2. phploc
    3. pdepend
    4. phpmd
    5. phpcs
    6. phpcpd

An iterative cycle here should take less than 5 minutes (and a maximum of 30 minutes). The goal is to quickly know after pushing changes to your repository that nothing is broken.

For this to work, you simply need to make a symbolic link from the jenkins project workspace to some path which apache/nginx makes available to external users. For example

/home/jenkins/workspace/project-a-develop-to-development/public -> /var/www/development/project-a

  1. Pull the latest revision from the repository
  2. Download and update composer (if required)
  3. Install dependencies
    1. bower install
    2. npm install
    3. composer install
  4. Build/Prepare website
    1. Compile LESS into CSS
    2. Concatenate and minify JS
  5. Prepare the application environment
    1. Migrate database
    2. Seed database

An iterative cycle here should take less than 5 minutes. Anything that takes longer than that would be suspicious.

Now that you have both projects setup, here's how things work. First, project-name-develop is triggered every 1-5 minutes and checks the repository for changes. If changes are detected, a build starts and will verify that the current state of the code is valid.

Once the build finishes, if it is successful, projecy-name-develop-to-development will start (triggered on project-name-develop success). It will deploy the stable code so that users may test it.

A whole change cycle will generally take from 1 to 30 minutes depending on how many tests you have and how well you've been able to optimize your jenkins build workflow.

Here's a list of things to try/check:

  • If you are running phpunit with code coverage, disable it and run it in a separate jenkins project. Code coverage is 2-5x slower than without it. When you are running the tests, you want to know the results fast and code coverage should not be a priority. Speed is the priority.
  • If you are running tests against a database and the tests requires setting up and tearing down the database (either just truncating the tables or full DROP tables), search for ways to avoid hitting the database or how to improve performance. For example, if you are testing using SQLite, run an initial database migration and seeding and copy the resulting .sqlite file so that it can be copied on test setup instead of migrating/seeding every time.
  • If migrating/seeding takes a long time, keep the resulting .sqlite file and only rebuild it if its source files (dependencies) have changed. On a project, you will run tests much more often than you will be rebuilding the .sqlite file, so it is worth investing in developing such a tool.
  • Since php is single threaded, look for tools that will enable you to do multi-process php testing. An example of such tool is liuggio/fastest. Depending on the number of processors/cores you have available, you could see a 4-8x gain in speed.
  • If you have the money/hardware, distribute testing over many machines. If you want a unified phpunit code coverage/results, you can use phpcov to merge separate test results into a single result file.