Skip to content

Contributing to Tower

Lance Pollard edited this page Oct 3, 2012 · 14 revisions

Contributing to Tower

Windows:

Windows is now supported.

This guide is for developing Tower in a Mac OS X environment. (Windows follows the same installation. Just make sure you have make installed as it doesn't come natively.)

All contributions, either via master or the wiki, get credit in Tower Contributors once we get that page up.

Also, we will create gists named Tower.js Discussion - [topic goes here] until GitHub has a Google Groups replacement. I'm too much a fan of syntax highlighting to use Google Groups :)

Contributing to the Tower Codebase

Tower's master branch is always a reflection of what you'll get with npm install. Tower's development branch is the latest stuff. So when a pull request is merged, it's first going to be merged to development and it may be a while before it's pushed to master. Issues will be closed when code is pushed to master.

First setup your Tower development environment.

Create a dedicated branch

git branch development
git checkout development

It doesn't really matter what name you use, because this branch will only exist on your local computer and your personal repository on GitHub. It won't be part of the Tower git repository.

This is also optional, but it's good practice. You can also use feature branches on your main development branch.

Setting up your environment

For starters you'll need npm, node, and git of course.

  • The first thing you'll want to do is fork your own copy of Tower into your own git repository. After you've forked Tower you'll need to clone it locally.
git clone git://github.com/username/repository.git some_folder_here && cd some_folder_here
  • After downloading a fresh copy of Tower you'll need to install all of the dependencies.
make install
  • Your now ready to begin stabbing at Tower's source code, but first you need to start the watch command to automatically compile the coffeescript when you've added, edited, or deleted a file.
make watch

This process will need to remain open when tampering with Tower's source.

  • If you want to use your version of Tower inside one of your apps to test stuff you'll need to run: (Make sure you're within the tower directory you created earlier)
npm link
  • To use your local version of Tower cd into one of your apps and run:
npm link tower

This will link your version of Tower with your app so that you can test stuff out.

Compile the CoffeeScript Files for Tower

Note: Tower does not use Design.io anymore. It uses a mixture of gruntjs and cake files.

cake watch # App Development
make watch # Tower's Source Development

Write Your Code

The code should be written Test Driven. Use mocha to execute the Tower test suite. To run the entire test suite from the console, simply execute:

npm test

That references the test key in package.json, which looks like this:

mocha $(find test -name "*Test.coffee")

You can customize this expression to run a subset of tests if you're developing something and don't want the clutter.

Example: run all "article" related tests

mocha $(find test -name "article*Test.coffee")

See Browser testing for more info.

Follow the Coding Conventions

Tower follows a simple set of coding style conventions.

  • Two spaces, no tabs.
  • No trailing whitespace. Blank lines should not have any space.
  • Prefer &&/|| over and/or.
  • a = b and not a=b.
  • Follow the conventions you see used in the source already. Check the style guide for a few notes as well.

Commit Your Changes

When you're happy with the code on your computer, you need to commit the changes to git:

git commit -a -m "Here is a commit message on what I changed in this commit"

Please squash your commits into a single commit when appropriate. This simplifies future cherry picks, and also keeps the git log clean.

Before you do the final push, synchronize with upstream from @viatropos/master

git remote add upstream [email protected]:viatropos/tower.git
git fetch upstream
git merge upstream/master

Issue a Pull Request

Push your code to your repository

git push

