From 869e8f7d8ffc61f30e7ba0ac3e2e6eb99a56f6b8 Mon Sep 17 00:00:00 2001 From: Alessandro Gasparini Date: Tue, 19 Aug 2025 08:15:19 +0200 Subject: [PATCH 1/5] Edits to all chapters for consistency --- slides/01_intro.qmd | 16 ++- slides/02_r_packages.qmd | 97 ++++++++--------- slides/03_quality.qmd | 217 ++++++++++++++------------------------ slides/05_publication.qmd | 102 ++++++++---------- slides/06_conclusion.qmd | 11 +- 5 files changed, 176 insertions(+), 267 deletions(-) diff --git a/slides/01_intro.qmd b/slides/01_intro.qmd index 524f825..cdf5798 100644 --- a/slides/01_intro.qmd +++ b/slides/01_intro.qmd @@ -10,12 +10,12 @@ author: Audrey T. Yeo {{< include _disclaimer.qmd >}} -## Welcome to GSWEP4R at the ISCB46 ! +## Welcome to GSWEP4R at ISCB46! \ \ -_We have an open source spirit here. Please sit with someone you do not already know_ +_We have an open source spirit here. Please sit with someone you do not already know._ \ @@ -33,7 +33,7 @@ Be Curious. Be Respectful. Be Kind. ::: {.column width="70%"} - M Sci Biostatistics (Zurich), M Nursing (Sydney) - Currently : Founder of [Finc-Research](https://finc-research.com) -- Previously : Master Thesis in Longitudinal Cluster Analysis, Biostatistician at Roche for 4 years, Paeds / Onc RN from Melbourne, Australia +- Previously : Master Thesis in Longitudinal Cluster Analysis, Biostatistician at Roche for 4 years, Paeds / Onc RN from Melbourne, Australia - Lead developer of `phase1b` package, Bayesian Framework for Clinical Trials and `openstatsware` member - Enjoys developing statistical software, especially writing tests @@ -144,7 +144,7 @@ readr::read_csv("resources/program.csv", col_types = "cc") |> ## What do we mean by GSWEP4R\*? ::: aside -\* Good Software Engineering Practice for R +\* Good Software Engineering Practice for R Packages ::: - Applying concept of "Good XYZ Practice" to SWE with R @@ -155,7 +155,7 @@ readr::read_csv("resources/program.csv", col_types = "cc") |> ## Why care about GSWEP4R? -- R is one of the most successfull statistical programming languages +- R is one of the most successful statistical programming languages - R is a powerful yet complex *ecosystem* - Core component: R packages - Mature user & contributor community @@ -262,13 +262,11 @@ knitr::include_graphics("resources/pkg_graph.png") - shareable - easier to document -# Extra motivation for today's course : +# Extra motivation for today's course: check out the [diversity alliance hackathon on Sep 30](https://www.linkedin.com/posts/open-source-in-pharma_diversity-alliance-hackathon-rpharma-activity-7355688433186422784-XDpd/?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAm-hUYBK6599wxUyoAYIPTNW2hexCikETs) and see if you can apply today's learned skills there! - -# Question, Comments? - +# Question, comments? # License information {.smaller} diff --git a/slides/02_r_packages.qmd b/slides/02_r_packages.qmd index 7c1ae30..fa54a47 100644 --- a/slides/02_r_packages.qmd +++ b/slides/02_r_packages.qmd @@ -11,26 +11,24 @@ author: Alessandro Gasparini # Introduction -## What You Know Already +## What you know already -- Packages provide a mechanism for loading optional code, data, and - documentation +- Packages provide a mechanism for loading optional code, data, and documentation - A library is a directory into which packages are installed - `install.packages()` is used to install packages into the library - `library()` is used to load and attach packages from the library - - "Attach" means that the package is put in your `search` list --- objects in - the package can be used directly + - "Attach" means that the package is put in your `search` list --- objects in the package can be used directly - Remember that **package $\neq$ library** -## What We Want to Talk About Now +## What we want to talk about now - How to write, build, test, and check your own package `r emoji::emoji("blush")` - How to do this in a methodical and sustainable way - Give tips and tricks based on practical experience -# Contents of a Package +# Contents of a package -## How is a Package Structured? +## How is a package structured? Package source = directory with files and subdirectories @@ -54,7 +52,7 @@ Package source = directory with files and subdirectories ::: ::: -## How to Get Started Quickly +## How to get started quickly Once upon a time, developers would set up this structure manually `r emoji::emoji("yawning_face")` @@ -65,7 +63,7 @@ Nowadays, it's super fast with: ![](resources/rstudio-rpackage.png){.r-stretch} -## `DESCRIPTION` File +## `DESCRIPTION` file - *Package*: Choose the name of your package - Not unimportant! @@ -76,7 +74,7 @@ Nowadays, it's super fast with: - *Authors@R*: Add authors and maintainer - *Description*: Like an abstract, including references -## `DESCRIPTION` File (cont'd) +## `DESCRIPTION` file (cont'd) - *License*: Important for open sourcing - Consider permissive licenses such as Apache and MIT @@ -88,7 +86,7 @@ Nowadays, it's super fast with: - *Suggests*: Packages for documentation processing (`roxygen2`), running examples, tests (`testthat`), vignettes -## `R` Folder +## `R` folder - Only contains R code files (recommended to use `.R` suffix) - Can create a file with `usethis::use_r("filename")` @@ -105,7 +103,7 @@ Nowadays, it's super fast with: NULL ``` -## `NAMESPACE` File +## `NAMESPACE` file ```{r} #| echo: true @@ -118,13 +116,12 @@ export(package_used_second) export(package_used_third) ``` -- Defines the namespace of the package, to work with R's namespace management - system +- Defines the namespace of the package, to work with R's namespace management system - Namespace directives in this file allow to specify: - Which objects are exported to users and other packages - Which are imported from other packages -## `NAMESPACE` File (cont'd) +## `NAMESPACE` file (cont'd) - Controls the search strategy for variables: 1. Local (in the function body etc.) @@ -133,34 +130,28 @@ export(package_used_third) 4. Base namespace 5. Normal `search()` path -## `man` Folder +## `man` folder -- Contains documentation files for the objects in the package in the `.Rd` - format +- Contains documentation files for the objects in the package in the `.Rd` format - The syntax is a bit similar to `LaTeX` - All user level objects should be documented - Internal objects don't need to be documented --- but I recommend it! -- Once upon a time, developers would set up these `.Rd` files and the - `NAMESPACE` manually `r emoji::emoji("yawning_face")` +- Once upon a time, developers would set up these `.Rd` files and the `NAMESPACE` manually `r emoji::emoji("yawning_face")` - Fortunately, nowadays we have `roxygen2`! `r emoji::emoji("rocket")` -## `roxygen2` to the Rescue! +## `roxygen2` to the rescue! -- We can include the documentation source directly in the R script on top of - the objects we are documenting -- Syntax is composed of special comments `#'` and special macros preceded with - `@` -- In RStudio, running Build > More > Document will render the `.Rd` files and - the `NAMESPACE` file for you +- We can include the documentation source directly in the R script on top of the objects we are documenting +- Syntax is composed of special comments `#'` and special macros preceded with `@` +- In RStudio, running Build > More > Document will render the `.Rd` files and the `NAMESPACE` file for you - Get started with `usethis::use_roxygen_md()` -- Placing your cursor inside a function in RStudio, create a `roxygen2` skeleton - with Code > Insert Roxygen Skeleton +- Placing your cursor inside a function in RStudio, create a `roxygen2` skeleton with Code > Insert Roxygen Skeleton ## Setting up `roxygen2` in your project ![](resources/roxygen2-setting.png){.r-stretch} -## `roxygen2` Source +## `roxygen2` source `R/my_sum.R`: @@ -187,7 +178,7 @@ my_sum <- function(x, y) { } ``` -## `roxygen2` Output +## `roxygen2` output `man/my_sum.Rd`: @@ -222,7 +213,7 @@ my_sum(1, 2) } ``` -## `roxygen2` Output (cont'd) +## `roxygen2` output (cont'd) `NAMESPACE`: @@ -232,7 +223,7 @@ my_sum(1, 2) export(my_sum) ``` -## `tests` Folder +## `tests` folder - Where store the unit tests covering the functionality of the package - Get started with `usethis::use_testthat()` and `usethis::use_test()` and @@ -241,7 +232,7 @@ export(my_sum) into R scripts directly in `tests` directory - We will look at unit tests in detail later -## `data` Folder +## `data` folder - For (example) data that you ship in your package to the user - Get started with `usethis::use_data()` @@ -250,7 +241,7 @@ export(my_sum) - If you generate the example data, save the R script, too - Put that into `data-raw` folder, start with `usethis::use_data_raw()` -## `inst` Folder +## `inst` folder - Contents will be copied recursively to installation directory - Be careful not to interfere with standard folder names @@ -261,7 +252,7 @@ export(my_sum) - Create it with `usethis::use_citation()` - `inst/doc` can contain documentation files (typically `pdf`) -## `src` Folder +## `src` folder - Contains sources and headers for any code that needs compilation - Should only contain a single language here @@ -272,7 +263,7 @@ export(my_sum) - Wrapping existing libraries for use in R - Speeding up complex or long computations -## `vignettes` Folder +## `vignettes` folder - Special case of documentation files (`pdf` or `html`) created by compiling source files @@ -283,7 +274,7 @@ export(my_sum) - Important for the user to understand the high-level ideas - Complements function-level documentation from our `roxygen2` chunks -## `NEWS` File +## `NEWS` file - Lists user-visible changes worth mentioning - In each new release, add items at the top under the version they refer to @@ -323,9 +314,10 @@ License: Artistic-2.0 | AGPL-3 + file LICENSE - The optional file `LICENSE`/`LICENCE` contains a copy of the license - Only include such a file if it is referred to in the `License` field -## Adding a license to your package +## Adding a license to your package {.scrollable} - Once again, functions from the usethis package simplify this process + - Possible options: - `usethis::use_mit_license(copyright_holder = NULL)` - `usethis::use_gpl_license(version = 3, include_future = TRUE)` @@ -336,18 +328,17 @@ License: Artistic-2.0 | AGPL-3 + file LICENSE - `usethis::use_ccby_license()` - `usethis::use_proprietary_license(copyright_holder)` -# Building the Package +# Building the package -## Documenting the Package +## Documenting the package - The first step is to produce the documentation files and `NAMESPACE` - In RStudio: Build > More > Document - In the console: `devtools::document()` -## Checking the Package +## Checking the package -- R comes with pre-defined check command for packages: - "the R package checker" aka `R CMD check` +- R comes with pre-defined check command for packages: "the R package checker" aka `R CMD check` - About 22 checks are run (so quite a lot), including things like: - Can the package be installed? - Is the code syntax ok? @@ -357,7 +348,7 @@ License: Artistic-2.0 | AGPL-3 + file LICENSE - In RStudio: Build > Check - In the console: `devtools::check()` -## Building the Package +## Building the package - The R package folder can be compressed into a single package file - Typically we manually only build "source" package @@ -365,20 +356,18 @@ License: Artistic-2.0 | AGPL-3 + file LICENSE - In the console: `devtools::build()` - Makes it easy to share the package with others and submit to CRAN -## Installing the Package +## Installing the package -- R comes with pre-defined install command for packages: - `R CMD INSTALL` +- R comes with pre-defined install command for packages: `R CMD INSTALL` - In RStudio: Build > Install - In the console: `devtools::install()` -- Note: During development it's usually sufficient to use Build > More > Load - All +- Note: During development it's usually sufficient to use Build > More > Load All - Runs `devtools::load_all()` - Roughly simulates what happens when package would be installed and loaded - **Unexported** objects and helpers under `tests` will also be available - Key: much faster! -## Keyboard Shortcuts +## Keyboard shortcuts - Learning a few keyboard shortcuts can speed up many of the tasks we introduced in this lecture: @@ -389,7 +378,7 @@ readr::read_csv(here::here("slides/resources/keyboard-shortcuts.csv"), col_types knitr::kable(align = "ccc") ``` -- There are many more – check the [RStudio IDE Documentation](https://docs.posit.co/ide/user/ide/reference/shortcuts.html) +- There are many more – check for instance the [RStudio IDE Documentation](https://docs.posit.co/ide/user/ide/reference/shortcuts.html) # Exercise @@ -405,7 +394,7 @@ readr::read_csv(here::here("slides/resources/keyboard-shortcuts.csv"), col_types 1. Run checks 1. Build the package -> We will be using this package throughout the day! +$\leadsto$ We will be using this package throughout the day! # References diff --git a/slides/03_quality.qmd b/slides/03_quality.qmd index 5ec5977..ab7b381 100644 --- a/slides/03_quality.qmd +++ b/slides/03_quality.qmd @@ -9,12 +9,11 @@ author: Daniel Sabanés Bové {{< include _disclaimer.qmd >}} -# Quality by Design: Recommended Workflow +# Quality by design: recommended workflow -![[Photo CC0 by Kateryna Babaieva on -pexels.com]{.copyright}](thumbnails/workflow3.jpg){fig-align="center"} +![[Photo CC0 by Kateryna Babaieva on pexels.com]{.copyright}](thumbnails/workflow3.jpg){fig-align="center"} -# Suggestion for a High Quality Workflow +# Suggestion for a high quality workflow 1. Idea 2. Design docs @@ -23,10 +22,9 @@ pexels.com]{.copyright}](thumbnails/workflow3.jpg){fig-align="center"} 5. Publication (see later today) 6. Use in production -## Example - Step 1: Idea +## Example - step 1: idea -Let's assume that you used some lines of code to create simulated data in -multiple projects: +Let's assume that you used some lines of code to create simulated data in multiple projects: ```{r, echo = TRUE} dat <- data.frame( @@ -40,7 +38,7 @@ dat <- data.frame( Idea: put the code into a package -## Example - Step 2: Design docs +## Example - step 2: design docs 1. Describe the purpose and scope of the package 2. Analyse and describe the requirements in clear and simple terms ("prose") @@ -58,7 +56,7 @@ Idea: put the code into a package (5. Ed.). Carl Hanser Verlag GmbH & Co. KG.](https://amzn.to/3DdwiBe) [^9]: [Shall and must - plainlanguage.gov](https://www.plainlanguage.gov/guidelines/conversational/shall-and-must/) -## Example - Step 2: Design docs +## Example - step 2: design docs **Purpose and Scope** @@ -66,14 +64,13 @@ The R package *simulatr* is intended to enable the creation of reproducible fake **Package Requirements** -*simulatr* **must** provide a function to generate normal distributed random -data for two independent groups. The function **must** allow flexible -definition of sample size per group, mean per group, standard deviation per -group. The reproducibility of the simulated data **must** be ensured via an -optional seed. It **should** be possible to print the function result. The -package **may** also facilitate graphical presentation of the simulated data. +*simulatr* **must** provide a function to generate normal distributed random data for two independent groups. +The function **must** allow flexible definition of sample size per group, mean per group, standard deviation per group. +The reproducibility of the simulated data **must** be ensured via an optional seed. +It **should** be possible to print the function result. +The package **may** also facilitate graphical presentation of the simulated data. -## Example - Step 2: Design docs +## Example - step 2: design docs ::: columns ::: {.column width="45%"} @@ -102,7 +99,7 @@ UML Diagram [^5]: A picture is worth a thousand words -## Example - Step 3: Packaging +## Example - step 3: packaging **R package programming** @@ -111,21 +108,17 @@ UML Diagram 3. Create R generic functions 4. Document all functions -# Apply Clean Code Rules +# Apply clean code rules ![](thumbnails/code_view.jpg){fig-align="center"} -## Why is Clean Code important? +## Why is clean code important? -- **Maintainability**: The code is readable and understandable and has a - reduced complexity, i.e., it's easier to fix bugs -- **Extensibility**: The architecture is simpler, cleaner, and more - expressive, i.e., it's easier to extend the capabilities and the risk of - introducing bugs is reduced -- **Performance**: The code often runs faster, uses less memory, or is easier - to optimize +- **Maintainability**: The code is readable and understandable and has a reduced complexity, i.e., it's easier to fix bugs +- **Extensibility**: The architecture is simpler, cleaner, and more expressive, i.e., it's easier to extend the capabilities and the risk of introducing bugs is reduced +- **Performance**: The code often runs faster, uses less memory, or is easier to optimize -## Example: Clean Code Rules - Step by Step +## Example: clean code rules - step by step This script breaks all common clean code rules: @@ -230,8 +223,7 @@ getMeanAndMedian <- function(x) { ::: {.column width="32%"} CCR#2 **Formatting** [{{< fa circle-check size=1x >}}]{.green} -CCR#3 **Simplicity**: Did you keep the code as simple and straightforward as -possible, i.e., did you avoid unnecessary complexity +CCR#3 **Simplicity**: Did you keep the code as simple and straightforward as possible, i.e., did you avoid unnecessary complexity [{{< fa circle-question size=1x >}}]{.red} ::: ::: @@ -240,10 +232,8 @@ possible, i.e., did you avoid unnecessary complexity Note: -- From the **Simplicity** rule also follows that large source files should be - split into multiple files -- General guideline: keeping the number of lines to less than 1,000 lines per - file can help maintain code readability and manageability +- From the **Simplicity** rule also follows that large source files should be split into multiple files +- General guideline: keeping the number of lines to less than 1,000 lines per file can help maintain code readability and manageability ## Example: CCR#3 @@ -262,8 +252,7 @@ getMeanAndMedian <- function(x) { CCR#3 **Simplicity** [{{< fa circle-check size=1x >}}]{.green} -CCR#4 **Single Responsibility Principle (SRP)**: does each function have only a single, -well-defined purpose [{{< fa circle-question size=1x >}}]{.red} +CCR#4 **Single Responsibility Principle (SRP)**: does each function have only a single, well-defined purpose [{{< fa circle-question size=1x >}}]{.red} ## Example: CCR#4 @@ -288,8 +277,7 @@ getMedian <- function(x) { CCR#4 **Single Responsibility Principle (SRP)** [{{< fa circle-check size=1x >}}]{.green} -CCR#5 **Don't Repeat Yourself (DRY)**: Did you avoid duplication of code, either -by reusing existing code or creating functions +CCR#5 **Don't Repeat Yourself (DRY)**: Did you avoid duplication of code, either by reusing existing code or creating functions [{{< fa circle-question size=1x >}}]{.red} ## Example: CCR#5 @@ -341,8 +329,7 @@ getMedian <- function(x) { CCR#5 **Don't Repeat Yourself (DRY)** [{{< fa circle-check size=1x >}}]{.green} -CCR#6 **Comments**: Did you use comments to explain the purpose of code blocks -and to clarify complex logic [{{< fa circle-question size=1x >}}]{.red} +CCR#6 **Comments**: Did you use comments to explain the purpose of code blocks and to clarify complex logic [{{< fa circle-question size=1x >}}]{.red} ## Example: CCR#6 @@ -377,8 +364,7 @@ getMedian <- function(x) { ::: {.column width="40%"} CCR#6 **Comments** [{{< fa circle-check size=1x >}}]{.green} -CCR#7 **Error Handling**: Did you include error handling code to gracefully -handle exceptions and unexpected situations +CCR#7 **Error Handling**: Did you include error handling code to gracefully handle exceptions and unexpected situations [{{< fa circle-question size=1x >}}]{.red} ```{r, echo = TRUE, eval = FALSE} @@ -418,45 +404,33 @@ getMedian <- function(x) { CCR#7 **Error Handling** [{{< fa circle-check size=1x >}}]{.green} -## Summary of Clean Code Rules - -1. **Naming**: Use descriptive and meaningful names for variables, functions, - and classes -2. **Formatting**: Adhere to consistent indentation, spacing, and bracketing to - make the code easy to read -3. **Simplicity**: Keep the code as simple and straightforward as possible, - avoiding unnecessary complexity -4. **Single Responsibility Principle (SRP)**: Each function should have a - single, well-defined purpose -5. **Don't Repeat Yourself (DRY)**: Avoid duplication of code, either by - reusing existing code or creating functions - -## Summary of Clean Code Rules - -6. **Comments**: Use comments to explain the purpose of code blocks and to - clarify complex logic -7. **Error Handling**: Include error handling code to gracefully handle - exceptions and unexpected situations -8. [{{< fa star size=1x >}}]{.blue} **Test-Driven Development (TDD)**: Write - tests for your code to ensure it behaves as expected and to catch bugs early -9. **Refactoring**: Regularly refactor your code to keep it clean, readable, - and maintainable -10. [{{< fa star size=1x >}}]{.blue} **Code Review**: Have other team members - review your code to catch potential issues and improve its quality - -## How to apply Clean Code Rules? +## Summary of clean code rules + +1. **Naming**: Use descriptive and meaningful names for variables, functions, and classes +2. **Formatting**: Adhere to consistent indentation, spacing, and bracketing to make the code easy to read +3. **Simplicity**: Keep the code as simple and straightforward as possible, avoiding unnecessary complexity +4. **Single Responsibility Principle (SRP)**: Each function should have a single, well-defined purpose +5. **Don't Repeat Yourself (DRY)**: Avoid duplication of code, either by reusing existing code or creating functions + +## Summary of clean code rules + +6. **Comments**: Use comments to explain the purpose of code blocks and to clarify complex logic +7. **Error Handling**: Include error handling code to gracefully handle exceptions and unexpected situations +8. [{{< fa star size=1x >}}]{.blue} **Test-Driven Development (TDD)**: Write tests for your code to ensure it behaves as expected and to catch bugs early +9. **Refactoring**: Regularly refactor your code to keep it clean, readable, and maintainable +10. [{{< fa star size=1x >}}]{.blue} **Code Review**: Have other team members review your code to catch potential issues and improve its quality + +## How to apply clean code rules? Recommended quality workflow for R packages: - Follow the naming and styling guidelines (#1, #2) -- Continuously write tests and optimize the code coverage with help of tools - (#7, #8) +- Continuously write tests and optimize the code coverage with help of tools (#7, #8) - Document the package and functions (#6) - Regularly refactor your code (#1 - #7, #9) -- Publish your code on [GitHub](https://github.com) and invite colleagues to - contribute (#10) +- Publish your code on [GitHub](https://github.com) and invite colleagues to contribute (#10) -# Package Testing +# Package testing ::: clean-code-rule CCR#8: TDD @@ -464,7 +438,7 @@ CCR#8: TDD ![](thumbnails/testing.jpg){fig-align="center"} -## Verification vs Validation +## Verification vs validation ::: columns ::: {.column width="50%"} @@ -487,7 +461,7 @@ Are we building the right product? ::: ::: -## What are Unit Tests? +## What are unit tests? - Automated tests - Record the expected output of a function using code @@ -506,8 +480,7 @@ CCR#8: TDD - Ensure that changes to the codebase do not break existing functionality - Express the desired behavior in a way that a human can understand - Help to identify and fix bugs early on in the development process -- Save time and resources by catching issues before they become more difficult - and costly to fix +- Save time and resources by catching issues before they become more difficult and costly to fix ::: info-block ::: columns @@ -523,29 +496,21 @@ Unit tests help to increase the reliability and maintainability of the code ## What other important test types exist? -- **Integration Testing**: Test if different functions or scripts work - together as expected -- **Performance Testing**: Analyze the performance of the implemented - functions and check whether they meet the requirements (UR/UX) -- **Snapshot Testing**: Record the results in a separate human-readable file - and compare it to the output during the test; useful for large/complex - outputs and binary formats like plots +- **Integration Testing**: Test if different functions or scripts work together as expected +- **Performance Testing**: Analyze the performance of the implemented functions and check whether they meet the requirements (UR/UX) +- **Snapshot Testing**: Record the results in a separate human-readable file and compare it to the output during the test; useful for large/complex outputs and binary formats like plots -# Testing in Practice +# Testing in practice ![](thumbnails/coding_cottonbro-studio.jpg){fig-align="center"} - ## How to realize testing with R? R package [testthat](https://cran.r-project.org/package=testthat) - Popular testing framework for R that is easy to learn and use -- Unit testing, integration testing, and [snapshot - testing](https://cran.r-project.org/web/packages/testthat/vignettes/snapshotting.html) - supported -- Also performance testing, e.g., with help of - [microbenchmark](https://cran.r-project.org/package=microbenchmark) package +- Unit testing, integration testing, and [snapshot testing](https://cran.r-project.org/web/packages/testthat/vignettes/snapshotting.html) supported +- Also performance testing, e.g., with help of [microbenchmark](https://cran.r-project.org/package=microbenchmark) package **Example**: unit test passed @@ -603,7 +568,7 @@ expect_equal(getMean(c(1, 3, 2, NA)), 2) expect_equal(getMean(c(1, 3, 2, NA), na.rm = FALSE), NA_real_) ``` -## testthat Comparisons Functions (1/2) +## testthat comparisons functions (1/2) ::: small @@ -625,7 +590,7 @@ expect_equal(getMean(c(1, 3, 2, NA), na.rm = FALSE), NA_real_) | expect_named | return a vector with (given) names? | ::: -## testthat Comparisons Functions (2/2) +## testthat comparisons functions (2/2) ::: small @@ -649,19 +614,13 @@ expect_equal(getMean(c(1, 3, 2, NA), na.rm = FALSE), NA_real_) ## How to check the package quality? -- [pkgbuild](https://cran.r-project.org/package=pkgbuild): Tools needed to - build R packages -- [rcmdcheck](https://cran.r-project.org/package=rcmdcheck): Run [R CMD - check](https://r-pkgs.org/R-CMD-check.html) from R and capture results -- [devtools](https://cran.r-project.org/package=devtools): Tools to make - developing R packages easier, e.g., - [check()](https://rdrr.io/cran/devtools/man/check.html) automatically builds - and checks a source package, using all known best practices +- [pkgbuild](https://cran.r-project.org/package=pkgbuild): Tools needed to build R packages +- [rcmdcheck](https://cran.r-project.org/package=rcmdcheck): Run [R CMD check](https://r-pkgs.org/R-CMD-check.html) from R and capture results +- [devtools](https://cran.r-project.org/package=devtools): Tools to make developing R packages easier, e.g., [check()](https://rdrr.io/cran/devtools/man/check.html) automatically builds and checks a source package, using all known best practices ## How to improve the test coverage? -[covr](https://cran.r-project.org/package=covr): Track and report code coverage -for your package +[covr](https://cran.r-project.org/package=covr): Track and report code coverage for your package ```{r, echo = TRUE, eval = FALSE} library(covr) @@ -710,7 +669,7 @@ We can go into the details by clicking on a file name: ![](resources/covr_example_2.png) -# Code Style +# Code style ::: clean-code-rule CCR#2: Formatting @@ -718,7 +677,7 @@ CCR#2: Formatting ![](thumbnails/styling.jpg){fig-align="center"} -## Why is Code Style important? +## Why is code style important? ::: clean-code-rule CCR#2: Formatting @@ -726,32 +685,23 @@ CCR#2: Formatting - Make the code more readable, maintainable, and consistent - Make it easier for others to understand and contribute to the codebase -- Adhering to a consistent code style can reduce the number of errors and make - debugging simpler -- "Good coding style is like correct punctuation: you can manage without it, - butitsuremakesthingseasiertoread." ([The tidyverse style - guide](https://style.tidyverse.org)) +- Adhering to a consistent code style can reduce the number of errors and make debugging simpler +- "Good coding style is like correct punctuation: you can manage without it, butitsuremakesthingseasiertoread." ([The tidyverse style guide](https://style.tidyverse.org)) ## How to optimize the code styling? -Two popular R packages support the [tidyverse style -guide](https://style.tidyverse.org): +Two popular R packages support the [tidyverse style guide](https://style.tidyverse.org): -- [styler](https://styler.r-lib.org): interactively restyle selected text, - files, or entire projects: +- [styler](https://styler.r-lib.org): interactively restyle selected text, files, or entire projects: - [style_text](https://styler.r-lib.org/reference/style_text.html) - [style_file](https://styler.r-lib.org/reference/style_file.html) - [style_pkg](https://styler.r-lib.org/reference/style_pkg.html) -- [lintr](https://github.com/jimhester/lintr): perform automated checks to - confirm that you conform to the style guide -- [air](https://posit-dev.github.io/air/) : an R formatter that ensures whitespace, newlines, punctuations conform to a set of rules and standards +- [lintr](https://github.com/jimhester/lintr): perform automated checks to confirm that you conform to the style guide +- [air](https://posit-dev.github.io/air/) : an R formatter that ensures whitespace, newlines, punctuation conform to a set of rules and standards -The [devtools](https://devtools.r-lib.org) function -[spell_check](https://devtools.r-lib.org/reference/spell_check.html) runs a -spell check on text fields in the package description file, manual pages, and -optionally vignettes. +The [devtools](https://devtools.r-lib.org) function [spell_check](https://devtools.r-lib.org/reference/spell_check.html) runs a spell check on text fields in the package description file, manual pages, and optionally vignettes. -## Code Styler in RStudio +## Code styler in RStudio How to link the [styler](https://styler.r-lib.org)[^10] package to a keyboard shortcut: @@ -789,12 +739,10 @@ install.packages(c("DT", "htmltools", ::: panel-tabset ## Task 1 -Take your package project and refactor it, i.e., apply the linked -clean code rules: +Take your package project and refactor it, i.e., apply the linked clean code rules: 1. Optimize naming manually (CCR#1) -1. Use the [styler](https://styler.r-lib.org) package to optimize the - formatting (CCR#2) +1. Use the [styler](https://styler.r-lib.org) package to optimize the formatting (CCR#2) 1. Check and correct where appropriate: - Simplicity (CCR#3) - Single Responsibility Principle (CCR#4) @@ -803,28 +751,19 @@ clean code rules: ## Task 2 1. Add comments to explain the purpose of code blocks (CCR#6) - - If it concerns exported functions use - [Roxygen2](https://roxygen2.r-lib.org/) notation -1. Check correct spelling with the - [devtools](https://cran.r-project.org/package=devtools) function - [spell_check()](https://devtools.r-lib.org/reference/spell_check.html) + - If it concerns exported functions use [Roxygen2](https://roxygen2.r-lib.org/) notation +1. Check correct spelling with the [devtools](https://cran.r-project.org/package=devtools) function [spell_check()](https://devtools.r-lib.org/reference/spell_check.html) ## Task 3 Apply CCR#8 to your package project: 1. Add unit tests -1. Optimize your test coverage with help of the [covr](https://covr.r-lib.org/) - functions - [package_coverage](https://www.rdocumentation.org/packages/covr/versions/3.6.1/topics/package_coverage) - and - [report](https://www.rdocumentation.org/packages/covr/versions/3.6.1/topics/report) +1. Optimize your test coverage with help of the [covr](https://covr.r-lib.org/) functions [package_coverage](https://www.rdocumentation.org/packages/covr/versions/3.6.1/topics/package_coverage) and [report](https://www.rdocumentation.org/packages/covr/versions/3.6.1/topics/report) ## Task 4 -Check if your package is ready for release with the -[devtools](https://cran.r-project.org/package=devtools) function -[check()](https://rdrr.io/cran/devtools/man/check.html) +Check if your package is ready for release with the [devtools](https://cran.r-project.org/package=devtools) function [check()](https://rdrr.io/cran/devtools/man/check.html) ::: # References diff --git a/slides/05_publication.qmd b/slides/05_publication.qmd index 3deaf29..440b5cc 100644 --- a/slides/05_publication.qmd +++ b/slides/05_publication.qmd @@ -42,25 +42,23 @@ Source: the [`mmrm`](https://github.com/openpharma/mmrm/blob/main/_pkgdown.yml) ## {background-iframe="https://openpharma.github.io/mmrm/latest-tag/reference/index.html" background-interactive="true"} -## Publication as GitHub Page +## Publication as GitHub page - It's helpful for users to read the website online - GitHub is very helpful here because: - A separate branch, `gh-pages`, stores the rendered website - - GitHub actions automatically render the website when the `main` branch - is updated + - GitHub actions automatically render the website when the `main` branch is updated - To get started, use `usethis::use_pkgdown_github_pages()` - Or, manually deploy site with `pkgdown::deploy_to_branch()` ## {background-iframe="https://openpharma.github.io/mmrm/latest-tag/" background-interactive="true"} -# Licensing, Open Sourcing, Versioning +# Licensing, open sourcing, versioning ## Licensing - High level categorization of licenses: - - "Permissive": Relaxed. Can be freely copied, modified, published (under the - same license). + - "Permissive": Relaxed. Can be freely copied, modified, published (under the same license). - "Copyleft": Stricter. Same rights need to be preserved in derivative works. - Helpful tool: - R itself is licensed under GPL, but packages can choose, e.g.: @@ -71,8 +69,7 @@ Source: the [`mmrm`](https://github.com/openpharma/mmrm/blob/main/_pkgdown.yml) ## Licensing (cont'd) - Need to be careful here when you bundle any code from other software - - Care must be taken that any copyright/license statements from copied or - modified code are preserved and authorship is not misrepresented + - Care must be taken that any copyright/license statements from copied or modified code are preserved and authorship is not misrepresented - Are the licenses of your package and the source compatible? - e.g. cannot copy/paste code from a GPL package and publish in an MIT package - `LICENSE` file optionally can contain further restrictions of the license @@ -86,15 +83,14 @@ Source: the [`mmrm`](https://github.com/openpharma/mmrm/blob/main/_pkgdown.yml) - The consequence is that you cannot copy, distribute, modify other people's contributions to your project - Even if unlicensed code is published in a public repository, as a user, you generally don't have the permission from the creators of the software to use, modify, or share the software -## Open Sourcing +## Open sourcing - The easiest way to "open source" your R package is to make the GitHub/code repository public - This allows for easy open source contributions from other developers via pull requests - Please check with your organization first: - Are they ok to publish the software? - What is the appropriate copyright holder? -- Also allows bugs to be filed and to have - the GitHub issues page in the package description +- Also allows bugs to be filed and to have the GitHub issues page in the package description ## Versioning @@ -110,13 +106,12 @@ Source: the [`mmrm`](https://github.com/openpharma/mmrm/blob/main/_pkgdown.yml) -# Checks Before Release +# Checks before release ## CRAN (The Comprehensive R Archive Network) - CRAN is the central repository for R packages -- It has additional requirements beyond the standard package ones, which are - described in the Repository Policy +- It has additional requirements beyond the standard package ones, which are described in the Repository Policy - Submitting a package indicates agreement with the policy - In particular: "The time of the volunteers is CRAN’s most precious resource, and they reserve the right to remove or modify packages on CRAN without notice or explanation (although notification will usually be given)." @@ -136,22 +131,18 @@ Source: the [`mmrm`](https://github.com/openpharma/mmrm/blob/main/_pkgdown.yml) `r emoji::emoji("exclamation")` A CRAN submission can be punishing, painful, and nerve-racking: -The first release of the [rpact](https://cran.r-project.org/package=rpact) -package took 5 weeks and 6 submission attempts; painful experiences: +The first release of the [rpact](https://cran.r-project.org/package=rpact) package took 5 weeks and 6 submission attempts. +Painful experiences: -- Some Linux machines may generate different random numbers than expected - (despite setting a seed) -- Not only errors and warnings lead to the rejection of a submitted package, - but also notes -- Your local Windows test system may be much faster than the CRAN system - (e.g., 5 times) +- Some Linux machines may generate different random numbers than expected (despite setting a seed) +- Not only errors and warnings lead to the rejection of a submitted package, but also notes +- Your local Windows test system may be much faster than the CRAN system (e.g., 5 times) - Don't use "R Package for" in your package title - The description of the package must be provided with a DOI reference ## CRAN (cont'd) {.scrollable} -Example message informing about the rejection of the last -[rpact](https://cran.r-project.org/package=rpact) submission: +Example message informing about the rejection of the last [rpact](https://cran.r-project.org/package=rpact) submission: > Dear maintainer, > @@ -174,7 +165,7 @@ Example message informing about the rejection of the last > r-devel-linux-x86_64-debian-gcc Check: Result: Note_to_CRAN_maintainers > Maintainer: 'Friedrich Pahlke' -## R-Hub to the Rescue +## R-Hub to the rescue ::: columns ::: {.column width="30%"} @@ -191,7 +182,7 @@ Typically used via the [website](https://builder.r-hub.io/) ::: ::: -## R-Hub Platforms +## R-Hub platforms ```{r} #| echo: true @@ -199,13 +190,13 @@ library(rhub) rhub::rhub_platforms() ``` -## GitHub Actions +## GitHub actions - It is also possible to use [GitHub Actions](https://docs.github.com/en/actions) to run `R CMD check` - Free for public repositories, paid service for private repositories - Checks will be run every time someone pushes a commit to a repository hosted on GitHub - Easy setup from your R console: `usethis::use_github_action_check_standard()` - - ( runs a standard `R CMD check ` on three major operating systems. ) + - This runs a standard `R CMD check ` on three major operating systems - Script and documentation are developed and maintained by the `r-lib` organization [here](https://github.com/r-lib/actions/tree/v2/check-r-package) # GitHub @@ -215,30 +206,27 @@ rhub::rhub_platforms() - Tags are a feature of Git, i.e., not specific to GitHub - Git can tag (or "bookmark") specific points in the code history as being important - Typically, for each release, create a tag `vx.y.z` (MAJOR.Minor.patch format) -- The value here is that users can later check out the package - in the state of this release version +- The value here is that users can later check out the package in the state of this release version - Download in R: `remotes::install_github("org/package", ref = "vx.y.z")` - Comparison of versions are also possible, etc. -## Tags: Example +## Tags: example ![](resources/tags.png) ## Releases - [Releases](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases) are based on Git tags, and a feature of GitHub -- Are "deployable software packages to make them available for a wider audience - to download and use" +- Are "deployable software packages to make them available for a wider audience to download and use" - Contain release notes and links to the binary package files for download - - However, for R packages these `tar.gz` package files are rarely used - directly - + - However, for R packages these `tar.gz` package files are rarely used directly + ```{Bash} #| eval: false git diff v0.3.14 v0.3.15 # checking for difference in mmrm release ``` -## Releases: Example +## Releases: example ![](resources/releases.png) @@ -246,14 +234,11 @@ git diff v0.3.14 v0.3.15 # checking for difference in mmrm release ## A Note on Bioconductor -- The [Bioconductor](https://www.bioconductor.org/) project develops, supports, - and disseminates open source software for the analysis of biological assays -- Like CRAN, Bioconductor has additional package requirements. - One can only submit either to CRAN or Bioconductor. +- The [Bioconductor](https://www.bioconductor.org/) project develops, supports, and disseminates open source software for the analysis of biological assays +- Like CRAN, Bioconductor has additional package requirements: one can only submit either to CRAN or Bioconductor - Packages are peer reviewed by community members - New packages and updates to existing packages are released semi-annually -- Software is expected to be interoperable with other Bioconductor packages - through the re-use of common data structures and infrastructure +- Software is expected to be interoperable with other Bioconductor packages through the re-use of common data structures and infrastructure # References @@ -264,52 +249,52 @@ git diff v0.3.14 v0.3.15 # checking for difference in mmrm release - [CRAN Repository Policy](https://cran.r-project.org/web/packages/policies.html) - [Bioconductor packages](https://contributions.bioconductor.org/index.html) -## Quick quiz (One correct answer only){.smaller} +## Quick quiz (one correct answer only){.smaller} ::: columns ::: {.column width="45%"} -1. I am cloning / forking a repo that has an MIT Licence. Which license shall I use if I want to make modification and distribute my new package ? +1. I am cloning / forking a repo that has an MIT Licence. Which license shall I use if I want to make modification and distribute my new package? a. MIT Licence -b. any licence -c. no licence assumes transfer of my rights from the original repo +b. Any licence +c. No licence assumes transfer of my rights from the original repo ::: ::: {.column width="5%"} ::: ::: {.column width="45%"} -2. I want to build a website for my package. Which file can I *mainly* configure my website in ? +2. I want to build a website for my package. Which file can I *mainly* configure my website in? \ \ \ \ a. `_pkgdown.yml` file b. .gitignore -c. any .Rd file +c. Any .Rd file ::: ::: -## Quick quiz (Solutions) +## Quick quiz (solutions) ::: columns ::: {.column width="40%"} -1. I am cloning / forking a repo that has an MIT Licence. Which license shall I use if I want to make modification and distribute my new package ? +1. I am cloning / forking a repo that has an MIT Licence. Which license shall I use if I want to make modification and distribute my new package? a. MIT Licence -b. **any licence** -c. no licence because that assumes transfer of my rights from the original repo's MIT Licence +b. **Any licence** +c. No licence because that assumes transfer of my rights from the original repo's MIT Licence ::: ::: {.column width="10%"} ::: ::: {.column width="40%"} -2. I want to build a website for my package. Which file can I *mainly* configure my website in ? +2. I want to build a website for my package. Which file can I *mainly* configure my website in? \ \ \ a. **`_pkgdown.yml` file** b. .gitignore -c. any .Rd file +c. Any .Rd file ::: ::: @@ -317,7 +302,7 @@ c. any .Rd file Use your project from *chapter 2* : -- Run CRAN-like checks in RStudio: +- Run CRAN-like checks in RStudio: - Go to Tools -> Project Options -> Build Tools -> "Check package - R CMD check additional options" : -> type "--as-cran" - Alternatively, use `--as-cran` in argument in console : @@ -343,8 +328,7 @@ rcmdcheck::rcmdcheck("myrootdir", args = "--as-cran") - In the current version, changes were done by (later authors): Liming Li [`r fontawesome::fa("github")`](https://github.com/clarkliming), Philippe Boileau [`r fontawesome::fa("globe")`](https://pboileau.ca/), - Alessandro Gasparini [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/ellessenne) [`r fontawesome::fa("github")`](https://www.github.com/ellessenne) [`r fontawesome::fa("globe")`](https://www.ellessenne.xyz/), Audrey Yeo Te-ying - [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/audreyyeo8000/) - [`r fontawesome::fa("github")`](https://github.com/audreyyeocH) + Alessandro Gasparini [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/ellessenne) [`r fontawesome::fa("github")`](https://www.github.com/ellessenne) [`r fontawesome::fa("globe")`](https://www.ellessenne.xyz/), + Audrey Yeo Te-ying [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/audreyyeo8000/) [`r fontawesome::fa("github")`](https://github.com/audreyyeocH) {{< include _license_footer.qmd >}} diff --git a/slides/06_conclusion.qmd b/slides/06_conclusion.qmd index 288f772..1c30ac8 100644 --- a/slides/06_conclusion.qmd +++ b/slides/06_conclusion.qmd @@ -35,7 +35,7 @@ TODO - Packaging a set of functions is an ideal way to share with collaborators and the public - Start small and simple and over time you can learn additional options -## Engineering Workflow +## Engineering workflow - Use a workable workflow:\ Idea $\rightarrow$ Design docs $\rightarrow$ Programming $\rightarrow$ Quality check $\rightarrow$ Publication @@ -46,7 +46,7 @@ TODO - Use assertions for all arguments $\rightarrow$ better user experience - Implement common generics like `print` and `plot` -## Ensuring Quality +## Ensuring quality - Apply common clean code rules, e.g., - Use [testthat](https://cran.r-project.org/package=testthat) to test, test, and test @@ -104,9 +104,8 @@ TODO # License information {.smaller} - Creators (initial authors): - Daniel Sabanés Bové - [`r fontawesome::fa("github")`](https://github.com/danielinteractive/) - [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/danielsabanesbove/), + Daniel Sabanés Bové [`r fontawesome::fa("github")`](https://github.com/danielinteractive/) [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/danielsabanesbove/), - In the current version, changes were done by (later authors): - TODO + Alessandro Gasparini [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/ellessenne) [`r fontawesome::fa("github")`](https://www.github.com/ellessenne) [`r fontawesome::fa("globe")`](https://www.ellessenne.xyz/), + {{< include _license_footer.qmd >}} From 68475b374840ab963a755f634b7956c1b88c9aab Mon Sep 17 00:00:00 2001 From: Alessandro Gasparini Date: Tue, 19 Aug 2025 09:28:16 +0200 Subject: [PATCH 2/5] Adjusted knitr engine --- slides/05_publication.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slides/05_publication.qmd b/slides/05_publication.qmd index 440b5cc..5fa44f3 100644 --- a/slides/05_publication.qmd +++ b/slides/05_publication.qmd @@ -221,7 +221,7 @@ rhub::rhub_platforms() - Contain release notes and links to the binary package files for download - However, for R packages these `tar.gz` package files are rarely used directly -```{Bash} +```{bash} #| eval: false git diff v0.3.14 v0.3.15 # checking for difference in mmrm release ``` From 080cd73e88442a750ca895517b8fa064b1e47180 Mon Sep 17 00:00:00 2001 From: Alessandro Gasparini Date: Tue, 19 Aug 2025 09:28:35 +0200 Subject: [PATCH 3/5] Licence -> license --- slides/02_r_packages.qmd | 2 +- slides/05_publication.qmd | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/slides/02_r_packages.qmd b/slides/02_r_packages.qmd index fa54a47..0780fce 100644 --- a/slides/02_r_packages.qmd +++ b/slides/02_r_packages.qmd @@ -288,7 +288,7 @@ export(my_sum) - We mentioned before that licensing information is usually included in the `DESCRIPTION` file - In fact, the `License` field (in standardized form) is mandatory - Licensing for a package which might be distributed is an important but potentially complex subject -- It is very important to include license information, as otherwise: +- It is very important to include licensing information, as otherwise: - It may not be possible to use it - It may not be possible to distribute copies of it - We are going to talk more about licensing in Chapter 5 later today diff --git a/slides/05_publication.qmd b/slides/05_publication.qmd index 5fa44f3..3065221 100644 --- a/slides/05_publication.qmd +++ b/slides/05_publication.qmd @@ -253,10 +253,10 @@ git diff v0.3.14 v0.3.15 # checking for difference in mmrm release ::: columns ::: {.column width="45%"} -1. I am cloning / forking a repo that has an MIT Licence. Which license shall I use if I want to make modification and distribute my new package? -a. MIT Licence -b. Any licence -c. No licence assumes transfer of my rights from the original repo +1. I am cloning / forking a repo that has an MIT license. Which license shall I use if I want to make modification and distribute my new package? +a. MIT license +b. Any license +c. No license because that assumes transfer of my rights from the original repo's MIT license ::: ::: {.column width="5%"} @@ -278,10 +278,10 @@ c. Any .Rd file ::: columns ::: {.column width="40%"} -1. I am cloning / forking a repo that has an MIT Licence. Which license shall I use if I want to make modification and distribute my new package? -a. MIT Licence -b. **Any licence** -c. No licence because that assumes transfer of my rights from the original repo's MIT Licence +1. I am cloning / forking a repo that has an MIT license. Which license shall I use if I want to make modification and distribute my new package? +a. MIT license +b. **Any license** +c. No license because that assumes transfer of my rights from the original repo's MIT license ::: ::: {.column width="10%"} From 40748209c1ff2d8c735ba64655bb8243fa2526af Mon Sep 17 00:00:00 2001 From: Alessandro Gasparini Date: Tue, 19 Aug 2025 09:28:54 +0200 Subject: [PATCH 4/5] Updated index page with tools to compile packages from source code --- index.qmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.qmd b/index.qmd index a2ff3ae..ecfb5f9 100644 --- a/index.qmd +++ b/index.qmd @@ -59,7 +59,7 @@ Prior to the short course, participants should - Set up a (free) [GitHub.com account](https://github.com/join). - Note: There are other git platforms like [Gitlab](https://about.gitlab.com/) or [Bitbucket](https://bitbucket.org/), but we made the choice to go with GitHub.com for the course, since it is by far the most relevant git platform in the R community. - Install the latest [R](https://www.r-project.org/) and [RStudio](https://posit.co/download/rstudio-desktop/) software. -- Install [Rtools](https://cran.r-project.org/bin/windows/Rtools/rtools44/rtools.html) (only on Windows and optional if you want to try out Rcpp) +- Install [Rtools](https://cran.r-project.org/bin/windows/Rtools/rtools44/rtools.html) (on Windows) or the [required tools](https://mac.r-project.org/tools/) (on macOS) to compile/build packages from source code. - Install additional R packages using the [installation script](slides/download/install.R). For the course, participants are required to use their own laptop to be able to participate in the exercises. From 776f9ed5904f71d36cc0efc272b1e4cadcafe2b2 Mon Sep 17 00:00:00 2001 From: Alessandro Gasparini Date: Tue, 19 Aug 2025 18:23:16 +0200 Subject: [PATCH 5/5] Harmonised changes in chapter 6 --- slides/06_conclusion.qmd | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/slides/06_conclusion.qmd b/slides/06_conclusion.qmd index 4d5119a..9ba2117 100644 --- a/slides/06_conclusion.qmd +++ b/slides/06_conclusion.qmd @@ -45,9 +45,9 @@ author: Daniel Sabanés Bové - Packaging a set of functions is an ideal way to share with collaborators and the public - Start small and simple and over time you can learn additional options -## Ensuring Quality +## Ensuring quality -- Quality by Design: Use a workable workflow:\ +- Quality by Design: use a workable workflow:\ Idea $\rightarrow$ Design docs $\rightarrow$ Programming $\rightarrow$ Quality check $\rightarrow$ Publication - Apply common clean code rules: - Use clear names for functions and variables @@ -88,8 +88,7 @@ author: Daniel Sabanés Bové # License information {.smaller} - Creators (initial authors): - Daniel Sabanés Bové - [`r fontawesome::fa("github")`](https://github.com/danielinteractive/) - [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/danielsabanesbove/), + Daniel Sabanés Bové [`r fontawesome::fa("github")`](https://github.com/danielinteractive/) [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/danielsabanesbove/), + Alessandro Gasparini [`r fontawesome::fa("linkedin")`](https://www.linkedin.com/in/ellessenne) [`r fontawesome::fa("github")`](https://www.github.com/ellessenne) [`r fontawesome::fa("globe")`](https://www.ellessenne.xyz/) {{< include _license_footer.qmd >}}