Developing a big, sophisticated project entails many challenges. To mitigate some of these challenges, we have adopted several best practices: incremental development, code review, and continuous integration.
Here are some tips on how to divide up a big project into smaller, bite-sized pieces so each piece can be incrementally developed, code reviewed, and integrated.
- Input: define different sets of test inputs based on complexity and difficulty. Tackle simpler sets first.
- Output: define intermediate results leading to the final output. Often, results A and B are needed to generate C. So the project can have multiple stages, based on the intermediate results.
- Algorithm: complex compiler algorithms are often just enhanced versions of more fundamental algorithms. Implement the fundamental algorithms first to gain insight and experience. Then, afterward, you can implement the full-blown versions.
- Language: for projects dealing with multiple languages, focus on one language at a time.
- Platform: limit the scope of supported platforms: Linux, Ubuntu, OS X (TODO: add reference to ROSE supported platforms)
- Performance: Start with a basic, working implementation first. Then try to optimize its performance, efficiency.
- Scope: your translator could first focus on working at a function scope, then grow to handle an entire source file, or even multiple files, at the same time.
- Skeleton then meat: a project should be created with the major components defined first. Each component can be enriched separately later on.
- Annotations (manual vs. automated): Performing one compiler task often requires results from many other tasks being developed. Defining source code annotations as the interface between two tasks can decouple these dependencies in a clean manner. The annotations can be first manually inserted. Later the annotations can be automatically generated by the finished analysis.
- Optional vs. Default: introducing a flag to turn on/off your feature. Make it as a default option when it matures.