In the previous issue we discussed using the right tools to more easily debug your Web development scripts.
Now these tools can be made even more useful if they are configured in a way that makes the developer’s life easier.
2. Configuring your environment for better productivity
If you don’t make yourself at home in your own code base, who will?
Configuring your environment can mean many things, but the points I would like to cover in this post are:
- Setting up your editor / subversion / server so that you can get through the day in the most painless way
- Creating a development environment that works alongside your production
- Writing your code so that if something goes wrong you can easily pinpoint the cause and quickly fix it
Setting up editor / server & co
When you start working on a project, you often want to start small and avoid wasting massive investments to organise your code. Now, once you’ve done it a few times, you’ll realize that settings up a clean and comfy environment doesn’t take that much effort, and really pays off in the long run.
By that I mean the following:
On the editor
- Making sure your editor is the right one for the language you use, and is extendible. This means it allows you to define keyboard shortcuts for the kind of things you often do. I like creating shortcuts for the following stuff:
- firing up a
svn diff
orsvn commit
command. Most of the time it’s just to figure out if I’ve changed the file at all, sometimes it’s to do an actual commit - opening the browser at a given location
- bookmarks for often-used config files (e.g. the apache ini)
- firing up a
On the server
A common practice with beginners using a webserver is to put all their projects under a single root, so they can then get pages at
http://localhost/project1
(which will point to c:\bla\bla\root\project1
)
http://localhost/project2
(which will point to c:\bla\bla\root\project2
)
Now, by tweaking some config, you can achieve a much more symmetric setup, where your 2 projects will be hosted on the root of some (virtual) server. In order to do so, do the 2 following things:
- Add as many entries as you like in your hosts files (see Wikipedia), of the following form
# all these names point to your localhost # but Apache will see the difference # due to the VirtualHosts directive 127.0.0.1 project1 127.0.0.1 project2
- Add virtual hosts in your Apache config, like this
DocumentRoot "c:\bla\bla\root\project1" ServerName project1
The result of that is the ability to get the website (from your computer that is!) at an address like
http://project1/
I know – in theory it shouldn’t matter whether your pages are at the root of your server or not! However in practice it is a source of so much pain and wasted time when your local setup runs on a sub-folder of the root and your production setup runs on the root, and some things do not work as expected on your production server. Life’s too short to try and make it work (and some of the frameworks are just rubbish at working outside of the root of a server and you do not plan to fix them).
In the database
Not that I am doing it routinely, but some cool database features can be leveraged to make your life easier:
- Views: these are queries that you can use as if they were a table. So for instance, if you’ve got a query like this
SELECT user_id, user_name FROM users WHERE user_type = 'admin'
Then you would create a view by doing this
CREATE VIEW admins AS SELECT user_id, user_name FROM users WHERE user_type = 'admin'
Subsequently, you can then do
SELECT user_name FROM admins
This can be useful when you are debugging and don’t want to endlessly retype the same WHERE
clauses.
- Triggers: never used these, but they look pretty powerful. They allow you to have cascading effects in your tables, or prevent you from doing operations which would violate relationships (e.g. preventing you from deleting a user in the users table if the posts table still has entries linked to that user)
In your system
Create scripts to perform standard tasks. I personally think that people who write batch / unix scripts are masochists, and so I do it in python much more easily. That includes
- Issuing ssh commands to a remote server (e.g.
svn update
) - Tranfering files through SCP
- Creating a dump of your mysql database using
mysqldump
- Going to some of your favorites directories
Creating a development environment
For some people, a development environment is something they are not even aware of and which consists of a series of commented print
(PHP) or console.log
(Javascript) statements scattered randomly in their code, and which will be uncommented when needed – and sometimes accidentally pushed to production with unpredictable consequences…
Any serious framework will consider the development environment an integral part of the project, and provide an API that will allow the developper to leave trails of what is happening. At the same time it is important that the user does not see any of this, be it for better customer experience or sometimes as a security precaution (i.e. avoiding to give the user insights in the server-side code). This can happen by having the notion of environment at the API level. This means that
- At the root of your code (the HTML page for Javascript, your controller for PHP), there needs to be an assesment of what the current environment is, i.e. ‘development’, ‘testing’, or ‘production’. This can be done by some environment variable, some local file, can be based on the hostname (or the virtual host – even better!), or perhaps by some cookie on the user’s browser.
if ( /*... */ ) $ENVIRONMENT = 'production' if ( /* ... */ ) $ENVIRONMENT = 'development'
- Any setting that has reasons to vary depending on the environment should be predicated on the environment. So, for instance, the MySQL database could be a function of the environment, for instance like this
$db['production']['database'] = 'projectdb_prod'; $db['dev']['database'] = 'projectdb_dev';
And the subsequent calls will be like this
$server = $db[ $ENVIRONMENT ]['database']
A golden rule – A SINGLE CODEBASE
The ‘single codebase’ rule means that you do not want to have different versions of the same file depending on the server. This would be difficult to maintain / deploy (not least because it would have to be outside of your control version system), and soon or later you are going to accidentally overwrite the config of one server onto another and scratch your head to understand the source of a bug. Instead, you want all the settings to be in the common codebase, and ensure that the choices are done on-the-fly depending on the environment / host / OS.
Writing your code so it is debuggable
Separation of concerns
Modularity, for example as in MVC frameworks can dramatically improve the debuggability of your code. This is because the business logic will be testable independently of the GUI (which tends to be tough to test).
Hard to give precise guidelines, but let’s say that the rule of thumb is to make it so that you can test key features of your application with one-liners and without having to use the user interface.
Using configuration settings or even bits of code that can be changed at runtime
A technique I have found useful, which is more related to fine-tuning the Javascript part of your application than debugging it, is that of using configuration settings.
For instance, in an app I am developping, I need to parametrize many settings so that some graphics looks as good as possible.
Previously my code was looking a bit like this
some_setting = 0.5 some_other_setting = 25 timestep = 0.25 some_curve = timestep * some_setting + x * some_other_setting + /* .. */
This meant that, in order to test changes to any of these settings (say, move some_setting
to 0.6), I needed to reload my page. Given that I am now convinced that one-page (javascript) apps are the future of the web, I end up with a page whose initialization can take up to 10 seconds. Given the features, this is acceptable for the end-user, but for debugging purposes, it is a bit of a pain.
The idea I came up with (well this must be a design pattern – I just don’t know how it’s called) was to use a global function to get and set settings, and attach a callback that gets triggered every time the settings are changed.
This broadly worked as follows.
In a library, I would have
// ideally this first line should be in a project specific library whilst // the rest is totally generic function DefaultSettings() { return { 'SOME_SETTING' : 0.5 /* ... */ } } current = DefaultSettings() onchange = function() {} function Settings(key) { return current[key] } function SettingsSet(key,value) { current[key] = value; onchange(); // trigger callback } function SettingsReset() { current = DefaultSettings(); onchange(); } function SettingsAttachCB( callback ) { onchange = callback }
Then my code above would become
some_setting = Settings('SOME_SETTING'); some_other_setting = Settings('SOME_OTHER_SETTING'); timestep = Settings('TIMESTEP'); some_curve = timestep * some_setting + x * some_other_setting + /* .. */
And in my initialization function, I would have a line like this
SettingsAttachCB( SomeRefreshFunction );
This would mean that, once the page has loaded, I can go to the Chrome debugger console, type SettingsSet('SOME_SETTING', 0.6)
, and that will automatically trigger SomeRefreshFunction
.
As a matter of fact, I even wrote a little HTML widget that turns current
in JSON into a popup window, and allows some users to modify it.