Many teams benefit from setting an expected coding standard. With this comes an array of benefits which help ongoing development of projects, such as:
- Ease of maintenance
- Avoid wheel re-invention
- IDE integrations
- Bug reduction
- ISO certifcation support
But as we're here to talk about how Selesti handles them, I wont go into detail (hopefuly you're already sold on the idea of them!) but below is a small guide to getting started with implementing your standards of choice using IDE integrations and GIT Hooks.
We typically have 4 points of checking (sometimes we don't use them all — we make this decision based on the project), and this is pretty consistent across all the languages we use. These are:
- Task Runners (Gulp)
- Text Editor / IDE
- GIT Hooks
- CI / Deployment System
To start with, our task running, IDE and GIT hooks all use the eslint cli. To install this you'll need node/npm set up on your machine with the node_modules linked to your PATH correctly.
If you do not have eslint already installed (try typing `eslint` into your terminal and see what happens), simply run `npm install eslint -g` and you should see it starting to install!
Once you've done that you should be able to type `eslint` and it will wait for input from you. You can just cancel that as it's now set up, and you're ready to start using it as a part of your development process.
The first method of integration we'll look at is IDE. This does require all your team to be on board with using IDEs with plugins, but if they choose not to then they'll need to make sure their GIT Hooks are set up :) or the CI is set up!
The 2 IDEs we'll be looking at are Sublime 3 and Atom.
ESLint with Atom
Visit the webpage https://atom.io/packages/linter-eslint and it will give you some basic commands on how to install it and configure it. Once it's installed you can view the Packages section of Atom and configure it a little more.
We typically base our rule set off the eslint recommended set, with some very minor rule tweaks, so we create a ".eslintrc.yml" with the following content.
*note* With ESLint:Recommended, it only enables default "possible error prevention, best practice and variables" and if you want to use their defaults for the rest, you need to enable them individually, using the defaults, which is how you end up with a similar config to ours.
You can of course tweak these, but as a whole the defaults for eslint are near identical to PHPs PSR-1 and PSR-2 so we stick to them to make it easier to get used to one style.
Once we've got our config in place, we register it within the `package.json` - it's not compulsory to do this, but the hint helps plugins a bit better! We simply add (if you do not have a package.json, you can create one by typing `npm init` and following the instructions):
A crude example can be seen below.
ESLint with Sublime
The steps to getting Sublime set up are almost identical: make sure your rule file is set up, and that it's registered. The main difference is the plugin that you'll be using. Firstly you'll need to make sure you have the "SublimeLinter" framework installed, you can read how to install it http://sublimelinter.readthedocs.io/en/latest/installation.html it should take no more than 5 minutes!
Once that is set up you can start installing linters! We'll be using https://github.com/roadhump/SublimeLinter-eslint and you can follow the instructions here. If you're comfortable with Package Manager, you can just search eslint and pick the SublimeLinter3 package.
Again, you should be ready to go. Sublime is not as pretty as Atom, but still gives you the same information. You get a little marker and an explanation in the status bar:
So it's all good and well your team using IDE plugins, but what happens if they ignore them? Or they choose not to use them? You still do not want incorrect code pushed to your repos — and this is why we get the GIT Hooks involved.
The first part of this will assume you have a composer project set up on a non-Windows based machine, however if you do not then the setup will be a little more manual.
If you happen to have Linux/OSX and composer you can set up a script within your `composer.json` that looks similar to this:
This means when we run `composer githooks` later it will link your project-specific hooks into the git repo hook folder.
If you're not using composer but are on OSX, you can just run the commands above manually once the hooks have been created.
If you're on Windows, then you can either find out how to symlink them yourself or just manually copy them into `project/.git/hooks
Moving on! So the hook itself gets built up over time, and will have more than this in it, but at a minimum it will start to look similar to this.
This is what your hook file might start to look like in a minute.
What this will do is: if the command within the hook is run and it returns an exit code then we know it failed and a violation has been made.
So to get this working we need to create a folder called "git-hooks" within the project and add a file called `pre-push` and to make sure it's executable `chmod +x pre-push` with the above content in it, you'll need to adjust the paths to where your files are stored.
The reason we dont use GIT Templates is because the projects are so different that it would not make sense, so this way the developer can see the hook folder and can install them the best way for their system.
To verify it is working you can run `./git-hooks/pre-push` from your project root. If not a lot happens, then you're good! Otherwise it will say it failed, and you can then run the command it suggests to see the output (the reason we pass it to /dev/null is because some developers use SourceTree which crashes when a large output is present, so we mute it until it's needed). There is also a note at the bottom of this post for a "fix" if you use sourcetree which has PATH issues.
When you try and push, if everything went to plan, you should get an error (assuming your code has errors of course!)
Once you're happy that it's working as expected, you'll be able to start adding other languages. Next up is our SCSS set up!
To start with make sure you have both `node-sass` and `sass-lint` installed. If you do not then run `npm install node-sass sass-lint -g` then try running `sass-lint` on your terminal.
Very similar to the ESLint set up, we'll need to create a `.sass-lint.yml` file which will store our rules, and we'll need to register the file within our `package.json` using
Once it's registered you can add your rule set. The config we use is pretty default, but we tweak the tab length to 4, nest depth to 5, and ordering to smacss. You can copy this config and try it out.
Now you've got a rule set in place, you can start to validate against it!
SASS Lint with Atom
SASS Lint with Sublime
Same as before (notice a pattern?) Install https://github.com/skovhus/SublimeLinter-contrib-sass-lint
If you've jumped here, you'll need to follow the initial git hooks setup first, so open up your existing (or new) `pre-push` file and add the following (this is a little different due to the way sass-lint works) — remember to update the path to your project scss files
Hopefuly this is all starting to make sense now, and you can see there is a general pattern emerging,
That being said, the final steps I've simplified. However there are 2 sections to how we handle our PHP — we check both against PHPs built in linter for syntax issues, and we also test the code styling against PSR1/2, so I'll split them out.
I'll go over PHP Linting first, before code styling.
PHP Lint with Atom
PHP Lint with Sublime
*note* Once these are installed, there is no guarantee it will work out of the box. First you'll need make sure the version of PHP you have installed on your machine is newer than php 5.4. If it's not, then I recommend you download a copy for your OS and store it somewhere.
*note 2* You need to make sure you have the PATH to your php bin. If your environment is setup nicely and you can access `php -v`from the terminal, you're safe! Otherwise you'll need to find where the binary for the PHP install is and either add it to your PATH or hard code it in your IDE. If you do not have the PHP install in your PATH then if you adjust the settings in the plugin of choice to where it is stored, you should be able to run it.
Continuing inside the `pre-push` hook we've been using, we'll add a new section with the following (change the path you want to scan):
You can test it out by doing something like removing a `;` from your code and running `./git-hooks/pre-push` and all should be good!
PHP Code Styling
The last thing is to ensure the code styling adhears to PSR1/2 .
For a super simple basic introduction to PSR, it stands for "Proposed Standard Recommendations" and gets collaboratively drafted by the community and those around the PHP-FIG who then agree and release it. You can read more about PHP-FIG on their website: http://www.php-fig.org/
There's not much to them, it's mainly things like conventions for naming methods and brace positioning.
Now that you've obviously memorised the standards, we'll start our familiar steps again:
PHPCS for Atom
PHPCS for Sublime
One of the differences here is the way you install PHPCS, which is a php library called CodeSniffer. You can read more about it: https://github.com/squizlabs/PHP_CodeSniffer
You'll need to pick a method of installing if you do not already have it.
You can see if its globally installed by typing `phpcs` or locally installed by`./vendor/bin/phpcs` and if it starts to take input then it's working!
You might find it easiest to install it globally by first installing Composer on your system, then making sure the global binary path is set up. This should include something like `$HOME/.composer/vendor/bin`
Once you're satisfied that your PATH is set up correctly, you can install PHPCS by running `composer global require "squizlabs/php_codesniffer=*"`then running `phpcs` again. If it still cant find it, try a fresh terminal session, and if that fails go back to making sure your PATH is set up correctly :)
Additionally if you're using composer on your project anyway, you can just include it in your project by running `composer require "squizlabs/php_codesniffer=*` then you should get the local version installed. If you're having trouble with your PATH this might be the best way to go.
Once it's all working and you can run phpcs, you can set up the hook in the same `pre-push` folder, remembering to change the paths:
As you can see we're running a local version of phpcs. This is because occasionally we run this on a CI like DeployBot, so having all the dependencies bundled with the project helps!
So now everything should be set up and working a treat, you can run the scripts on demand by doing `./git-hooks/pre-push` in your terminal, or by setting up a composer script.
So the theory now is, that developers in your team will be able to get visual feedback from their IDE regarding potential errors so they can fix them as they work, then the GIT Hooks will prevent code violations being pushed to your central repo.
- Why not use Gulp/Grunt to check?
- You can! In fact we do for certain projects, however over time as a project grows, we've noticed that the task runners slow down by having lots of tasks, so by putting the usage into the IDE instead, it keeps our sass/js/php compiling tasks fast and lean!
- Why use "pre-push" and not "pre-commit"
- You can! But the reason we don't is that often developers are commiting to keep a logged history of work, and when they're under pressure having pristine commits can be tricky, and having a fairly slow set of scripts running on every commit can be a pain, so by moving it to the "pre-push" we give the developers a chance to commit as much as they like, before pushing to the main repo
- Why not check using your CI?
- You can! But we do not as by that time, the code shared is already poluted, then other developers might pull it and get issues which they have to fix for their deployment etc, so by catching it before it's too late we keep things speedy for everybody.
As with any project, you'll get niche things you'll want to run, however if you're using composer we've got some generic scripts which are very handy to run on demand! You can drop this in with your scripts if you use composer — just update the paths and any dependencies.
Additionally if you want to add some colour and fancy styling to your hook, you can view our finished hook just below in all its colourful glory!
Sourcetree has an annoying bug where it sets its own PATH, so things like your node modules or composer packages might not be detected. To counteract this we have a custom bash profile which sets up all our paths correctly. We call this `.selesti_profile` and it's placed in the home directory. Then at the top of our GIT Hooks we have a custom snippet which loads this file, and it fixes the PATHS for us by setting them up manually:
Hopefuly this has given you some inspiration as to how your team can implement some simple coding standards, but remember to pick the standard/style that works best for your team. If this means that you have three different projects, and they need to use three different standards, that's fine — as long as each project sticks to one style.
If you've got any suggestions for ways to improve this flow, drop us a line at [email protected]