Scalable and Flexible Directory Structure for Web Applications

Designing a modular and component-based directory structure for your Web applications can seem like an easy task. If your system is small, it may seem logical to go with the simplest design possible, but if there’s anything more time consuming and complex than developing a new directory structure design, it’s trying to redesign an existing system that wasn’t developed with growth in mind.

Consistency

To ensure that your development and build processes work effectively in a team environment, it’s essential to start with a correct directory structure that is consistent across all of your development servers. Frameworks, for example, provide a standard directory structure to organize the content in a logical way, consistent with the architecture choices: MVC pattern and project, application and module grouping.

The directory structure of the Zend Framework:

project/
  app/
    modules/
      module/
        controllers/
        models/
        views/
  cache/
  config/
  lib/
    Zend/
  public/
    index.php
  tests/

The directory structure of Symfony:

project/
  apps/
    application/
      modules/
        module/
            actions/
            config/
            lib/
            templates/
  cache/
  config/
  data/
  lib/
  log/
  plugins/
  test/
  web/
    css/
    images/
    js/
    uploads/

The directory structure of Ruby on Rails:

project/
  app/
    controller/
    helpers/
    models/
    views/
    layouts/
  components/
  config/
    environments/
  db/
  lib/
  log/
  public/
    css/
    images/
    js/
    uploads/
  script/
  test/
  vendor/

Scalability and Flexibility

A small system may very well start with a single project, but as the business requirements grow, you may find it useful to divide the system into multiple projects. If you’re creating your directory structure from scratch, you have the opportunity to maximize scalability and flexibility.

Using a directory as a container for all of the shared libraries enables greater reuse of components. If a project needs to reference a specific library create a symbolik link, for example:

libraries/
  ezComponents/
  Zend/
    1.5/
    1.5.1/
    1.5.2/
    1.6/

projectA/
  lib/
    Zend/ -> /home/libraries/Zend/1.6
  public/

projectB/
  lib/
    Zend/ -> /home/libraries/Zend/1.6
  public/

File references should be used only to reference outer-project libraries (such as the Zend Framework) that are not specific to a project. On of the advantages of doing it this way is that project references are sensitive to changes, this means that you can automatically switch from one version to another one without having to distribute files across multiple projects.

There are two main models to consider for creating projects:

1. Single application
2. Multi-application

Single Application

The single application model allows you to break up your projects to provide a greater level of isolation and control. Think about which applications you want to work on in isolation, and create separate projects accordingly.

project/
  app/
    controllers/
    models/
    views/
  lib/
    Zend/ -> /home/libraries/Zend/1.6
  public/

Or in larger systems, a modular single application model:

project/
  app/
    modules/
      module/
        controllers/
        models/
        views/
  lib/
    Zend/ -> /home/libraries/Zend/1.6
  public/

These are simpler to work with and offer a number of significant advantages over the multi-application model. For example, it allows you to work on smaller subsystems, and therefore reduces the complexity of the project and the number of dependencies.

Multi-application

In some cases, you may want to divide your project into multiple applications. For example, if you want to reduce the number of files required on each application. This allows you to work on separate applications within the inner-project boundary. A single project approach is simpler, so split a project up into multiple applications only if absolutely necessary.

project/
  apps/
    applicationA/
      modules/
    applicationB/
      modules/
  config/
  lib/
  public/

One of the disadvantages of using this model is that you are limited in the way you can break up your projects. This is because of the application dependency relationships. As a result, if you want to move a particular application to a different server, you are forced to copy all the dependent files, such as configuration files, layouts, schemas and/or specific components and libraries. Unless you have very good reasons to use a multi-application model, you should avoid this and adopt a single application model.

Naming Conventions

Ruby on Rails did a great job establishing a standard directory structure, and since then everyone has tried to conform to this structure as much as possible. For that reasons, when naming your folders you should aim for a consistent set of names, this can greatly simplify project organization. While it is possible to rename folders later on in the development cycle, you should avoid this if possible. For example:

Bad:

project/
  controllers/
  etc/
  ezComponents/
  models/
  templates/
  var/
    log/
    tmp/
  www/
  Zend/

Good:

project/
  app/
    controllers/
    models/
    views/
  config/
  lib/
    ezComponents/
    Zend/
  log/
  public/
  tmp/

Versioning

It is always good to assign unique version numbers to unique states of a project. These numbers are generally assigned in increasing order and correspond to new developments in the project.

project/ -> /home/project_version/0.3

project_version/
  0.1/
  0.2/
  0.3/
    app/
      modules/
        module/
          controllers/
          models/
          views/
    lib/
    public/

One of the advantages of doing it this way is that when a new version of the project is released, you only need to change the reference to the version number, as opposed to modifying the Web server configuration file. This speeds up the deployment process and allows you to rollback to a previous state of the project very easily.

Proposed Structure

The directory structure I use for my projects has been influenced by many frameworks, specially Rails, which defines a standard project structure. I’ve then added to this some things I’ve seen in real-world projects.

libraries/
  Zend/
    1.5.2/
    1.6/

mysite/
  build/
  migrate/
  www/ -> /home/mysite_version/0.2

