LFE Style Guide
2 General Guidelines
2.1 Principles
There are some basic principles for team software development that every developer must keep in mind. Whenever the detailed guidelines are inadequate, confusing or contradictory, refer back to these principles for guidance:
Every developer's code must be easy for another developer to read, understand, and modify — even if the first developer isn't around to explain it. (This is the "hit by a truck" principle.)
Everybody's code should look the same. Ideally, there should be no way to look at lines of code and recognize it as "Fred's code" by its style. * Be precise. * Be concise. * Keep It Simple. * Use the smallest hammer for the job. * Use common sense. * Keep related code together. Minimize the amount of jumping around someone has to do to understand an area of code.
2.2 Priorities
When making decisions about how to write a given piece of code, aim for the following "-ilities" in this priority order:
- Usability by the developer/user/consumer/customer.
- Debuggability/Testability.
- Readability/Comprehensibility.
- Extensibility/Modifiability.
- Efficiency (of the LFE code at runtime)
Most of these are obvious.
Usability means that the system has to do what the end user requires; it has to handle such things as transaction volumes, uptime requirements; etc.
For the LFE efficiency point, given two options of equivalent complexity, pick the one that performs better. (This is often the same as the one that conses less, i.e. allocates less storage from the heap.)
Given two options where one is more complex than the other, pick the simpler option and revisit the decision only if profiling shows it to be a performance bottleneck.
However, avoid premature optimization. Don't add complexity to speed up something that runs rarely, since in the long run, it matters less whether such code is fast.
2.3 Architecture
To build code that is robust and maintainable, the following matter a great deal:
- how the code is divided into components;
- how these components communicate;
- how changes propagate as they evolve, and more importantly,
- how the programmers who develop these components communicate as these components evolve.
If your work affects other projects, might be reusable across projects, adds new components, has an impact on other projects, or otherwise isn't purely local, you create a document describing the new architecture or proposed changes in architecture. This document should then be shared with projects and/or communities in order to build community consensus around the proposed changes or, better yet, provide additional insight of the problem space in question and perhaps better alternative solutions that have fewer negative impacts on other projects..
If you don't know or don't care about these issues, ask someone who does. A great place to start is on the #erlang-lisp channel of Frenode or the Lisp Flavored Erlang mail list on Google Groups.
2.4 Using Libraries
Often, the smallest hammer is to use an existing library. Sometimes the least effort actually is to create one that doesn't exist yet.
In general, it is better to contribute to a library that is missing the features that you need or has broken functionaly that you need fixed. The obvious benefits of this include:
- Good will with the maintainers of the open source project.
- Less code for you or your project(s) or team(s) to maintain.
- Increaed contact and communication between different projects.
- Safeguarding against the NIH syndrome.
Whichever library, old or new, you pick, you should discuss with the other members of your project. Do they agree with the solution? Is the selected library viewed by all as a good project and dependency? Discuss the use of such library in the appropriate mailing-lists and IRC channels. Then have your code that integrates this library reviewed by people knowledgeable in the problem domain. Be ready to discuss why this particular solution makes sense as compared to other available libraries.
Some libraries are distributed under licenses not compatible with the software you're writing, and must not be considered available for use. Be aware of these issues, or consult with people who are.
2.5 Open-Sourcing Code
If you write a general-purpose library, or modify an existing open-source library, you are encouraged to publish the result separate from your main project and then have your project import it like any other open-source library.
Use your judgment to distinguish general-purpose versus business-specific code, and open-source the general-purpose parts.
Open-sourcing code has many advantages, including being able to leverage third parties for development, letting the development of features be user- directed, and keeping you honest with respect to code quality. Whatever code you write, you will have to maintain anyway, and make sure its quality is high enough to sustain use in production. There should therefore be no additional burden to open-sourcing, even of code that (at least initially) is not directly usable by third parties.
2.6 Development Process
Development process is outside the scope of this document. However, developers should remember at least these bits: get reviewed, write tests, eliminate warnings, run tests, avoid mass-changes (keep branches small).
All code changes should be reviewed. You should expect that your code will be reviewed by other hackers, and that you will be assigned other hackers' code to review. Part of the review criteria will be that code obeys the coding standards in this document.
You should write and check-in tests for new code that you write and old bugs you fix. There should be a unit test for every code path in each function, as well as tests for any previously failing case. Your work is not truly done until this activity is complete. For more details on this, see the Testing section of the Style Guide, the EUnit section of the User Guide, and the LFE TDD Tutorial.
Your code should compile without any errors or warning messages.
All code should be committed to an appropriate source control system, in a way that allows for complete reproducibility of build, test and execution of the code that is, has been, or may be deployed.
You should run the test suite for your project and all tests should pass before any code is committed.
All bug fixes, feature, changes, etc., should be done in small branches. A good rule of thumb is that a branch diff should not be greater than 500 lines (e.g.,
git diff|wc -l
). If it is, reviewers will be less likely to quickly volunteer a review, the changes will be harder to follow, and theh likelihood of negative impacts that might not get caught is higher. If you find that your branch is too large, hop on the mail list or IRC to seek advice on how best to split your brach into sensible, separate branches.
The following is pending BEAM AST support:
- You should incorporate code coverage into your testing process. Tests are not sufficient if they do not cover all new and updated code; code that for whatever reason cannot be included in coverage results should be clearly marked as such including the reason.