As per as I see, there are three ways to make code changes
If the changes are generic, make the changes(fixing an issue or adding feature) and contribute the code back to community. In that way, you don’t have to maintain your custom changes
If the changes are very specific to your usecase
a) Create an app and make the changes in that app. In that way, you will not be mixing your changes with erpnext, frappe
b) Fork the repository(erpnext/frappe) and make the changes to your forked repository. You have the burden of rebasing your forked repo with the mainline code, so this is better avoided
The code changes are common to development and production environment, so it really doesn’t make much difference.