mysite_version/
  0.1/
  0.2/
    app/
      cache/
      config/
      layouts/
      modules/
        module/
          controllers/
          i18n/
          models/
          properties/
          views/
      tmp/
    lib/
      Core/
      Zend/ -> /home/libraries/Zend/1.6
    public/
      index.php
    test/

Web server configuration file (never changes):

<VirtualHost *:80>
DocumentRoot /home/mysite/www/public
ServerName mysite.com
ServerAlias www.mysite.com
</VirtualHost>

More information


About these ads

27 thoughts on “Scalable and Flexible Directory Structure for Web Applications

  1. About Zend Framework structure, how you you use models directory on every module dictory?, because I saw some *tricky* implementations about it, I use that same modules structure, and in my bootstrap I set the modules directory using the Zend_Controller_Front::addModuleDirectory method, all works fine, but the models folder is not recognized by the framework, so I need to call the php’s set_include_path() function for every model folder that I want to use, I guess Zend Framework’s people *forget* it.

  2. You can extend Zend_Controller_Action and add the following method:

    getModel ( [str class, [str module] )

    The second parameter is optional, if no module name is provided, use the current one.

  3. Hi,

    I’m waiting for your example because it’s the architecture that i want to do !

    I still listen to!

    Thanks for this great post

    Yu.

  4. Hi, looks good, but I’d suggest a few tweaks:

    - Move config/ up a level, as it may contain config files for other components, not just your MVC application

    - Multiple webroots per project

    - Place the VHosts file in the config/ directory, and link to it with an Apache Include directive

    - Use version control and a build script, rather than manually versioning with directories

    - Move libraries out of the project entirely, so they’re available server-wide, not project-wide

    I threw up a post that expands on this.

  5. You are right, I didn’t have time to explain how to add multiple bootsrappers to a project. I’m glad you did.

    > Place the VHosts file in the config/ directory, and link to it with an Apache Include directive.

    Good tip, I’m going to look into this, thanks.

    > Use version control and a build script, rather than manually versioning with directories

    Versioning the directory structure is different from using a VCS. You can have, for example, legacy projects using version 0.9 of the ZF library. Or developers working on future versions of a project. The directory structure shown above assumes you are working on the development server.

    > Move libraries out of the project entirely, so they’re available server-wide, not project-wide

    Based on my experience, only shared libraries should be moved outside a project. Moving all the libraries, including project-specific components, can lead to a maintenance nightmare. But that’s just my opinion.

    Thanks David!

  6. >Versioning the directory structure is different from using a VCS. You can have, for example, legacy projects using version 0.9 of the ZF library.

    I can see the advantage of holding multiple versions of the codebase and flipping between them with symlinks, but it results in configuration data (the symlinks themselves) being managed manually outside source control, which makes me nervous.

    >Based on my experience, only shared libraries should be moved outside a project.

    Agreed. I thought you were putting 3rd-party components in libraries/ ? It’s possible I misunderstood your layout.

  7. All the code you see in the directory structure is managed inside a VCS. The way continuous integration is done is up to the development team. Developers usually commit changes to the repository and a cron job updates the directory structure on an hourly basis.

    At some point, you’ll need to have a file-based representation of your repository, and allowing the web server to access different versions of a library can help you upgrade and downgrade components and work more effectively with legacy code.

  8. Pingback: David Otton

  9. Pingback: GrantPalin.com

  10. Pingback: rpsblog.com

  11. Thanks for this great article. I’m new to PHP and ZF and trying to create my own directory structure on my projects.

    I have a question. I didn’t understand what “mysite/www/ -> /home/mysite_version/0.2″ and “mysite_version/0.2/library/Zend/ -> /home/libraries/Zend/1.6″ are. Are those redirections to directories? How and where will we use them?

    I’m sorry if that question looks so stupid.

    Best regards..

  12. Pingback: Top Posts 2008

  13. There’s a few months that I’m working with ZF (I’m really work with Magento, who implements a custom strucutre based on ZF).
    Now I’m looking for a clear directory structure to work with my own applications.
    I found your article very interesting, and I start to make my own tests.
    I prefer the multi modules strucutre, and I can get ZF working with that schema.
    Until now, I can’t make that every controller into every module, can load his own models.
    Can you explain a little bit more about how can use the multi modules strucutre and configure the index.php to have the avility to find the models and views of every module?
    Thank you.

  14. In the name of consistency and class naming convention, just say no to lower case, plural directory names. Zend Framework got it right, and then abandoned all reason with its mvc implementation. A new resource loader is in the works to make it easier to autoload module resources like models.

  15. Pingback: » Keeping Admin and Public Areas Separate Zend Framework - MVC - ACL versus .htaccess - Eat My Business

  16. Thanks, that saved me a great deal of time. How long have you spent working with Magento? You so are an online high-and-mighty at it!

    Thanks again, Anteve.

  17. Thanks man…I needed to come up with a custom solution to a base class that will be have extended functionality and a different UI layer for each client. With a combination of your versioning and multiplication examples I was able to come up with something quickly that will work for years to come! Thanks!!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s