# Contributing to Frappe Books If you are a Frappe Books user and want to contribute to improving it _without writing code_, there are several things you can do: - **Inform us of issues** you face while using Frappe Books by [raising issues](https://github.com/frappe/books/issues/new). - **Add a language** you would like to use Frappe Books in by [contributing translation](https://github.com/frappe/books/wiki/Contributing-Translations). - **Share your thoughts** on Frappe Books by joining our [Telegram group](https://t.me/frappebooks). - **Use Frappe Books** for your accounting requirements and tell people about it. --- If you want to contribute code to Frappe Books, please go through the following sections for tips and guidelines: - [Code Quality](#code-quality) - [Contributing Features](#contributing-features) - [Invisible until required](#invisible-until-required) - [Simple UI](#simple-ui) - [Documentation and Tests](#documentation-and-tests) - [PR Description](#pr-description) - [Writing Tests](#writing-tests) ## Code Quality A few rules of thumb to ensure that you're contributing maintainable code to Frappe Books: - **Readability over succinctness**: If your succinct code takes longer to parse (as in read and understand) then it is bad code because we aren’t playing code golf. - **Write short functions** such that the name of the function accurately describes what the function does. - **Use early exits** ([reference](https://softwareengineering.stackexchange.com/questions/18454/should-i-return-from-a-function-early-or-use-an-if-statement)). - **Don’t nest conditionals and loops**. If you find the need for nested loops or conditionals, wrap the inner loop or conditional in a function and call it in the outer code block. - In general, understand why chunking and naming information is helpful when it comes to comprehension. - **Succinctness over readability only if it is significantly more performant**: For example, if your code goes from `O(n)` to `O(log(n))` then it’s okay to sacrifice readability. In such a case, add comments that mention what is going on. - **Don't Write comments**: Variable names, function names and easy to read code should do what a comment would. - **Write comments only if the code can't be explained by its context** such as if the code is esoteric for the sake of performance. - **Rebase don't merge**: Merge commits are ugly and should be used only to merge a large PR. - **Format your code**: Frappe Books uses `prettier` and `eslint` rules for code styling and linting, please make sure you have run them and fixed your code accordingly before pushing. - **Use TypeScript**: Even the `*.vue` files should use TypeScript ([reference](https://vuejs.org/guide/typescript/overview.html#usage-in-single-file-components)). ## Contributing Features When contributing features, these points should be ensured: ### Invisible until Required We strive to make Frappe Books as easy and simple to use as possible, and Progressive Disclosure is one of the design patterns that enables us to do this. - **Big Features**: ensure that the feature should be hidden using feature flags unless needed by majority users. Example: inventory features are hidden until _Enable Inventory_ is checked in the Settings. - **Small Features**: ensure that they stay hidden until needed until the context is relevant. Example: extra fields in the Invoice Items table aren't shown unless the User clicks on the Edit Row button. Added feature should not silently alter existing functionality until the user is aware of it. ### Simple UI A few rules of thumb to follow if your contributions alters the UI. - Do not crowd the UI. - Ensure even spacing, most spacing and sizes are an even multiple of `1rem`. - Ensure vertical and horizontal alignment. For text ensure vertical baseline alignment. - Simple Labels, ideally just a single word. Avoid overflow and word-breaks. - Child tables should have at most 5 columns. Extra columns should should be jadded to the row edit form. This website: [anthonyhobday.com/sideprojects/saferules](https://anthonyhobday.com/sideprojects/saferules/) contains several safe rules to follow. If you're unsure of your design go through the list. Do not break them without judgement. ### Documentation and Tests We know documentation and tests are boring, but they're important and we need you to add them for large changes. - **Documentation**: If the feature being added requires an explanation then [documentation](https://docs.frappe.io/books/) should be updated in the [frappe/books_docs](https://github.com/frappe/books_docs) repository. _Add a link to the documentation PR in your feature PR._ - **Tests**: If your features alters business logic then tests should be added. ### PR Description All pull requests should have a meaningful and detailed description. The following things should be in mentioned in the description: - **What the change is** should be described in sufficient detail, _not_ a single line such as _"This PR adds `[some_feature]`"_. - **Screenshots** should be added if the change affects the UI. ## Writing Tests You should write tests. If your features alter business logic and there are no tests then it is imperative to write tests. Here are a few rules of thumb to ensure that the tests you're writing are meaningful: - **Test values that should have changed against expected change.** If values after an operation are not as expected, the tests should fail. - **Test values that shouldn’t have changed.** If values which shouldn’t have changed also change, the test should fail. - **Don’t alter previously written tests,** unless they’re failing due to changes in implementation. - **Don’t write tests for code that has already been tested,** unless you have reason to believe that they could have changed. - **Manually test your changes using the UI atleast once**. - Don’t write tests for the sake of writing tests. - Don’t write tests just cause you aren’t sure how something executes. - Write tests cause you want to ensure that something continues to execute in the way you intend for it to be executed. - Write tests cause manually clicking through the UI to check your changes is time-consuming and not feasibly repeatable. - Write tests to catch unaccounted-for edge cases, then write code to account for those edge cases.