Thanks for considering contributing to {gsDesign2}! We welcome your Pull Requests to improve our software. For potentially larger changes, we advise first opening an Issue to discuss the new feature.
For more information on the organization of the package, please see the article Overview of package architecture.
Style Guide
Goals
The overall goal of the style guide:
- User experience: ensure a consistent API and syntax with minimal surprises for using our software.
- Developer experience: minimize time and cost to make consistent interface design decisions for developing our software.
Ultimately, the style guide should help us
- Support a healthy coexistence of user-facing, functional API, and low-level, object-oriented API.
- Create balanced alignment with the style and best practices presented in other high-quality research software.
- Build a universe of software for clinical trial design at scale.
Package names
General principles for deciding the name of a package:
- Prefer lower case
- Use dot (
.) to indicate a collection of extension packages. Examples include the “gamlss” packages and the “future” packages. - Can be easily searched and found using search engines.
- Follow existing conventions, even if they don’t agree with the rules above. Examples include gsDesign and gsDesign2.
Note that the package name and the product name can be stylized differently. Example: tensorflow vs. TensorFlow.
Functional API
All user-facing interactions should have a functional API.
Object-oriented API
Object-oriented API should be selectively used for low-level abstractions and limited cases in user-facing interactions when appropriate.
Classes
Class names defined under an OOP system, for example, S3 or R7, should use UpperCamelCase.
This rule intends to indicate the “function” is a class constructor, instead of a (regular) exported or internal function and follows the conventions in R6.
The input argument names and variable names should still use snake_case.
# Good
RangedDoubleOrNULL <- new_class(
"RangedDoubleOrNULL",
properties = list(
value = class_any,
min = class_double,
max = class_double,
min_closed = class_logical,
max_closed = class_logical
),
...
)
# Bad
ranged_double_or_null <- new_class(
"ranged_double_or_null",
properties = list(
value = class_any,
min = class_double,
max = class_double,
min_closed = class_logical,
max_closed = class_logical
),
...
)Arguments
Argument order
Arguments should be arranged in the order of data, descriptors, details.
This style makes it natural to consistently create chainable operations that form a workflow under either a functional API or object-oriented API, with minimal surprises.
# Functional API
design <- create_design(enroll_rates, fail_rates, ...)
design |>
do_compute_1(detail_1 = ...) |>
do_compute_2(detail_2 = ...)
# Object-oriented API
design <- Design(enroll_rates, fail_rates, ...)
design$do_compute_1(detail_1 = ...)$do_compute_2(detail_2 = ...)This suggests that if the “data” argument requires multiple inputs, create another function to bundle them as a single object and pass it to the function of interest.
Required and optional arguments
Required arguments should not have a default value. In contrast, optional arguments should have a default value.
Enumerated type arguments
Use lower case abbreviations or snake_case for the enumerated type arguments.
# Bad
f <- function(method = c("AHR", "WLR", ...)) {}
# Good
f <- function(method = c("ahr", "wlr", ...)) {}
# Bad
f <- function(approx = c("event driven", "asymptotic", "generalized schoenfeld", ...)) {}
# Good
f <- function(approx = c("event_driven", "asymptotic", "generalized_schoenfeld", ...)) {}The reasoning behind this: the strings are used together with function names and argument names, using snake_case would create a visual consistency.
Whenever possible, set the default value of an enumerated type input in the argument definition. See enumerate possible options.
Code formatting
R code should be formatted using styler with the default tidyverse style.
C/C++ code should be formatted using clang-format. This is doable via the Visual Studio Code C++ extension.
The code formatting can be automatically checked in CI/CD workflows.
