-
Notifications
You must be signed in to change notification settings - Fork 57
Description
Summary of the new feature / enhancement
As a maintainer of the
dsc-libcrate and integrating developer of the same crate,
I want to be able to more quickly navigate, contribute, test, document, and reference the types and functions in the library
So that I can contribute and integrate more quickly and reliably.
The layout and library API for dsc-lib has grown organically from the beginning of the project. Along the way, we've learned a lot about writing idiomatic and performant Rust code that differs from the current structure.
Additionally, when we first began work on dsc-lib, we worked under the assumption that the only Rust projects that would take a dependency on the library are the dsc CLI and a limited set of crates developed in this monorepo. Now that the Bicep local extension depends on dsc-lib and we plan to develop a Development Kit in Rust for DSC resources and extensions, we should carefully consider updating the library to follow more consistent conventions for the library APIs and structure.
Proposed technical implementation details (optional)
There are a few different areas we can pursue as part of this overall effort:
-
Decomposing large rust files into submodules with the re-export pattern.
We're currently using this pattern to various degrees with the
typesmodule. We're almost using this pattern for thefunctions, except that the submodules are public, so you reference a function type asdsc_lib::functions::<snake_case_name>::<PascalCaseName>. Making this change would enable a simpler access for these types, likedsc_lib::functions::CreateArrayinstead ofdsc_lib::functions::create_array::CreateArray.This would also enable decomposing larger files with numerous types into smaller files that are easier to read, maintain, and reason about.
[!NOTE]
While out of scope for this issue, it will also make it easier for us to extract subsets of functionality into separate crates to improve compile time performance (for Rust, the crate is a compilation unit). For example, if we decomposed thedscresourcesmodule into adsc-lib-resourcescrate and re-exported it from withindsc-lib, any compilation for local development that doesn't affect the decomposed crate is able to reuse prior compilation. I'm not sure the performance benefits are worth this more drastic move, but we might find that to be the case in the future. -
Reviewing the naming for structs, functions, and other items for consistency and clarity.
Currently, we have a mix of naming conventions that have organically grown with the project. We should be more consistent in the naming for types, traits, and functions both to ease general cognitive load for maintainers and to provide a consistent model for integrating developers to rely on.
-
Standardize reference documentation for items in the library.
Currently, the reference documentation (triple slash docs above a definition) for the library is in a mixed state. Some definitions have extensive documentation, some have a single line, some are lacking documentation entirely. We should ensure we have coverage of every public item and that the structure we use is consistent. This is critical for integrating developers but also helpful for contributors and maintainers, since reference documentation is surfaced by the Rust Analyzer extension when working on the project.
We should also consider documenting private items to the same standard, though this only affects maintainers.
-
Moving shared type definitions into the
typesmodule.As we move forward with the schema canonicalization effort and adopting the "parse, don't validate" design pattern to improve reliability and coherence for the library, we should consider moving shared type definitions to that module. Not every type should be defined there - manifests belong in their relevant module, for example.
But some types are defined in a given module and reused across multiple modules as generic types, like
ExecutionType. -
Moving all Rust tests for public items into the
tests/integrationsuite.The primary motivating factor here is build and test timings. When integration tests are colocated with module code, any changes to either the tests or the implementation requires recompilation because the file changed.
Moving the tests and following the current pattern that mirrors the
srcdirectory structure can also help us quickly identify where we are lacking integration tests for the library. Currently, given the existing layout, we need to carefully check every implementation file for test coverage. -
Moving all Rust tests for private items into the
src/testsfolder.We don't seem to have many tests that validate the behavior of private items. The vast majority of the tests I reviewed are only validating public items. However, moving the tests to a dedicated unit tests folder will also improve compile times for local development similarly to moving integration tests.
In the process of moving tests out of the implementation files and into dedicated test files, we should consider whether the unit tests are providing any value over the integration tests.
-
Enhancing integration tests for faster feedback and improved reliability.
Currently, we use Pester tests in the
dscfolder as acceptance tests for the DSC CLI. We should continue to do so, as the CLI is its own fully separate boundary for users. However, given the need to make thedsc-libcrate available itself, we should provide integration tests that ensure correctness and reliability for the underlying APIs themselves.Rust integration tests are also much faster than repeatedly invoking
dscthrough Pester, so this can improve the local development feedback loop for contributors and maintainers. We can continue to rely on the acceptance tests in thedscfolder for CI.