This document proposes improvements to demography functions, and explains some technical details.
All three functions, recruitment()
, mortality()
and growth()
, could be defined with less arguments and the same arguments. That would make the functions easier to use and easier to document. The removed arguments could be either dropped completely or transformed into a function on their own. For example, the argument mindbh
filters stems which dbh
is at least a given value; such filtering is useful in many other situations. If we extract it into its own function, if can be reused without the need of duplicating code inside each function that currently has the mindbh
argument. That way, a census would be filtered before it is passed to any demography function. That helps not only users but also code-readers to see more-obviously what’s going on.
If all demography functions have (almost) the same arguments [not the case now – growth()
has many more arguments], all demography functions could share the same documentation. That will help users to understand how each function relates to the oters, and also help the maintainers to keep the documentation synchronized [although roxygen2 provides tools for inheriting documentation].
Some arguments’ defaults may change to more conservative values. For example, mindbh = 10
is the current default; that may change to mindbh = NULL
, which conservatively includes all stems (even if excluding stems is common, in this case safety may be more important than comfort).
If time allows all demography functions shown here should be reviewed and either refactored to make them easier to maintain or completely rewritten (as we did with abundance()
, basal_area()
and biomass()
).
The single biggest way to improve both the quality of your code and your productivity isto reuse good code.
― from “Code Complete (Developer Best Practices)” (https://goo.gl/83hsHb)
The forestr package evolves from the CTFS R Package (http://ctfs.si.edu/Public/CTFSRPackage/). In general, functions in forestr and the CTFS R Package may or may not share the same names or code. But the functions shown here, in particular, are almost identical to those in the CTFS R Package, both in name and code. While small, the changes in forestr make the functions considerably more reliable: They provide more informative warnings and when inputs are wrong they throw clearer error messages. The differences may become bigger with time, but now, by reusing big chunks of code from the CTFS R Package, users can get good a number of useful futures relatively quickly.
That gain in development-speed comes at a cost: With the inherited code comes inherited complexity. Consider the functions used here. The following three figures show that recruitment()
and mortality()
depend on just a few functions, but the dependencies of growth()
are many more.
recruitment()
:mortality()
:growth()
:While reducing code complexity is central to developing good software, providing users with the functionality they need is arguably the priority. Taking time into account, I propose to add the most important features first and to reduce the system’s complexity second – maybe after we release first version.