and [issue a pull request]((http://help.github.com/send-pull-requests/):

Get Some Feedback

Now you need to get other people to look at your patch, just as you've looked at other people's patches. You can use the #towerjs channel on IRC freenode for this. You might also try just talking to Tower developers that you know.

Contributing to the Tower Documentation

Tower has two main sets of documentation: The guides help you to learn Tower, and the actual code API for reference.

You can help improve the Tower guides by making them more coherent, adding missing information, correcting factual errors, fixing typos, bringing it up to date with the latest edge Tower.

Development guide

Tower should also have a development guide that goes through the main structure of Tower, the APIs and how to add functionality while following the existing conventions and design/architecture.

The development guide should be structured according to the folder structure inside lib/tower:

  • Application
    • Locale
  • Client
    • Application
    • Controller
    • Store
    • View
  • Controller
  • Http
    • Param
    • Route
  • Middleware
  • Model
    • Locale
    • Relation
    • Scope
    • Validator
  • Server
    • Application
    • Command
    • Controller
    • Generator
    • Mailer
    • Middleware
    • Store
  • Store
    • Memory
  • Support
    • Locale
  • View
    • Form
    • Helpers
    • Locale

Minimal amount of code

Every method should strive to be as simple as possible while still being able to handle as many cases as possible. Refactor it into something reusable if possible. Sacrifice performance only when you eliminate a lot of code (by "performance", I'm talking about differences like those between functions and for loops for iterating).

The most efficient implementations

Every method should not only be minimal, it should also be efficient, using formal algorithms where possible. But, if the algorithm implementation is significantly longer than a less efficient solution, or you'd have to import an external dependency, go with the less efficient solution, somehow get that external library to be part of something standard like underscore.js, or create a new algorithm.

Minimize the amount of methods you have on the class

There is a tradeoff here. If you're going to be using some set of functionality on a class all the time, then go with whatever's simpler for the developer. However, if it's an edge/uncommon case, then wrap it in a nested object.

An example is with the finder API vs configuration variables.

Instead of doing this for configuration, which just adds a bunch of methods to the API:

class App.User extends Tower.Model
  @defaultScope @desc("createdAt")
  @collectionName "people"

Do this:

class App.User extends Tower.Model
  @configure
    scope:          @desc("createdAt")
    collectionName: "people"

This way we have 1 method, configure, instead of potentially dozens of methods. This makes the class feel much lighter and easier to work with.

But when you use the methods all the time, you don't want to have to drill down through an object (law of demeter). You can see this through the scoping api

Imagine writing this a 100 times:

User.criteria().where(firstName: "Lance")

instead of this:

User.where(firstName: "Lance")

In the first case, we have a simpler api, but it makes development more burdensome and less intuitive. In the second case, it's very clear what's going on, even though we add several methods (where, anyIn, etc.) to the class API.

A tricky case is with methods for model naming: toKey, toParam, etc. Those are not that commonly used, but it makes sense doing model.toParam() rather than something like model.names().param. This is where you have to make the call. I tend to go with putting it all in a nested object, and then adding methods if it turns out it would make life easier down the road. Don't prematurely add methods unless it's just totally obvious you'll be using them.

Build it so you can Progressively Add Features

Instead of making it so the model.set method can do everything, make it handle the simple case and make that module usable by itself. This way, if you have a simple app, you can use the version/parts of the library that's a lot lighter than the complete solution. But also make it so it doesn't require too much memory/processing to append these new features if you do want them (other than the fact you'll have to load more code). I'm talking about not forcing every module to call super if it overrides a method in a simpler method. Somehow organize your code so you can minimize these types of extra method calls while still making it enhanceable.

Minimize the number of singular/plural method implementations (purely aesthetic)

You can use both if it makes testing your methods easier, but just make sure it's not purely aesthetic.

class App.User extends Tower.Model
  @default "store", Tower.Store.Memory
  @default "scope", @desc("createdAt")
class App.User extends Tower.Model
  @defaults store: Tower.Store.Memory, scope: @desc("createdAt")

Helping to Resolve Existing Issues

Verify Bug Reports

Testing Patches

Reporting an Issue

Bugs

https://github.com/viatropos/tower/issues

Please markup your issue with GitHub's markdown code blocks:

  info  - socket.io started
[Mon, 23 Apr 2012 16:40:33 GMT] INFO Tower development server listening on port 3000

node.js:201
       throw e; // process.nextTick error, or 'error' event on first tick
...

Your code is wrapped in triple backslashes, and you can specify the language (\`` bash, ``` coffeescript, ``` javascript, ``` ruby, ``` html`, etc.)

Features

Add these to the todo wiki's Potential Features section.

Questions

http://stackoverflow.com/

Discussion

https://groups.google.com/group/towerjs https://groups.google.com/group/towerjs-dev

IRC

The #towerjs channel on irc.freenode.net.

Feedback

You're encouraged to help improve the quality of this guide.

If you see any typos or factual errors you are confident to patch, please clone the wiki and push the change yourself. That branch of Tower has public write access. Commits are still reviewed, but that happens after you've submitted your contribution. the wiki is cross-merged with master periodically.

You may also find incomplete content, or stuff that is not up to date. Please do add any missing documentation for master.

If for whatever reason you spot something to fix but cannot patch it yourself, please open an issue.

And last but not least, any kind of discussion regarding Tower documentation is very welcome on the Tower Google Group.

Contributing Translations

Translating the Tower Guides

It's great to have people volunteer to translate the Tower Guides into their own language.

If you want to launch a translation, you should:

  1. Fork the Tower.js wiki
  2. Add folders for your own language (for example, ./pt-BR/guides for Brazilian Portuguese)
  3. Copy the source files from guides to your own language folder, and translate them

Current translation efforts

Here's how I am going to layout http://towerjs.org:

  • /guides (/guides/models, /guides/application, etc.)
  • /api (generated documentation)
  • /community (links to github, google group, contributors, etc.)
  • /roadmap
  • /examples (list of projects with pictures)
  • /screencasts
  • /tests (client test suite)
  • /contributors

The bulk of what you'd be translating would be under /guides (I might call this /docs, not 100% yet). Currently, those files are in the wiki/docs folder when you clone the wiki.

We said before we were going to go with the http://towerjs.jp domain for both the docs and the group. My thinking then was, I didn't want to be a bottleneck for you getting your translations out there on the web. But after further reflection, I think it would be easier and more manageable if everything did go through the main site at http://towerjs.org.

The main reason is, you and other contributors who translate Tower into different languages, shouldn't have to purchase a domain and go through the hassle of managing an application on top of all your translation work... that just creates a barrier to writing translations. If you want to have your own domain and keep the app in sync with the towerjs.org repo, that's totally fine, but I think the default should only require that you just handle the markdown files you're translating.

Here's how we do that.

First, any translation should be accessible from http://towerjs.org/{locale}, so http://towerjs.org/ja/docs or http://towerjs.org/ja-JP/docs (not sure the exact locale for Japan). I may want to make this a subdomain (i.e. http://ja-JP.towerjs.org/docs), but for now lets assume it will define a top-level path.

Second, to write the actual translations:

  1. clone the wiki (https://github.com/viatropos/tower/wiki/_access).
  2. copy/paste the [relevant] wiki pages into the locale (wiki/ja-JP/docs/models.md, etc.).
  3. translate those pages.
  4. submit a pull request.
  5. I'll update the main site.

See https://github.com/viatropos/towerjs.org/blob/master/Cakefile#L102 for the markdown files currently being used on the main site.

In the end, this will work a lot like docrails where you just edit markdown files.

Clone this wiki locally