Paclet Workflow

Set up a development sessionSet up documentation development
Set up paclet/package developmentSet up paclet builds and installs
Set up unit testingSet up paclet deployment
The Wolfram Language's renowned ability to facilitate computational exploration is well-established but converting any discoveries into usable computational systems depends on carefully designed functions and packages all implemented within paclets. Consequently, developing an efficient, repeatable workflow for creating, testing, documenting and deploying paclets defines a vital cog in any set-up aiming to produce sophisticated WL-based systems. The value of instituting such a workflow is therefore immense---nothing less than the conduit for getting your computational discoveries out into the world.
There already exists a range of comprehensive tutorials, how-to's and excellent tech notes on paclets in the Documentation Center so why provide yet another one? There are three main reasons:

1.  To provide a more succinct list of key steps in a paclet workflow.

2.  To highlight some key conceptions, tricks and gotchas.

3.  To spotlight a streamlined workflow enhanced by PacletAssurance.

The paclet's existing documentation is comprehensive and an important, authoritative reference. Sometimes however, its very comprehensiveness impedes developing the overview needed to set up bespoke workflows. In particular, gaining such an overview can depend on some key insights or functions that are intended to be highlighted in this tech note. Finally, freshly-developed, added-on tools from PacletAssurance are designed to further exploit these insights to create even slicker workflows.
Set up a development session
There are several function that will eventually transition into the System` context but for now load these in from PacletTools`.
Additionally there are several functions from PacletAssurance` that will help create a more streamlined developing experience.
The following functions configure a developing session.
$DeveloperDirectory
directory to place all paclets under development
DeveloperOn
ensures that paclets under development are found first
Configuring a developing session and/or creating a new paclet.
$DeveloperDirectory can either be set at the start of every development session or, perhaps more conveniently during continuous development activity set as a persistent definition across kernel sessions.
If persistently set, the only set-up required in each session is executing DeveloperOn[].
Set up paclet/package development
Package development is the foundational pillar of any significant computational system built in the WL but this is an expansive and deep subject worthy of dedicated exploration in its own right. Most developers however, will have already established their own package-developmental workflow so the focus here will be on their integration with paclets.
Paclets are officially described as "units of Wolfram functionality" whose main payload is typically defined by its constituent packages. Paclets also include however, other resources contributing to this new functionality including two ones indispensable to promulgation, its Documentation and TestFiles.
But not all paclets are created equal. There is a very important distinction to be made between two types of paclets in the WL --namely, "Developer" and "Built" paclets. Developer paclets are those ones in which editing and development take place whereas "Built" paclets are the ones used by the system when adding its functionality. Built paclets are typically created from Developer paclets by invoking either PacletInstall or (in PacletAssurance) PacletBuildInstall or PacletDeploy.
This distinction between two types of paclet can be overlooked because a paclet is notionally created simply by placing a PacletInfo.m file in a folder containing all of a paclet's components. The attraction of such design comes from existing resources being made readily available simply by adding a single file. In practice however, professionally-released code is rarely produced in this way since it more typically requires the iterative and simultaneous development of related paclet resources (such as, for example, Documentation and TestFiles) that themselves typically require a level of post-processing.
Best practice development being promoted here then, involves setting up a basic Development paclet from the get-go, refining and improving its resources in-place before periodically invoking PacletBuildInstallculminating in a PacletDeployonce the paclet is ready for promulgation. Failing to fully inculcate this distinction between Developer and Built paclets can lead to unexpected errors when using native paclet functions. To avoid this and make this demarcation sharp, PacletAssurance defines a $DeveloperDirectory which is where a new paclet is automatically placed when CreateDeveloperPaclet is invoked.
CreateDeveloperPaclet["myPaclet","myPackage"->{"fooA","fooB"}]
creates myPaclet containing myPackage itself containing public functions fooA and fooB.
Creating a new paclet and placing it under development.
CreateDeveloperPaclet creates a paclet structured to facilitate those practices identified as carrying particular import. For example, this created paclet automatically includes a TestFiles directory set to contain the paclet's unit-tests, a component promoted here as being equally as important as its documentation.
A suggested workflow to leverage PacletAssurance's unit-testing functionality therefore, is to, in tandem with developing code and documentation, develop corresponding unit-tests categorized within the paclet's TestFile directory. Over time your own package-design will dictate the evolution of the paclet's overall directory-structure as it becomes populated with named functions that are, in turn, both influence and are influenced by, corresponding documentation and unit-tests.
Set up unit testing
PacletAssurance provides a significant extension to the built-in testing framework by organizing unit-tests in a way that scales. Further, the transparency associated with making public a function's own unit-testing can create a powerful layer of accountability and robustness.
TestSummary
generates a summary of collections of unit tests
TestFile
returns a test file associated with a given function
TestFiles
returns test files associated with a given function or paclet
Additional unit-testing functionality.
One useful way to leverage these functions is to maintain a protocol whereby every function published by your computational system comes with unit-tests organized according to, as a bare minimum, the following three categories: 1) Core usage 2) Documentation 3) ExceptionHandling.
Core Usage
The units tests associated with a function's core usage exemplify the function's signature applications. They are usually the first ones tested and define the function's raison d'être.
Documentation
The unit tests associated with Documentation consist of all tests corresponding to all the examples provided in the documentation outside those already appearing in core usage.
ExceptionHandling
The unit tests associated with ExceptionHandling consist of all those tests specifying how your system can elegantly handle unexpected input or output.

File layout

Implementing the above unit-testing categorization is activating by defining suitably-named and placed testing files. That is, the unit tests in each category appear in a (.nb) testing notebook together with its (.wlt) counterpart. The notebook is where you add/edit tests while the .wlt file is what is ultimately run during efficient testing. For example, our onSocPacletExample, has public functions FooA and FooB so that following this protocol leads to the following .nb and .wlt files placed in a TestFiles directory within the paclet:

Other Categories & Best Practice

The minimal categorization embodied in these three categories; Core usage, Documentation and ExceptionHandling can be readily varied and extended. For instance, sound modularization practice suggests unit-testing files being capped to containing a few dozens tests (perhaps less than ~50) so that for complex functions with larger numbers of tests these categories can be further decomposed -e.g. Documentation1, Documentation2 ... etc. Other possibilities includes categories like CornerCases, Coverage, FileSystemTouching, ComputationalIntensive, Bugs as are any other categories relevant to your application.
The point is that whatever categorization is ultimately chosen, PacletAssurance functions like TestSummary, TestFile and TestFiles provide indispensable ways to organize and run test-suites of arbitrary granularity. In this way, WL's testing framework becomes genuinely scalable. An example of the type of seamless testing that results from following this protocol is provided in this Tech Note where PacletAssurance's own unit tests are exposed.
Set up documentation development
Documentation forms an integral part of WL-based computational systems and remains one of its distinguishing features. Leveraging this pedigree is hence a vital part of imbuing your own software with similar levels of clarity, literateness and robustness.
Creating documentation in the WL is a two-step process; firstly documentation is written in notebooks with the aid of Documentation Tools before secondly, these pages are built into the pages loaded by the Documentation Center for viewing by end-users. Streamlining this editing -viewing therefore forms a core part of iteratively improving documentation.

Previewing a single documentation page

Getting a quick, preliminary feel for how a documentation page's will ultimately appear can be obtained by clicking the "Preview" button on the right-hand-side of the page's docked cell.
While this provides instant feedback for how a function's description and functionality is tracking, such previewing doesn't represent a full weaving of the page into a package's full documentation (links in the page won't, for example, be directed to newly edited pages similarly viewable in the Documentation Center). A more complete integration however, can be previewed by building and installing in sequence, a two-step process that can be usefully combined into a single function.
Set up paclet builds and installs
PacletBuildInstall folds two paclet functions into one essentially becoming a short-hand way of sequentially performing a PacletBuild followed by a PacletInstall. This is convenient because one inevitably follows the other in standard paclet development: The main deliverable from a PacletBuild is a zipped .paclet file that is intended to be distributed and installed by third-party users. But developers are unlikely to carry out such promulgation without first testing the installation on their own systems, a task that can be performed simultaneously by PacletBuildInstall.
The other advantages of periodically invoking PacletBuildInstall is that regular testing in an "installed environment" is liable to catch any in situ issues while also providing system-wide, "pre-release" functionality that may be still be of utility to a developer even prior to a fully-polished release.
PacletBuildInstall
builds and installs a paclet
Combining building, installing and testing.
A final advantage of using PacletBuildInstall is that post-installation testing of the paclet's correctness can be automated by setting its "Assurance" option:
Caveat 1: Using PacletBuildInstall to view the latest integrated documentation requires quitting and starting a fresh kernel (ideally a seamless workflow would avoid this discontinuity but currently this is not possible).
Caveat 2: PacletBuildInstall by default uses the option setting ForceVersionInstall True and hence will install the specified paclet over any existing paclet with the same version number (while leaving untouched newer paclets while still installing).
Set up paclet deployment
While a cycle of building and installing defines typical paclet development, the final paclet created is not usually optimized for distribution as a commercial product. For instance, before distributing a commercial product you may want to perform a variety of tasks during the final build such as: removing any development notebooks from the release (say those ones containing initialization cells); add company/authorial information to the pacletinfo.wl file; encode specified kernel files; add DRM; perform final unit testing etc. Automating all of these tasks can be performed via PacletDeploy through its option settings.
PacletDeploy
deploy a fully-productionized paclet
Preparing a paclet for commercial release.