This page is
brand/en/package-guide.mdin kitDesign (the English translation ofbrand/套件開發須知.md).
Rules shared by the KIT R packages (kits, kitDesign, kitsUI, kitJoin, kitverse, and any new packages): how to lay out a package, how to bump versions, how to write NEWS, how to build Shiny apps, and how to write statistical code people can trust. Details on version rules and release steps are in Versions and releases; the interface spec is in the KIT design language.
| Package | Kind | Sections of this document |
|---|---|---|
| kits | Statistical computing | 1, 2, 4 |
| kitDesign | Interface (components for apps) | 1, 2 |
| kitsUI, kitJoin | Shiny apps | 1, 2, 3 |
| kitverse | Installs and loads the other packages in one go | 1, 2 |
1. What every package needs
1. Files
| File | Contents |
|---|---|
DESCRIPTION |
Version, Date, Authors@R,
URL (GitHub and website), BugReports,
Encoding: UTF-8, Depends: R (>= 4.1.0),
Imports (with minimum versions), Remotes
(packages not on CRAN, pinned to a tag) |
NAMESPACE, man/
|
Generated by roxygen2; never edit by hand |
R/ |
Code. Strings are ASCII only (see point 4) |
tests/testthat/ |
Tests. Every fixed bug keeps a test |
README.md |
English (GitHub shows it by default); README.zh-TW.md
is Chinese. The first line of each links to the other |
NEWS.md |
What changed in each version (see section 2) |
LICENSE, LICENSE.md
|
MIT |
.github/workflows/ |
R CMD check (Linux, Windows, macOS); add pkgdown if the package has a website |
2. Dependencies
-
Always give minimum versions in
Imports, especially when you use a new feature, e.g.bslib (>= 0.11.0)(the Brite theme).install.packages()only installs missing packages; it does not upgrade ones that are installed but too old. With a minimum version, kitverse and the apps’ launch scripts can detect this and upgrade. -
Pin
Remotesto a tag, not main:jiewenTsai/kitDesign@v0.5.0. -
Every reference to the same package must point to the same
tag. If kitsUI says
kitDesign@v0.5.0and kitverse sayskitDesign(main), pak stops with a “dependency conflict” and CI fails on all three platforms. When you upgrade kitDesign, update kitsUI, kitJoin, and kitverse together. - Don’t add a dependency you can do without. Packages used by only a
few functions go in
Suggests; callrequireNamespace()where they are used.
3. Where people install from
- Participants install from r-universe (https://jiewentsai.r-universe.dev): like CRAN, it has prebuilt Windows and macOS binaries, needs no Rtools or Xcode, and does not go through the GitHub API.
-
Don’t use
remotes::install_github()at workshops: with 80 people in one venue (one public IP), GitHub’s limit of 60 API calls per hour runs out. The same goes forpak. - To put a new package on r-universe: add a line to
packages.jsoninjiewenTsai/jiewentsai.r-universe.dev, and select that repo in the r-universe App settings on GitHub.
4. Chinese text and encoding
- All files are UTF-8.
-
Strings in R code must be ASCII only (an R CMD
check rule); write Chinese as
\uXXXX. Write Chinese directly while coding, then runLC_ALL=en_US.UTF-8 Rscript tools/escape_non_ascii.R: it converts to\uXXXXand leaves a line “# 原文:…” (“original text: …”) above it. Comments and tests can use Chinese directly. -
Function help (roxygen) is in English:
?functionin R and the English website both read it. kitDesign’s Chinese help is kept inpkgdown/zh/man/(for the Chinese website); when the English help changes, update the Chinese page too. - On Windows, R uses UTF-8 throughout only from R 4.2: Chinese file names and Chinese column names require R 4.2 or later (kitverse checks this).
5. Tests and checks
-
R CMD check: 0 errors, 0 warnings. Every NOTE must be explainable (e.g. kitverse deliberately does not import its Imports). - Don’t hard-code things that change in tests: read dates and version
numbers from
DESCRIPTION. - To fix a bug, first write a test that fails, then fix it.
- Cases that can crash R (e.g. readr reading an odd encoding) are
tested in a
callrsubprocess, so a crash only fails that one test.
6. Git
- One commit does one thing. The first line of the message says what was done; the body says why and how it was verified.
- A version-bump commit puts the versions in its title: “kitJoin 0.7.0: 「KIT 資料處理工具」, kitDesign 0.5.0” (“KIT data processing tool”).
- Tag releases:
vX.Y.Z. - Don’t commit data: research data such as TDCYP is tested only on your own computer and deleted afterwards; test data is fake data or public demo data.
2. Version numbers and NEWS
1. Version numbers (X.Y.Z)
| What changed | Which number goes up | Example |
|---|---|---|
| A fix; the screen, functions, and results are all unchanged | patch (0.6.0 → 0.6.1) | Fix JavaScript, fix the docs, fix a test |
| A new feature, or a small visible change; existing usage needs no changes | minor (0.6.1 → 0.7.0) | Add a function, add an argument with a default value, change an app’s title, add a chart |
| Existing usage has to change | major (0.7.0 → 1.0.0) | Rename or remove a function, change an argument’s meaning, a file format (e.g. the fixed file) can no longer read old files, results change |
- 0.x means “still settling”; 1.0.0 is a promise: from that version on, every major change in the table above bumps the major version and explains clearly how to migrate.
- kitDesign: a visible design change (colors, button size) counts as major, because both apps change with it (see Versions and releases).
- Statistical packages: the same data giving different numbers is at least minor; a change in estimation method or a default is major. NEWS must say how much the numbers differ.
- When to release 1.0:
- kitDesign: the first version both apps use (already reached).
- kitsUI, kitJoin, kitverse: the version used on the day of the workshop. All 80 people install the same version, so problem reports all refer to the same version.
- kits: when the fixed file format and function names are final, and results have been cross-validated (see section 4).
2. NEWS.md
One per package, at the root of the repo. In R, read it with
news(package = "kitsUI"); the pkgdown site’s “Changelog”
page is this file.
# kitJoin 0.7.0 (2026-11-01)
## Changes you can see
* The app is now called 「KIT 資料處理工具」 ...
## Fixes
* ...
## Under the hood
* Uses kitDesign 0.5.0 (`Imports: kitDesign (>= 0.5.0)`, `Remotes: jiewenTsai/kitDesign@v0.5.0`).- The heading is always
# package X.Y.Z (YYYY-MM-DD)(pkgdown relies on it to split versions). - Use these subheadings, and leave out any that have nothing:
- Breaking changes: what users must change to keep working (major only).
- Changes you can see: what users can see: the screen, functions, output files.
- Fixes: what was fixed; call out explicitly any case where a wrong result was reported as a success.
- Under the hood: what users can’t see: dependencies, refactoring, tests.
- Write for users: say “what happens now”, not “which file changed”. Quote on-screen text exactly as it appears, e.g. 「③ 各世代的垂直連結」 (“③ vertical linking across cohorts”).
- One section per version, newest at the top. Don’t put history in the README (the README has just one line: “See NEWS.md for the changes in each version”).
- kitDesign’s NEWS uses Chinese subheadings (“元件” (components), “修正” (fixes), “看得到的改變” (visible changes)), with the same meanings as above.
3. Releasing a version
- Update
VersionandDateinDESCRIPTION. - Add this version at the top of
NEWS.md. - Check:
tools/escape_non_ascii.R,roxygen2::roxygenise(),R CMD build,R CMD check(0 errors, 0 warnings). - Commit,
git tag vX.Y.Z, and push to GitHub (git push origin main --tags). r-universe rebuilds on its own. - Update the packages that use it: the minimum version in
Importsand the tag inRemotes, and write “Uses kitDesign X.Y.Z” in their NEWS. Bump kitverse’sImportstoo.
3. Shiny apps
1. Build the app as a package
- An app is an R package:
run_xxx()opens the app (run_kitsui(),run_kitjoin()), andkit_app()returns ashinyApp. -
app.Rat the root is for cloud deployment (itsource()s the package’sR/);run.batis for double-clicking on a local Windows machine. All three ways read the version from the sameDESCRIPTION. - Start a new app with
kitDesign::kit_new_app(): it sets up the header, step tabs, an example tab written to the page skeleton, and tests.
2. Always use kitDesign for the interface
- Page:
kit_page(title, subtitle, version = , date = , package = "kitXxx"). The version line reads “kitXxx v0.7.0 · 2026-11-01”, so a problem report shows at a glance which version of which app it is. - Use kitDesign’s components, colors, fonts, status boxes, and buttons; don’t copy your own CSS or theme. If a component is missing, add it to kitDesign so both apps can use it.
- Follow the KIT design language: for researchers aged 40–60; easy to see, safe to click, results first; one primary button per page; scroll to the status box after running; the 「用 R 怎麼做」 (“How to do it in R”) panel shows the equivalent R code.
- On-screen text is plain Traditional Chinese; text in charts follows kits’ English.
3. Cloud deployment (Posit Connect Cloud)
-
manifest.jsonrecords which packages, at which versions, the cloud installs. Always update it after upgrading kitDesign; otherwise the cloud installs the old version and the app breaks as soon as it opens. -
Don’t regenerate the whole file:
rsconnect::writeManifest()upgrades every CRAN package to the latest version at once (once it upgraded 17 at a time, including readr, which had problems). Change only the entry you need (e.g. kitDesign) and the checksums of changed files, and check the diff. - One cloud app can’t carry a whole workshop. Load test (2026-10-31): kitsUI on Free (4 GB, 1 CPU) reached 2.6–2.8 GB at 20 users and crashed at 50; Basic (8 GB, 2 CPU) held 100 users, but the slowest waited more than 30 minutes. R is single-threaded, so more CPUs help little. For workshops of 80–100 people, everyone uses their own computer (kitverse).
4. Local version
- Participants install kitverse: after
library(kitverse), userun_kitsui()andrun_kitjoin(). -
kitverse_check()actually starts each app to test it; add new apps to its list. - Uploaded data stays on the participant’s own computer and is never sent to any server.
5. Tests
- Server logic:
shiny::testServer(); downloads:kitDesign::kit_test_download(). - For on-screen text such as the version line and titles, test with a
pattern (
"kitJoin v[0-9.]+ · "); don’t hard-code version numbers. - When you change a workflow, run it end to end at least once with real data (don’t rely on unit tests alone).
4. Statistical packages
Errors in statistical code often don’t crash; they quietly produce wrong numbers. So the rules focus on this: state clearly what is computed, verify that it is computed correctly, and announce when results change. See rOpenSci’s statistical software standards (general standards, plus standards for categories such as IRT, regression, and Bayesian methods).
1. State clearly what is computed
- For every method, give the model, the estimation method, and
references (DOI): in the Description in
DESCRIPTION, in the function docs, and somewhere it can be looked up in R (kits’kits_algorithm()lists the steps, formulas, and references behind a result). - Explain why each default is set the way it is (e.g. the convergence criterion, the maximum number of iterations, how missing values are handled).
- Provide
inst/CITATION(kits already has one), socitation("kits")shows how to cite it.
2. Keep computation separate from presentation
- The computation layer is pure functions: data and settings in,
results out; no reading or writing files, no printing, no dependence on
global options (kits’
algo_*()layer, which can be chained with pipes). - Results are objects with a class, with
print(),summary(),as.data.frame(), andplot()methods. - Shiny apps only call the computation layer and never reimplement computations in the app. The code shown in 「用 R 怎麼做」 (“How to do it in R”) must produce exactly the same results.
3. Input checks and errors
- Check before computing: columns, types, ranges (e.g. scores must start at 0), missing values, and whether each group has enough people.
- Errors and warnings use classed conditions that users can catch by
class with
tryCatch()(kits’kits_abort(..., class = "kits_error_data"), with no extra dependency on rlang). Messages say what is wrong and how to fix it; the app then turns them into plain language (kitDesign’skit_abort(),kit_is_user_error()). - Don’t silently fix data. If you must fix it, record what was changed in the returned result.
4. Verify the results are correct
- Compare with another implementation: compute on the same data with another package (kits has kitsPreview, which computes the same results with dexter and cNORM); differences must be within tolerance.
- Simulation recovery: simulate data from known parameters; the estimates must recover the original parameters (bias and RMSE in the expected range).
- Edge cases: all correct, all wrong, only one item, only one person, a group with nobody in it, everything missing. Either give a sensible result or stop and say why.
-
Numerical tolerance: compare floating-point numbers
with a tolerance (e.g.
1e-12), and write it in the test. -
Reproducibility: use
set.seed()wherever there is randomness, so the same input gives the same result every time.
5. File formats
- Files saved for later use (e.g. kitsUI’s fixed file) carry a format version and a checksum.
- New versions must read old files; when they can’t, say which version the file is and how to recreate it. Keep an old-version file in the tests.
- A format change is major (or minor while in 0.x, with a clear NEWS entry).
6. Announce when results change
- When the same data gives different numbers, write under “Changes you can see” in NEWS: which result, why, and by how much.
- A change in estimation method or a default is major.
- Text in charts follows the computing package’s English; names from the data (item IDs, cohorts) are written as they appear in the data.