Documentation Guidelines
Download Documentation Keypoint's PDFEffective documentation is essential for successful software development and collaboration. It bridges the gap between complex codebases and the developers who interact with them, ensuring clarity, consistency, and continuity throughout the project lifecycle. These Documentation Guidelines are designed to provide a standardized approach to creating, maintaining, and updating development documentation within our organization.
Why Documentation Matters
Facilitates Collaboration: Clear documentation enables team members to understand each other's work, fostering seamless collaboration across different roles and departments.
Enhances Maintainability: Well-documented code and processes make it easier to troubleshoot issues, implement updates, and onboard new team members.
Promotes Best Practices: Standardized documentation practices encourage consistency, reduce errors, and uphold quality across all development projects.
Supports Knowledge Sharing: Documentation serves as a repository of collective knowledge, preserving insights and decisions that inform future development.
Purpose of These Guidelines
The objectives of these guidelines are to:
- Establish Consistency: Provide a unified framework for documenting code, APIs, systems, and workflows to ensure uniformity across all projects.
- Improve Clarity: Encourage the use of clear, concise language and standardized formats to make documentation accessible and understandable.
- Streamline Processes: Outline procedures for creating, reviewing, and updating documentation to integrate seamlessly with development workflows.
- Adopt Best Tools and Practices: Recommend tools, templates, and methodologies that align with industry standards and enhance documentation quality.
By adhering to these guidelines, we collectively contribute to a more efficient, transparent, and robust development environment. Whether you are drafting a README file, commenting code, or outlining an API specification, this document will serve as a foundational resource to guide your documentation efforts.
Who Should Use This Guide
These guidelines are intended for all team members involved in the development process, including:
- Software Developers
- Quality Assurance Engineers
- Project Managers
- Technical Writers
- DevOps Engineers
Regardless of your role, embracing these documentation standards will enhance our collective ability to deliver high-quality software solutions.
We encourage all team members to engage with these guidelines actively, confident that our collective efforts will lead to improved collaboration, reduced friction, and a stronger foundation for all our development endeavors.
Table of Contents
Actionable Ways to Improve Your Documentation
Create a Table of Documentation
Over time, documentation can become fragmented and dispersed across platforms such as Confluence, READMEs, GitHub wiki pages, issues, and code comments. This fragmentation can make it challenging for even experienced developers to locate the information they need. New hires may expect certain information to reside in a specific location, only to find it elsewhere—or worse, discover that it does not exist.
An effective solution is to create a centralized document that links to every key piece of documentation related to the team, work processes, and the codebase itself. This centralized resource, referred to as the Table of Documentation, serves as a comprehensive list of links to other documentation. Directing new team members to this single document streamlines the onboarding process and allows them to work through the necessary materials systematically.
This document can be organized by areas of concern:
- Getting Started: Machine setup, required dependencies, etc.
- Contribution Guide: Git usage guidelines, pull request review process, feature development workflow, etc.
- Troubleshooting Guide: FAQs, common issues, developer experience (DX) challenges.
- Additional Resources: Any other pertinent information.
It is advisable to include only links and section headings in this document. Any supplementary explanations may belong in separate files. Additionally, if multiple documents cover the same topic or contain redundant information, consolidating them or extracting shared content into standalone documents with appropriate links is recommended.
The Table of Documentation should encompass most of the topics discussed in this guide, serving as a foundational resource for the team.
Create a Technical Glossary
Software development is an inherently technical field, and even seasoned developers regularly encounter unfamiliar terms on the job. However, the jargon does not stop at the industry level; individual teams often have their own specialized vocabulary, with acronyms and terms unique to their company, product, and work processes.
While definitions for general software terms are readily available, team-specific vocabulary may not be documented anywhere. Long-standing developers may use these terms regularly without realizing that some of their coworkers might not understand them. New developers, for instance, may not grasp these terms unless they ask or spend sufficient time within the team, and even some existing developers may hesitate to admit that they have been unsure about certain terminology.
Compiling a technical glossary that defines every unique acronym or term used internally can benefit nearly every software team. This resource can help decode internal language and make the team more accessible to both new and experienced developers. Additionally, it can give new hires more confidence by enabling them to understand discussions during meetings without needing to interrupt to ask for explanations.
A technical glossary can be as simple as a three-column table that includes:
- The term itself and any other names it may have.
- A definition, in as much detail as needed.
- Examples or links that provide additional context.
It is advisable to encourage contributions from experienced developers, but it is even more important to gather feedback from recent hires, as their perspective is still fresh and they may have recently encountered unfamiliar terms. This should be a collaborative effort—some team members might add a term, while others might fill out all three columns.
One of the advantages of a technical glossary is that it allows these terms to be used freely in other documentation without the need to redefine them for new readers; anyone can reference the glossary if they require clarification.
Given the importance of this document, it should be posted in a visible location—perhaps as one of the first links in the table of documentation.
Document Areas of Expertise
Developers frequently encounter situations where they need to identify the author of specific code segments. As code changes hands and evolves over time, contributions can become unclear, leaving team members unsure of whom to consult with their questions. This uncertainty can lead to inefficiencies, such as being redirected multiple times before finding the appropriate contact. Additionally, there may be a need for guidance from team members who specialize in certain areas (such as CSS, accessibility, or testing) but who did not necessarily write the code in question.
To address these challenges, creating a Table of Expertise can be highly beneficial. This up-to-date resource should identify:
- Areas of expertise, both at a high level (problem domain) and at a granular level (specific features).
- Team members who specialize in these areas or have worked on these features.
The responsibility for compiling this table should be shared among all team members, as each individual is most familiar with their own contributions. Furthermore, this list should include not only developers but also designers and product team members who oversaw the development or approved key decisions. This ensures that anyone needing information about the original design or implementation knows exactly whom to contact. Including contact information for collaborators from other teams—such as back-end or infrastructure specialists—can also be valuable for future reference.
When employees depart from the team, it is important to assign other developers to take partial or full ownership of the affected areas to ensure ongoing maintenance and support. Without this reassignment, those areas may become neglected over time.
Answer Frequently Asked Questions
Frequently Asked Questions (FAQs) are a common feature on customer-facing pages, but they can also be valuable for internal teams. Compiling answers to frequently asked questions can provide a useful reference document for team members, reducing the need to repeatedly address the same inquiries.
Below is a selection of common questions that team members are likely to have, organized by relevant areas of concern. These questions are based on typical challenges faced by developers. As answers are compiled, they should be linked in the table of documentation for easy access.
Contribution Guide
- What dependencies and tools are required to install on local machines?
- What environment variables need to be configured for the application to function correctly?
- Which branches are used as the main branches? Which branch should be used for new work?
- Should repositories be forked, or should branches be pushed directly to the origin?
- What Git flow (if any) is followed by the team?
- What naming conventions are used for branches?
- What conventions should be followed for Git commit messages?
- What continuous integration (CI) pipeline is in use?
- How can a pull request (PR) build be previewed? Are there deploy previews for PRs?
- Where can details of PR builds be viewed, and how can build failures be diagnosed?
- How can PR builds be restarted? Are there specific commands, or should force-push be used?
- Is there a preference for rebasing vs. merging when updating local branches?
- Should PRs be squash-and-rebase before merging?
- Who should be tagged for PR reviews, and how many reviewers are required?
- Is there a PR checklist available? (Consider using issue or PR templates for this.)
- Are signed commits required?
- What patterns and tools are used for software testing?
- What is the expected code coverage for different parts of the application?
- Where can test account credentials be found, created, or mocked?
Troubleshooting Guide
- What does the error message "(obscure error)" indicate?
- What are the common causes of the error "(error)," and what steps can be taken to resolve it?
- Who should be contacted for assistance if a specific problem arises?
Process Guide
- What is the end-to-end process for feature development? Are kick-off meetings part of this process?
- What regular meetings are scheduled, and how frequently do they occur? (Scheduling recurring calendar invites may be useful.)
- Which HR charge codes should be used for various types of work?
- What is the process for requesting time off?
- Are there any special team events, such as workshops or team social gatherings?
Document Code Effectively
Proper documentation of code is essential, even when it may seem unnecessary. While a developer may understand the functionality of a piece of code they wrote, others may find it unclear or confusing when they need to contribute. Furthermore, even the original developer may struggle to understand code they wrote long ago.
Skipping documentation often leads to complications over time, and the short-term convenience of omitting it is quickly outweighed by the long-term issues that arise. There are several common reasons why developers may neglect documentation:
- Time pressure and deadlines: Developers may omit documentation if it has not been accounted for in the planning and estimation process for a feature. Without allocating time for documentation, it is unlikely to be completed.
- Bad habits: Some developers may come from environments where documentation was not prioritized. Even when recognizing the importance of documentation, they may be reluctant to invest the effort to write it.
- Ego: Some developers may mistakenly believe their code is self-explanatory, assuming others should be able to understand it without documentation.
While other developers may comprehend what the code does, they may not understand why it was implemented in a specific way or the problem it is intended to solve. Therefore, effective documentation should not simply restate the functionality of the code. For example, the following comment, while accurate, is not particularly useful:
// Get all offline users
const
offlineUsers
=
users
.
filter
(
(
user
)
=>
!
user
.
isOnline
)
;
Effective comments should provide additional context that cannot be inferred from the code itself. For example, consider the following real-world cases:
This jsDoc comment for a TypeScript prop type includes concrete examples:
type
Props
=
{
/** The user's locale, pulled from their browser settings.
* Example values: `en-US`, `ar`.
*/
locale
?
:
string
;
}
This CSS comment clarifies why a particular property is used:
.parent button
{
/* NOTE: Using opacity here instead of visibility/display to ensure
that keyboard users can still tab over to this button. */
opacity
:
0
;
}
.parent:hover button,
button:focus
{
opacity
:
1
;
}
This CSS comment provides context on how one property relates to another:
.inline-element
{
/* Some type of inline-* display is needed for vertical align to work */
display
:
inline-block
;
vertical-align
:
middle
;
}
This JavaScript comment describes a temporary fix for a known issue:
/* NOTE: Temporarily fixes a race condition to give the browser time
to render the element before we do something with it. */
setTimeout
(
doSomething
,
0
)
;
This comment explains why editing is initially disabled in a JavaScript application:
const
initialState
=
{
/* Disable editing initially and enable after mount only if the user's
credentials allow them to edit this card. Otherwise, if we enable it
initially, they may be able to edit it in time. */
isEditingDisabled
:
true
,
items
:
[
]
,
}
This TODO comment outlines future cleanup tasks:
<!-- TODO: ideally, we'd use an <ol> here with <article> elements for
the cards, but these components are also used elsewhere, so this
refactor should be done in a separate cleanup PR. Ticket: [link here] -->
This final note clarifies changes to a feature:
/* NOTE: Prior to <Release>, we only supported X. Because we now
support X and Y, we must do Z for backwards compatibility.
*/
Instead of merely describing what the code does, these comments provide context and clarify why certain decisions were made, potential improvements, and any known issues.
Document Your App’s End-to-End Data Flow
As a product grows in size and complexity, it often consists of multiple interrelated components. While senior developers may have a comprehensive understanding of the app’s data flow, other developers may specialize in specific areas, and new team members will need time to gain a full understanding of how the pieces work together.
A clear, high-level understanding of the data flow is essential for effective collaboration. Without this knowledge, seemingly minor changes in one area of the app could lead to unintended consequences elsewhere. Additionally, a well-documented data flow helps developers identify the most appropriate place in the code to address issues, as multiple solutions may exist, some of which are more efficient than others.
To document your product’s data flow effectively, use a combination of text and diagrams to outline the following:
- What types of data are stored at a high level? (Consider using relational diagrams or simple JSON schemas.)
- Where is this data stored?
- Is any data cached? If so, where, when, and for how long is it cached?
-
What is the entry point for data on the front end of the application?
- Does the app initialize a global store, or does each component manage its own data queries?
- How does data flow from this entry point to other components of the app?
- How does the app handle concurrent data access and write operations?
- Is there a standardized and consistent method for querying and updating the data?
- How frequently is the data updated? Does the app batch updates based on user actions, or does it update with every mutation?
- Does the app store any data offline for users who lose their network connection? If so, how and when is this data synced later?
- How does the app ensure that the UI responds to data updates in real-time and prevent issues related to stale data? Are there specific patterns or libraries used to manage this?
This is a subset of the key questions that should be addressed when documenting data flow. The focus should be on providing high-level explanations, while linking to more detailed documentation where necessary, as lower-level implementations may change over time.
Document How to Document
This section may seem circular in nature, but it is valuable to include guidance on how to document effectively within your team's documentation. While this section may not carry the same priority as others, it remains a helpful resource.
Some of the guidance provided in this article can be compiled into an internal document focused on improving documentation practices. In addition, it is useful to document the following:
-
Where to place new documentation.
- GitHub wikis
-
A
docs/directory - Other designated platforms or tools
-
How and where to collaborate with teammates when writing documentation.
- Google Docs
- GitHub issues (for example, by editing each other's comments)
- Slack/Teams channels
- How to obtain approval for documentation before submission.
- How the team plans to ensure documentation remains up to date.
This guidance can be especially useful for new hires, who may encounter missing or outdated information during their onboarding process and may want to contribute improvements while the experience is still fresh in their memory. Newcomers often bring a fresh perspective and are eager to help improve existing documentation.
Additional tips for writing better documentation that may be included in this section:
- Provide examples, particularly if external documentation lacks clarity.
- In READMEs and tests, use minimal and direct code samples.
- Include links to external documentation, StackOverflow posts, or GitHub issues when addressing obscure problems or researched solutions.
-
If an issue is noticed but cannot be immediately resolved, leave a
TODO,NOTE, orFIXMEcomment to flag the problem, and consider submitting a tracking ticket. - Clarify common pitfalls or challenges when using specific modules or libraries.
- When writing short-term fixes, document the reasons behind the decision. Future developers may not be aware of the constraints or limitations at the time the code was written.
- When selecting an unconventional approach, explain the reasoning behind it.
- Reference related files, pull requests (PRs), and issues where applicable (e.g.,
See X for more context). - Consider using GitHub permalinks when linking to files to avoid dead links.
Documenting Features and Code
When documenting features and code, the goal is to ensure that any developer, regardless of their familiarity with the project, can easily understand the purpose and functionality of the code. This includes explaining how the feature works, the rationale behind key decisions, and any dependencies or implications the code might have on other parts of the application.
Feature Description
For each new feature, provide a high-level description that outlines its purpose, functionality, and how it fits into the overall system. For instance, if you are documenting a file upsertion feature, your description might look like this:
Feature: This feature allows the application to upload or update file details (file metadata and paths) in the system. It handles both individual files and batch uploads, ensures the correct folder and file naming conventions, and integrates with several database models to store metadata and maintain consistency across the system.
Code Description
After describing the feature at a high level, provide a detailed explanation of how the code works. This
should include the purpose of each key function, its inputs, outputs, and any relevant business logic.
For example, you might break down the upsertFileDetails function as follows:
Function:
upsertFileDetails(data: any, isIndividual: boolean)handles the upsertion of file details into the system. This function checks if the file already exists in the system and either updates its metadata or inserts a new entry.Parameters:
data: An object containing the folder and file details, as well as the existing upload path.isIndividual: A boolean indicating whether the file is uploaded individually or as part of a batch.Process Overview:
- The base directory for PDF files is retrieved from environment variables, with a default path provided if none is set.
- The folder and file names are extracted from the
dataparameter, and the relative upload subdirectory is calculated.- The filename is generated based on whether the file is uploaded individually or as part of a batch, ensuring the proper format for each case.
- The database is queried to check if the file already exists under the specified folder. If it does, the file's metadata is updated. If not, a new entry is created in the database.
- The function also handles any related whitelabel forecast files, ensuring that the data is consistent across different whitelabel groups.
Comments and Code Documentation
In addition to high-level documentation, ensure that inline comments are used within the code to clarify specific logic, decisions, or edge cases. Here’s how to effectively comment on the example code:
- Environment Variables: Comment on the use of environment variables like
process.env.PDFDIRto clarify why the default path is necessary. - File Naming Logic: Provide comments explaining how file names are generated for individual vs. batch uploads and why the specific naming format is required.
- Database Queries: Use comments to explain the purpose of database lookups (e.g., searching for existing files) and the rationale for updating or inserting new entries.
- Error Handling: While the code currently does not include explicit error handling,
it’s important to note potential failure points and add comments or
TODOnotes where necessary (e.g., handling failed database queries or missing data).
Example Comments in the Code
Here’s an example of how comments could be added to a function:
// Function to upsert file details (for individual or batch file uploads)
public static async upsertFileDetails(data: any, isIndividual: boolean) {
// Get the base directory for PDF files, defaulting if environment variable is not set
const pdfBasedir = process.env.PDFDIR || '/home/mbi/metalsource/pdf/';
// Extract the folder and file details from the data object
const { folder, file, existuploadSubPath } = data;
// Construct the folder path and relative subdirectory path
const folderPath = `${pdfBasedir}/${folder}`;
const subDir = path.relative(folderPath, existuploadSubPath);
// Initialize variable for the re-formatted file name
let fileNameRechange;
// Determine if the file is an individual file or part of a batch, and set the file name accordingly
if (isIndividual) {
fileNameRechange = file.originalname;
} else {
// Reformat the file name for batch uploads
const FolderData = folder.split('_');
const fileconvert = file.originalname.split(' ');
const last = fileconvert[fileconvert.length - 1];
const fileNewName = last.split('.');
fileNameRechange = `${fileNewName[2]}-${fileNewName[1]}-${fileNewName[0]}__${FolderData[1]}__${fileNewName[0]}-${fileNewName[1]}-${fileNewName[2]}.pdf`;
}
// Check if a forecast entry exists for the specified folder
const forecast = await Forcasts.findOne({ where: { ordnername: folder } });
if (!forecast) return;
// Extract prognosen_id from the forecast entry
const { prognosen_id } = forecast;
// Check if the file already exists in the database
const isAlreadyExist = await ForecastFiles.findOne({
where: { file_name: fileNameRechange, prognosen_id, path: `${subDir}/` },
paranoid: false,
});
// Current timestamp for creating or updating records
const currentDate = new Date();
let fileId = 0;
// If the file exists, update it, otherwise create a new entry
if (isAlreadyExist) {
fileId = isAlreadyExist.id;
await ForecastFiles.update(
{ path: `${subDir}/`, updated_date: currentDate, deleted_at: null },
{ where: { file_name: fileNameRechange, prognosen_id, path: `${subDir}/` }, paranoid: false }
);
} else {
// Create a new file entry in the database
const forecastFile = new ForecastFiles();
forecastFile.prognosen_id = prognosen_id;
forecastFile.file_name = fileNameRechange;
forecastFile.datum = isIndividual ? currentDate : extractDate(fileNameRechange);
forecastFile.path = `${subDir}/`;
forecastFile.is_visible = 1;
forecastFile.created_date = currentDate;
forecastFile.updated_date = currentDate;
await forecastFile.save();
fileId = forecastFile.id;
}
// Handle whitelabel forecast files similarly to the main forecast files
const findOneActiveWhitelabel = await WhitelabelGroups.findAll({
attributes: ['id'],
where: {
forecast_status: {
[Op.in]: [CustomStructureWhitelable.ACTIVE, CustomStructureWhitelable.ACTIVEORIGINAL],
},
},
});
// Iterate over whitelabel groups and upsert the corresponding files
for (let i = 0; i < findOneActiveWhitelabel.length; i++) {
const element = findOneActiveWhitelabel[i];
const whitelabelforecast = await WhitelabelForcasts.findOne({ where: { ordnername: folder, whitelabel_id: element.id } });
if (!whitelabelforecast) continue;
const whitelabel_prognosen_id = whitelabelforecast.prognosen_id;
const isAlreadyExistFile = await WhitelabelForecastFiles.findOne({
where: { file_name: fileNameRechange, prognosen_id: whitelabel_prognosen_id, whitelabel_id: element.id, path: `${subDir}/`, file_id: fileId },
paranoid: false,
});
// Update or insert whitelabel forecast file records
if (isAlreadyExistFile) {
await WhitelabelForecastFiles.update(
{ path: `${subDir}/`, file_id: fileId, deleted_at: null },
{
where: {
file_name: fileNameRechange,
prognosen_id,
whitelabel_id: element.id,
path: `${subDir}/`,
file_id: fileId,
},
paranoid: false,
}
);
} else {
// Create new whitelabel forecast file metadata
const forecastFile = new WhitelabelForecastFiles();
forecastFile.prognosen_id = whitelabel_prognosen_id;
forecastFile.file_name = fileNameRechange;
forecastFile.datum = isIndividual ? currentDate : extractDate(fileNameRechange);
forecastFile.path = `${subDir}/`;
forecastFile.is_visible = 1;
forecastFile.file_id = fileId;
forecastFile.whitelabel_id = element.id;
await forecastFile.save();
}
}
return;
}
Final Tips for Documenting Features and Code
When documenting features and code, always ensure that:
- The purpose of the code is clearly explained, both at a high level (in documentation) and at a granular level (in code comments).
- Any key decisions, assumptions, or edge cases are documented to help other developers understand the rationale behind certain approaches.
- References to external libraries, dependencies, and related code (files, PRs, or issues) are included where necessary.
- Clear examples or code snippets are provided to help explain complex logic or functionality.
- Input Examples are given to ensure easy adaption of features.