<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[No Clocks Blog]]></title><description><![CDATA[No Clocks Blog]]></description><link>https://blog.noclocks.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1729708694667/aa0a2f32-ea7d-4db3-8ee1-fcff57dafb69.png</url><title>No Clocks Blog</title><link>https://blog.noclocks.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 12 Sep 2026 05:38:23 GMT</lastBuildDate><atom:link href="https://blog.noclocks.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Lazy Loading Tab Completion Scripts in PowerShell]]></title><description><![CDATA[If you’re a frequent PowerShell Core user who has set up an extensive shell profile, you've probably encountered slow startup times, especially when loading many tab completion scripts. Often, these scripts are dot-sourced during profile startup, whi...]]></description><link>https://blog.noclocks.dev/lazy-loading-tab-completion-scripts-in-powershell</link><guid isPermaLink="true">https://blog.noclocks.dev/lazy-loading-tab-completion-scripts-in-powershell</guid><category><![CDATA[PowerShell Automation]]></category><category><![CDATA[Powershell]]></category><category><![CDATA[profile]]></category><category><![CDATA[startup]]></category><dc:creator><![CDATA[Jimmy Briggs]]></dc:creator><pubDate>Wed, 23 Oct 2024 19:27:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729711285289/48e77d10-7098-4a01-b6ca-f8a34aff12de.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’re a frequent PowerShell Core user who has set up an extensive shell profile, you've probably encountered slow startup times, especially when loading many tab completion scripts. Often, these scripts are dot-sourced during profile startup, which can significantly delay the availability of your terminal session.</p>
<p>In this blog post, we'll explore how to optimize the startup time of your PowerShell profile by implementing a lazy-loading mechanism for shell tab completion scripts. This method loads completions only when a relevant command is typed, thus avoiding unnecessary overhead during startup.</p>
<h2 id="heading-the-scenario">The Scenario</h2>
<p>Imagine you have a set of tab completion scripts located as individual files in a <code>completions</code> folder. When your PowerShell session starts, another script (<code>Profile.Completions.ps1</code>) dot-sources each of these completion scripts. This <code>Profile.Completions.ps1</code> is itself dot-sourced by your main profile script <code>Profile.ps1</code>, meaning every script in the <code>completions</code> folder is loaded every time you open a terminal.</p>
<p>While this setup ensures all tab completions are available, it comes at the cost of longer startup times.</p>
<p>A more efficient way is to load each completion script only when you type a command requiring it.</p>
<p>This concept is known as <em>lazy loading</em> or <em>lazy evaluating</em> in computer science.</p>
<h2 id="heading-why-lazy-loading">Why Lazy Loading?</h2>
<p>Lazy loading is the practice of loading resources only when they are needed. For PowerShell profiles, this means:</p>
<ul>
<li><p><strong>Optimized Startup:</strong> Loading scripts only when necessary speeds up the profile startup.</p>
</li>
<li><p><strong>Efficient Resource Usage:</strong> Memory is conserved by loading only the scripts you use during the session.</p>
</li>
</ul>
<h2 id="heading-implementing-lazy-loading-for-tab-completion-scripts">Implementing Lazy Loading for Tab Completion Scripts</h2>
<p>Let’s walk through the steps to implement a lazy-loading mechanism using PowerShell Core's built-in features, such as <code>Register-ArgumentCompleter</code>.</p>
<h3 id="heading-step-1-define-a-command-to-script-mapping">Step 1: Define a <code>Command-to-Script</code> Mapping</h3>
<p>The first step is to define a mapping between commands and their corresponding completion scripts.</p>
<p>We’ll use a hash table for this:</p>
<pre><code class="lang-powershell"><span class="hljs-comment">&lt;#
    <span class="hljs-doctag">.SYNOPSIS</span>
        Command-to-Script Mapping Hash Table.
    <span class="hljs-doctag">.DESCRIPTION</span>
        This PowerShell Data File (.psd1) contains the necessary mappings which map commands and programs to their
        corresponding shell completion scripts or modules.

        It is used in order to implement a lazy-loading mechanism for importing completion scripts.
    <span class="hljs-doctag">.NOTES</span>
        - The key is the command name.
        - The value is the path to the completion script or module.

        Tools with names different than their commands:
            - Obsidian CLI uses `obs` as its CLI command. 
            - 1Password CLI uses `op` as its CLI command.
            - `s` is the command for `s-search`.
            - `gh-copilot` is the key for the GitHub Copilot CLI Extension Completion Script, but the command is `gh copilot`.
#&gt;</span>

<span class="hljs-variable">$CompletionScripts</span> = <span class="hljs-selector-tag">@</span>{
    <span class="hljs-string">'aws'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\aws.completion.ps1"</span>
    <span class="hljs-string">'choco'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\choco.completion.ps1"</span>
    <span class="hljs-string">'docker'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\docker.completion.ps1"</span>
    <span class="hljs-string">'dotnet'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\dotnet.completion.ps1"</span>
    <span class="hljs-string">'ffsend'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\ffsend.completion.ps1"</span>
    <span class="hljs-string">'gh'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\gh.completion.ps1"</span>
    <span class="hljs-string">'gh copilot'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\gh-copilot.completion.ps1"</span>
    <span class="hljs-string">'git'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\git.completion.ps1"</span>
    <span class="hljs-string">'git-cliff'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\git-cliff.completion.ps1"</span>
    <span class="hljs-string">'obs'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\obsidian-cli.completion.ps1"</span>
    <span class="hljs-string">'oh-my-posh'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\oh-my-posh.completion.ps1"</span>
    <span class="hljs-string">'rclone'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\rclone.completion.ps1"</span>
    <span class="hljs-string">'rig'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\rig.completion.ps1"</span>
    <span class="hljs-string">'rustup'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\rustup.completion.ps1"</span>
    <span class="hljs-string">'s'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\s-search.completion.ps1"</span>
    <span class="hljs-string">'scoop'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\scoop.completion.ps1"</span>
    <span class="hljs-string">'yq'</span> = <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>\yq.completion.ps1"</span>
}
</code></pre>
<p>Here, <code>$PSScriptRoot</code> is used to reference the directory of the current script, ensuring paths remain relative.</p>
<h3 id="heading-step-2-create-the-lazy-loading-function-import-completion">Step 2: Create the Lazy Loading Function: <code>Import-Completion</code></h3>
<p>Now, we need a function that handles loading the completion script when a command is typed:</p>
<pre><code class="lang-powershell"><span class="hljs-comment"># ------------------------------------------------------------------------------</span>
<span class="hljs-comment"># Import-Completion</span>
<span class="hljs-comment"># ------------------------------------------------------------------------------</span>

<span class="hljs-function"><span class="hljs-keyword">Function</span> <span class="hljs-title">Import-Completion</span></span> {
    <span class="hljs-comment">&lt;#
    <span class="hljs-doctag">.SYNOPSIS</span>
        Load the completion script for the specified command.
    <span class="hljs-doctag">.DESCRIPTION</span>
        This function loads the completion script for the specified command by dot-sourcing the script file.

        The function checks if the completion script for the specified command exists in the `$CompletionScripts` hash
        table and if it has not already been loaded. If both conditions are met, the function dot-sources the completion
        script defined in the hash table and sets the `$Script:CompletionLoaded` hash table entry for the specified
        command to `$true` (for the current session).

    <span class="hljs-doctag">.PARAMETER CommandName</span>
        The name of the command for which to load the completion script. This parameter is mandatory and accepts input
        from the pipeline. The value of this parameter is validated against the keys in the `$CompletionScripts` hash
        table defined in the `Completions.psd1` file.

   <span class="hljs-doctag">.NOTES</span>
       This function is used to implement a lazy-loading mechanism for importing completion scripts.

    <span class="hljs-doctag">.EXAMPLE</span>
        # Load the completion script for the `aws` command.
        Load-Completion -CommandName 'aws'

        # Check if Loaded
        $Script:CompletionLoaded['aws']
    #&gt;</span>
    [<span class="hljs-type">CmdletBinding</span>(
        <span class="hljs-type">SupportsShouldProcess</span> = <span class="hljs-variable">$false</span>,
        <span class="hljs-type">ConfirmImpact</span> = <span class="hljs-string">'None'</span>
    )]
    <span class="hljs-keyword">Param</span>(
        [<span class="hljs-type">Parameter</span>(<span class="hljs-type">Mandatory</span> = <span class="hljs-variable">$true</span>, <span class="hljs-type">Position</span> = <span class="hljs-number">0</span>, <span class="hljs-type">ValueFromPipeline</span> = <span class="hljs-variable">$true</span>)]
        [<span class="hljs-type">ValidateScript</span>({ <span class="hljs-variable">$CompletionScripts</span><span class="hljs-type">.ContainsKey</span>(<span class="hljs-variable">$_</span>) })]
        [<span class="hljs-built_in">String</span>]<span class="hljs-variable">$CommandName</span>
    )

    <span class="hljs-keyword">If</span> (<span class="hljs-variable">$CompletionScripts</span>.ContainsKey(<span class="hljs-variable">$CommandName</span>) <span class="hljs-operator">-and</span> <span class="hljs-operator">-not</span> <span class="hljs-variable">$Script:CompletionLoaded</span>[<span class="hljs-variable">$CommandName</span>]) {
        . <span class="hljs-variable">$CompletionScripts</span>[<span class="hljs-variable">$CommandName</span>]
        <span class="hljs-variable">$Script:CompletionLoaded</span>[<span class="hljs-variable">$CommandName</span>] = <span class="hljs-variable">$true</span>
    }
}
</code></pre>
<p>This function:</p>
<ul>
<li><p>Takes the command name as a parameter.</p>
</li>
<li><p>Checks if the command has a mapped completion script and whether it's already loaded.</p>
</li>
<li><p>Dot-sources the script to load the completions if it hasn't been loaded yet.</p>
</li>
<li><p>Updates a tracking hashtable (<code>$script:CompletionLoaded</code>) to prevent reloading the same script multiple times.</p>
</li>
</ul>
<p><em>Note: that this function depends on a</em> <code>$CompletionScripts</code> hash-table to be loaded in order to function properly and map the commands to their completion files.</p>
<h3 id="heading-step-3-register-a-catch-all-argument-completer">Step 3: Register a Catch-All Argument Completer</h3>
<p>Next, we use <code>Register-ArgumentCompleter</code> to define a catch-all completer that intercepts all command typing and loads the appropriate completion script if necessary:</p>
<pre><code class="lang-powershell"><span class="hljs-built_in">Register-ArgumentCompleter</span> <span class="hljs-literal">-Native</span> <span class="hljs-literal">-CommandName</span> * <span class="hljs-literal">-ScriptBlock</span> {
    <span class="hljs-keyword">param</span>(<span class="hljs-variable">$commandName</span>, <span class="hljs-variable">$parameterName</span>, <span class="hljs-variable">$wordToComplete</span>, <span class="hljs-variable">$commandAst</span>, <span class="hljs-variable">$fakeBoundParameters</span>)

    <span class="hljs-comment"># Try to load the completion script for the typed command</span>
    <span class="hljs-built_in">Import-Completion</span> <span class="hljs-literal">-CommandName</span> <span class="hljs-variable">$commandName</span>

    <span class="hljs-comment"># Returning nothing here; the actual completion is handled by the script if it exists</span>
    <span class="hljs-keyword">return</span> <span class="hljs-variable">$null</span>
}
</code></pre>
<p>This catch-all completer does the following:</p>
<ul>
<li><p>It registers for all commands (<code>-CommandName *</code>) typed into the terminal.</p>
</li>
<li><p>Calls <code>Import-Completion</code> with the command name to load the necessary completion script.</p>
</li>
<li><p>Leaves the actual completion to the script if it exists.</p>
</li>
</ul>
<h3 id="heading-step-4-initialize-tracking-variables">Step 4: Initialize Tracking Variables</h3>
<p>Finally, initialize the <code>$script:CompletionLoaded</code> variable in your <code>Profile.Completions.ps1</code> script to track loaded completion scripts:</p>
<pre><code class="lang-powershell"><span class="hljs-comment"># Hashtable to track which completions have been loaded</span>
<span class="hljs-variable">$script:CompletionLoaded</span> = <span class="hljs-selector-tag">@</span>{}
</code></pre>
<p>This step sets up an empty hashtable that will be populated as completion scripts are loaded.</p>
<h3 id="heading-step-5-putting-it-all-together">Step 5: Putting It All Together</h3>
<ol>
<li><p><strong>Create</strong> <code>Profile.Completions.ps1</code>: This script should contain the command-to-script mapping, the <code>Import-Completion</code> function, and the catch-all completer registration.</p>
</li>
<li><p><strong>Update</strong> <code>Profile.ps1</code>: In your main profile script, simply dot-source <code>Profile.Completions.ps1</code>:</p>
<pre><code class="lang-powershell"> . <span class="hljs-string">"<span class="hljs-variable">$PSScriptRoot</span>/Profile.Completions.ps1"</span>
</code></pre>
</li>
</ol>
<p>With this setup, PowerShell will only load a completion script when a command is typed, significantly reducing startup times while still providing full tab completion functionality.</p>
<h2 id="heading-how-it-works">How It Works</h2>
<ul>
<li><p>When a command is typed, <code>Register-ArgumentCompleter</code> triggers the <code>Load-Completion</code> function.</p>
</li>
<li><p>The function checks if a completion script for the command exists and hasn’t been loaded yet.</p>
</li>
<li><p>If both conditions are met, it dot-sources the script, making the completions available.</p>
</li>
<li><p>The <code>$script:CompletionLoaded</code> hash table ensures each completion script is only loaded once per session.</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By implementing a lazy-loading mechanism for your PowerShell Core tab completions, you can maintain a clean and functional startup process while optimizing for performance. This approach ensures that only the necessary completion scripts are loaded, reducing the initial overhead of your PowerShell profile.</p>
<p>With this method, you retain the full power of command completions without compromising on startup speed. This technique can be further extended or modified to suit other scenarios where deferred script loading is beneficial.</p>
<p><strong>Happy scripting!</strong> 🎉</p>
]]></content:encoded></item><item><title><![CDATA[Schema-Driven Development and Single Source of Truth: Essential Practices for Modern Developers]]></title><description><![CDATA[💡
In the realm of software development, agility, consistency, and quality are more crucial than ever. As projects grow in complexity and teams scale, adhering to foundational best practices becomes essential. This article focuses on two critical par...]]></description><link>https://blog.noclocks.dev/schema-driven-development-and-single-source-of-truth-essential-practices-for-modern-developers</link><guid isPermaLink="true">https://blog.noclocks.dev/schema-driven-development-and-single-source-of-truth-essential-practices-for-modern-developers</guid><dc:creator><![CDATA[Jimmy Briggs]]></dc:creator><pubDate>Wed, 23 Oct 2024 19:01:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729709480466/ce5d70eb-ebee-4ceb-b32c-32530d12915f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712331601187/039f3043-7b8a-4fb0-acc0-9630de9f6f4d.png?auto=compress,format&amp;format=webp" alt class="image--center mx-auto" /></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">In the realm of software development, agility, consistency, and quality are more crucial than ever. As projects grow in complexity and teams scale, adhering to foundational best practices becomes essential. This article focuses on two critical paradigms: <strong>Schema-Driven Development (SDD)</strong> and the concept of a <strong>Single Source of Truth (SSOT)</strong>. We'll explore how to derive CRUD APIs directly from SQL DDL database schemas, generate database documentation via DBML, and produce OpenAPI and JSON schemas—all contributing to a more efficient and error-free development process.</div>
</div>

<h2 id="heading-best-practices">Best Practices</h2>
<p>Before diving into SDD and SSOT, let's briefly outline the broader landscape of best practices that high-performing teams should follow:</p>
<ol>
<li><p><strong>Schema-Driven Development &amp; Single Source of Truth</strong></p>
</li>
<li><p><strong>Configure Over Code</strong></p>
</li>
<li><p><strong>Security &amp; Compliance</strong></p>
</li>
<li><p><strong>Decoupled (Modular) Architecture</strong></p>
</li>
<li><p><strong>Shift Left Approach</strong></p>
</li>
<li><p><strong>Essential Coding Practices</strong></p>
</li>
<li><p><strong>Efficient SDLC</strong>: Issue management, documentation, test automation, code reviews, productivity measurement, source control, and version management</p>
</li>
<li><p><strong>Observability for Fast Resolution</strong></p>
</li>
</ol>
<hr />
<h2 id="heading-what-is-schema-driven-development">What is Schema-Driven Development?</h2>
<p><strong>Schema-Driven Development</strong> is an approach where a single schema definition serves as the foundational blueprint for all aspects of an application. Instead of manually coding each component, the schema drives the generation of APIs, validations, documentation, and even test cases. This ensures consistency, reduces redundant effort, and minimizes the chances of errors.</p>
<h3 id="heading-key-benefits-of-sdd"><strong>Key Benefits of SDD</strong></h3>
<ul>
<li><p><strong>Unified Source of Truth</strong>: All teams and services refer to the same definitions, ensuring alignment.</p>
</li>
<li><p><strong>Automated Generation</strong>: Reduces manual coding by auto-generating CRUD APIs, documentation, and client libraries.</p>
</li>
<li><p><strong>Enhanced Parallel Development</strong>: Frontend and backend teams can work simultaneously, reducing bottlenecks.</p>
</li>
<li><p><strong>Error Reduction</strong>: Automated validations prevent incorrect data from propagating through the system.</p>
</li>
</ul>
<h3 id="heading-signs-your-team-isnt-using-sdd"><strong>Signs Your Team Isn't Using SDD</strong></h3>
<ul>
<li><p>Multiple, inconsistent schema definitions across services.</p>
</li>
<li><p>Manually crafted APIs, documentation, and test cases.</p>
</li>
<li><p>Sharing Postman collections via email rather than generating them automatically.</p>
</li>
<li><p>Increased bugs due to inconsistent data handling.</p>
</li>
</ul>
<hr />
<h2 id="heading-understanding-single-source-of-truth-ssot">Understanding Single Source of Truth (SSOT)</h2>
<p>A <strong>Single Source of Truth</strong> is the practice of structuring information models and associated schemata such that every data element is stored exactly once. In software development, this means all components—APIs, databases, services—derive their structure from a single schema, typically the database schema.</p>
<h3 id="heading-advantages-of-ssot"><strong>Advantages of SSOT</strong></h3>
<ul>
<li><p><strong>Data Consistency</strong>: Eliminates discrepancies caused by redundant data definitions.</p>
</li>
<li><p><strong>Simplified Maintenance</strong>: Updates to the schema automatically reflect across all dependent components.</p>
</li>
<li><p><strong>Improved Collaboration</strong>: Teams work from a shared understanding, reducing miscommunication.</p>
</li>
<li><p><strong>Reduced Technical Debt</strong>: Consistent schemas prevent the accumulation of outdated or redundant code.</p>
</li>
</ul>
<hr />
<h2 id="heading-practical-examples-deriving-from-sql-ddl">Practical Examples: Deriving from SQL DDL</h2>
<h3 id="heading-example-1-generating-crud-apis-from-sql-ddl"><strong>Example 1: Generating CRUD APIs from SQL DDL</strong></h3>
<p><strong>Scenario:</strong> You have an existing database schema defined using SQL Data Definition Language (DDL):</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> books (
  <span class="hljs-keyword">id</span> <span class="hljs-built_in">INT</span> PRIMARY <span class="hljs-keyword">KEY</span> AUTO_INCREMENT,
  title <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  author <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  published_date <span class="hljs-built_in">DATE</span>,
  isbn <span class="hljs-built_in">VARCHAR</span>(<span class="hljs-number">13</span>)
);
</code></pre>
<p><strong>Using SDD, you can:</strong></p>
<ol>
<li><p><strong>Generate JSON Schemas:</strong></p>
<p> Use tools like <a target="_blank" href="https://github.com/duartealexf/sql-ddl-to-json-schema"><code>sql-ddl-to-json-schema</code></a> to convert your SQL DDL into JSON Schema definitions:</p>
<pre><code class="lang-json"> {
   <span class="hljs-attr">"title"</span>: <span class="hljs-string">"books"</span>,
   <span class="hljs-attr">"type"</span>: <span class="hljs-string">"object"</span>,
   <span class="hljs-attr">"properties"</span>: {
     <span class="hljs-attr">"id"</span>: { <span class="hljs-attr">"type"</span>: <span class="hljs-string">"integer"</span> },
     <span class="hljs-attr">"title"</span>: { <span class="hljs-attr">"type"</span>: <span class="hljs-string">"string"</span> },
     <span class="hljs-attr">"author"</span>: { <span class="hljs-attr">"type"</span>: <span class="hljs-string">"string"</span> },
     <span class="hljs-attr">"published_date"</span>: { <span class="hljs-attr">"type"</span>: <span class="hljs-string">"string"</span>, <span class="hljs-attr">"format"</span>: <span class="hljs-string">"date"</span> },
     <span class="hljs-attr">"isbn"</span>: { <span class="hljs-attr">"type"</span>: <span class="hljs-string">"string"</span> }
   },
   <span class="hljs-attr">"required"</span>: [<span class="hljs-string">"title"</span>, <span class="hljs-string">"author"</span>]
 }
</code></pre>
</li>
<li><p><strong>Generate OpenAPI Schemas:</strong></p>
<p> Use the JSON Schemas to create OpenAPI definitions for your RESTful APIs.</p>
<pre><code class="lang-yaml"> <span class="hljs-attr">openapi:</span> <span class="hljs-number">3.1</span><span class="hljs-number">.0</span>
 <span class="hljs-attr">info:</span>
   <span class="hljs-attr">title:</span> <span class="hljs-string">Book</span> <span class="hljs-string">API</span>
   <span class="hljs-attr">version:</span> <span class="hljs-number">1.0</span><span class="hljs-number">.0</span>
 <span class="hljs-attr">paths:</span>
   <span class="hljs-string">/books:</span>
     <span class="hljs-attr">get:</span>
       <span class="hljs-attr">summary:</span> <span class="hljs-string">List</span> <span class="hljs-string">all</span> <span class="hljs-string">books</span>
       <span class="hljs-attr">responses:</span>
         <span class="hljs-attr">'200':</span>
           <span class="hljs-attr">description:</span> <span class="hljs-string">A</span> <span class="hljs-string">list</span> <span class="hljs-string">of</span> <span class="hljs-string">books.</span>
           <span class="hljs-attr">content:</span>
             <span class="hljs-attr">application/json:</span>
               <span class="hljs-attr">schema:</span>
                 <span class="hljs-attr">type:</span> <span class="hljs-string">array</span>
                 <span class="hljs-attr">items:</span>
                   <span class="hljs-string">$ref:</span> <span class="hljs-string">'#/components/schemas/Book'</span>
 <span class="hljs-attr">components:</span>
   <span class="hljs-attr">schemas:</span>
     <span class="hljs-attr">Book:</span>
       <span class="hljs-string">$ref:</span> <span class="hljs-string">'book.schema.json'</span>  <span class="hljs-comment"># Reference to the generated JSON Schema</span>
</code></pre>
</li>
<li><p><strong>Auto-Generate CRUD APIs:</strong></p>
<p> Use frameworks like <strong>LoopBack 4</strong> or <strong>PostgREST</strong> that can generate RESTful APIs directly from your database schema.</p>
<p> <strong>Using PostgREST:</strong></p>
<ul>
<li><p><strong>Setup:</strong> Point PostgREST to your PostgreSQL database.</p>
</li>
<li><p><strong>Result:</strong> Instantly get a fully functional REST API adhering to the OpenAPI spec.</p>
</li>
</ul>
</li>
<li><p><strong>Generate Database Documentation via DBML:</strong></p>
<p> Convert your SQL DDL into Database Markup Language (DBML) to create interactive database diagrams and documentation.</p>
<p> <strong>Example DBML:</strong></p>
<pre><code class="lang-plaintext"> Table books {
   id int [pk, increment]
   title varchar
   author varchar
   published_date date
   isbn varchar
 }
</code></pre>
<p> <strong>Tools:</strong></p>
<ul>
<li><p><a target="_blank" href="http://dbdiagram.io"><strong>dbdiagram.io</strong></a>: Paste your DBML to visualize and generate documentation.</p>
</li>
<li><p><a target="_blank" href="http://dbdocs.io"><strong>dbdocs.io</strong></a>: Generate and host database documentation online.</p>
</li>
</ul>
</li>
</ol>
<p><strong>Benefit:</strong> Automates the creation of APIs and documentation, ensuring consistency and saving significant development time.</p>
<hr />
<h3 id="heading-example-2-validating-data-with-json-schemas"><strong>Example 2: Validating Data with JSON Schemas</strong></h3>
<p><strong>Scenario:</strong> Before inserting or updating records in your database, you want to ensure the data conforms to your schema.</p>
<ol>
<li><p><strong>Use JSON Schema Validators:</strong></p>
<p> In your API endpoints, validate incoming JSON payloads against the JSON Schema generated from your SQL DDL.</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> Ajv = <span class="hljs-built_in">require</span>(<span class="hljs-string">'ajv'</span>);
 <span class="hljs-keyword">const</span> ajv = <span class="hljs-keyword">new</span> Ajv();
 <span class="hljs-keyword">const</span> validate = ajv.compile(bookJsonSchema);

 app.post(<span class="hljs-string">'/books'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
   <span class="hljs-keyword">const</span> valid = validate(req.body);
   <span class="hljs-keyword">if</span> (!valid) {
     <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({ <span class="hljs-attr">errors</span>: validate.errors });
   }
   <span class="hljs-comment">// Proceed to insert data into the database</span>
 });
</code></pre>
</li>
</ol>
<p><strong>Benefit:</strong> Prevents invalid data from entering your system, reducing runtime errors and ensuring data integrity.</p>
<hr />
<h3 id="heading-example-3-generating-api-documentation"><strong>Example 3: Generating API Documentation</strong></h3>
<p><strong>Scenario:</strong> You want to provide up-to-date API documentation for your team and third-party developers.</p>
<ol>
<li><p><strong>Generate OpenAPI Documentation:</strong></p>
<ul>
<li><p>Use the OpenAPI schema generated from your database schema.</p>
</li>
<li><p>Utilize tools like <strong>Swagger UI</strong> or <strong>Redoc</strong> to render interactive documentation.</p>
</li>
</ul>
</li>
<li><p><strong>Automate Updates:</strong></p>
<ul>
<li><p>Integrate the schema generation into your build pipeline.</p>
</li>
<li><p>Whenever the database schema changes, the OpenAPI docs update automatically.</p>
</li>
</ul>
</li>
</ol>
<p><strong>Benefit:</strong> Ensures that your API documentation is always current and reflects the true state of your APIs.</p>
<hr />
<h2 id="heading-implementing-sdd-and-ssot-in-your-organization">Implementing SDD and SSOT in Your Organization</h2>
<h3 id="heading-1-start-with-your-sql-ddl-as-the-ssot"><strong>1. Start with Your SQL DDL as the SSOT</strong></h3>
<ul>
<li><p>Ensure your database schema is well-defined and includes all necessary constraints and data types.</p>
</li>
<li><p>Use this schema as the foundation for generating all other components.</p>
</li>
</ul>
<h3 id="heading-2-automate-schema-conversion"><strong>2. Automate Schema Conversion</strong></h3>
<ul>
<li><p>Use tools to convert SQL DDL to JSON Schemas and OpenAPI specs.</p>
</li>
<li><p>Examples include <strong>ddl-to-json-schema</strong> or custom scripts using SQL parsing libraries.</p>
</li>
</ul>
<h3 id="heading-3-generate-apis-automatically"><strong>3. Generate APIs Automatically</strong></h3>
<ul>
<li><p><strong>Option 1:</strong> Use frameworks like <strong>Hasura</strong> or <strong>Supabase</strong> for instant GraphQL and REST APIs over your database.</p>
</li>
<li><p><strong>Option 2:</strong> Implement code generators that produce API endpoints based on your schemas.</p>
</li>
</ul>
<h3 id="heading-4-generate-documentation-via-dbml"><strong>4. Generate Documentation via DBML</strong></h3>
<ul>
<li><p>Use tools like <strong>dbml-cli</strong> to convert SQL DDL to DBML.</p>
</li>
<li><p>Generate ER diagrams and host them using <a target="_blank" href="http://dbdiagram.io"><strong>dbdiagram.io</strong></a> or similar services.</p>
</li>
</ul>
<h3 id="heading-5-integrate-into-your-cicd-pipeline"><strong>5. Integrate Into Your CI/CD Pipeline</strong></h3>
<ul>
<li><p>Automate the generation of schemas, APIs, and documentation whenever changes are made to the database schema.</p>
</li>
<li><p>Ensure validation tests run against the updated schemas.</p>
</li>
</ul>
<hr />
<h2 id="heading-challenges-and-how-to-overcome-them">Challenges and How to Overcome Them</h2>
<h3 id="heading-initial-setup-overhead"><strong>Initial Setup Overhead</strong></h3>
<p><strong>Challenge:</strong> Setting up the automation pipeline requires initial effort.</p>
<p><strong>Solution:</strong> Start with critical components and gradually expand. Leverage existing tools and community scripts to reduce development time.</p>
<h3 id="heading-tooling-compatibility"><strong>Tooling Compatibility</strong></h3>
<p><strong>Challenge:</strong> Ensuring all tools work seamlessly with your specific SQL dialect.</p>
<p><strong>Solution:</strong> Verify tool compatibility or consider using intermediate formats like DBML, which supports multiple SQL dialects.</p>
<h3 id="heading-managing-schema-changes"><strong>Managing Schema Changes</strong></h3>
<p><strong>Challenge:</strong> Updating dependent services when the database schema changes.</p>
<p><strong>Solution:</strong> Implement versioning for your APIs and schemas. Use migration tools like <strong>Flyway</strong> or <strong>Liquibase</strong> to manage database changes systematically.</p>
<hr />
<h2 id="heading-conclusion">Conclusion</h2>
<p>Embracing <strong>Schema-Driven Development</strong> and establishing a <strong>Single Source of Truth</strong> by leveraging your SQL DDL can transform your development process. By automating the generation of APIs, validations, and documentation directly from your database schema, you ensure consistency, reduce errors, and accelerate development.</p>
<hr />
<p><strong>Ready to enhance your development workflow? Start by using your SQL DDL as the foundation and automate the generation of your APIs and documentation. Experience the efficiency and reliability that SDD and SSOT bring to your projects.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Accelerating Python: Unveiling the Latest Tools and Innovations]]></title><description><![CDATA[Photo by David Clode on Unsplash
Hello Fellow Pythonistas!
Is it just me, or does the realm of technology and Python seem to be accelerating at an unprecedented pace? As we dive deeper into 2024, the Python ecosystem continues to evolve with incredib...]]></description><link>https://blog.noclocks.dev/modern-python-tooling</link><guid isPermaLink="true">https://blog.noclocks.dev/modern-python-tooling</guid><category><![CDATA[Python]]></category><category><![CDATA[Developer]]></category><category><![CDATA[tools]]></category><category><![CDATA[Rust]]></category><dc:creator><![CDATA[Jimmy Briggs]]></dc:creator><pubDate>Sat, 18 May 2024 01:29:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1716140302994/091a22f3-473f-4baa-86b0-46cb9eee4c99.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Photo by <a target="_blank" href="https://unsplash.com/@davidclode?utm_source=medium&amp;utm_medium=referral">David Clode</a> on <a target="_blank" href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></p>
<p><strong><em>Hello Fellow Pythonistas!</em></strong></p>
<p><em>Is it just me, or does the realm of technology and Python seem to be accelerating at an unprecedented pace? As we dive deeper into 2024, the Python ecosystem continues to evolve with incredible new tools that boost productivity, streamline workflows, and enhance the overall development experience. In this edition, we’ll explore the latest and greatest in Python tooling. Whether you’re a seasoned developer or just getting started, there’s something here for everyone. Let’s jump right in!</em></p>
<h3 id="heading-uv-a-game-changing-package-installer">UV: A Game-Changing Package Installer</h3>
<p><code>uv</code> is a fast Python package installer and resolver written in Rust. Designed as a drop-in replacement for pip and pip-tools workflows, it can also replace <code>virtualenv</code>. This new tool has been met with excitement in the developer community due to its impressive speed and efficiency.</p>
<p><code>uv</code> handles dependencies by leveraging a global cache to avoid re-downloading or re-building them. Supporting a wide range of advanced pip features, including editable installs, Git dependencies, direct URL dependencies, local dependencies, constraints, and source distributions, <code>uv</code> offers comprehensive functionality. Additionally, <code>uv</code> allows users to specify dependency overrides, a useful feature for teams managing multiple large Python dependencies.</p>
<p>The dramatic speed improvement, with <code>uv</code> being anywhere from 10 to 115 times faster than <code>pip</code>, is attributed to its implementation in Rust. This allows <code>uv</code> to achieve unprecedented installation speeds, especially when operating with a warm cache.</p>
<h3 id="heading-ruff-the-ultimate-python-linter-and-formatter">Ruff: The Ultimate Python Linter and Formatter</h3>
<p><code>ruff</code> is a Python linter and code formatter, also written in Rust. Designed to be significantly faster than existing tools such as Flake8 and Black, Ruff integrates more functionality into a single interface. It can be used as a pre-commit hook, a VS Code extension, or a GitHub Action.</p>
<p>Ruff is said to be 30 to 120 times faster than other formatters. It consolidates multiple tools, including <code>Flake8</code>, <code>pyLint</code>, <code>Black</code>, <code>isort</code>, <code>pydocstyle</code>, <code>pyupgrade</code>, and <code>autoflake</code>, into a single interface, reducing the time spent formatting and linting code.</p>
<p>In addition to its speed, Ruff offers configuration options not available in Black, such as setting the desired quote style, indent style, line endings, and more. Ruff’s formatter is designed to have drop-in parity with Black, allowing for seamless integration into projects.</p>
<h3 id="heading-pydantic-rust-powered-data-validation">PyDantic: Rust-Powered Data Validation</h3>
<p><code>pydantic</code> is a popular data validation library whose core has been rewritten in Rust. This enhancement brings improved performance and reliability, making PyDantic an essential tool for developers handling complex data validation tasks.</p>
<h3 id="heading-tokenizers-by-hugging-face">Tokenizers by Hugging Face</h3>
<p>Hugging Face’s implementation of the most common tokenizers has also embraced Rust, offering significant performance improvements for NLP tasks. These tokenizers are essential for anyone working with large language models and text processing.</p>
<h3 id="heading-why-rust">Why Rust?</h3>
<p>Python developers often argue that runtime speed is not a primary concern in many applications, but there are exceptions. When faced with performance bottlenecks, Rust offers an excellent solution. Rust is a systems programming language that enables developers to write blazing-fast applications. It can detect memory management, parallelization, and other issues during compilation, which the Python interpreter/VM might miss.</p>
<p>Rust’s lack of a runtime makes it a perfect candidate for writing extensions for other languages, such as Python. Tools like PyO3 enable seamless interoperation between Python and Rust, allowing developers to write native Python modules in Rust with ease.</p>
<p>Here’s a quick guide to getting started with PyO3 and <code>maturin</code>:</p>
<pre><code class="lang-bash">mkdir hello_python &amp;&amp; <span class="hljs-built_in">cd</span> hello_python
<span class="hljs-comment"># Create and activate a Python virtual environment</span>
python3 -m venv venv
<span class="hljs-built_in">source</span> venv/bin/activate
<span class="hljs-comment"># Install maturin</span>
pip install maturin
<span class="hljs-comment"># Initialize the Rust project and related scaffolding</span>
maturin init
✔ 🤷 Which kind of bindings to use? · pyo3
</code></pre>
<h3 id="heading-controversies-and-impact">Controversies and Impact</h3>
<p>While UV and Ruff have received positive feedback for their features and benefits, some users have raised concerns about the learning curve associated with UV’s asynchronous programming model and the limited feature set of some newer tools compared to more established ones. However, the introduction of UV and Ruff has brought new tools and perspectives to the Python community, offering innovative solutions for building high-performance applications and streamlined workflows.</p>
<p>Stay tuned for more updates and insights on the latest Python tools in our upcoming newsletters!</p>
<p>That’s all for now! Happy coding!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716140301635/dfacc199-a71b-4c8d-aa3f-8b147625f4c9.png" alt /></p>
<p>No Clocks, LLC</p>
]]></content:encoded></item><item><title><![CDATA[Unveiling the Ultimate "R Package Developer Master Resource List"]]></title><description><![CDATA[Overview

This article aims to provide an exhaustive list of helpful tools, packages, and resources for developers, authors, maintainers, reviewers, and stakeholders in the R Package development workflow.

Welcome to the world of R Package Developmen...]]></description><link>https://blog.noclocks.dev/unveiling-the-ultimate-r-package-developer-master-resource-list</link><guid isPermaLink="true">https://blog.noclocks.dev/unveiling-the-ultimate-r-package-developer-master-resource-list</guid><category><![CDATA[R Language]]></category><category><![CDATA[Package Development]]></category><category><![CDATA[Lists]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Jimmy Briggs]]></dc:creator><pubDate>Tue, 27 Feb 2024 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1707151466448/fa9f1cf4-87c0-4276-b2ac-d06998cf4ac5.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[
<p><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-TCRLP6SS" height="0" width="0" style="display:none;visibility:hidden"></iframe>
</p>
<h2 id="heading-overview">Overview</h2>
<blockquote>
<p>This article aims to provide an exhaustive list of helpful tools, packages, and resources for developers, authors, maintainers, reviewers, and stakeholders in the R Package development workflow.</p>
</blockquote>
<p>Welcome to the world of R Package Development! Whether you're a seasoned R programmer looking to expand your toolkit or a newcomer eager to dive into the exciting realm of package development, you've come to the right place. In this comprehensive guide, we'll unveil the essential resources every R package developer needs to master their craft. From tutorials and books to online communities and tools, we've curated a treasure trove of resources to help you embark on your journey towards becoming a proficient R package developer.</p>
<p>Throughout this article, I will provide a walkthrough of the various packages, tools, resources, and axioms I have encountered over my years as an R package software engineer.</p>
<h2 id="heading-r-user-vs-r-developer">R User vs. R Developer</h2>
<p>In the world of R programming, there are distinct roles and distinctions between an <em>R User</em> and an <em>R Developer</em>, each with its own set of responsibilities, skills, and objectives.</p>
<p>To distinguish, R developers <em>develop</em> new innovative solutions while R Users <em>use</em> the tools and packages that the developers created. This article is aimed towards the development side of the spectrum and attempts to provide a comprehensive, curated toolbox for the R Developer, specifically in regard to developing R Packages.</p>
<p>In summary, while both R users and R developers utilize R for data analysis and statistical computing, they differ in their focus and expertise. R users primarily leverage R for data analysis tasks, while R developers specialize in creating and maintaining R packages to enhance the functionality and capabilities of the R programming language for a broader audience of users.</p>
<h3 id="heading-r-users">R Users</h3>
<ul>
<li><p><strong>Definition:</strong> An R user is someone who primarily utilizes R for data analysis, statistical modeling, visualization, and other tasks related to data science, research, or analytics.</p>
</li>
<li><p><strong>Skills &amp; Responsibilities:</strong></p>
<ul>
<li>Proficient in using R for data manipulation, exploration, and analysis.</li>
<li>Familiarity with statistical methods and techniques for interpreting data.</li>
<li>Ability to create visualizations and plots to communicate insights effectively.</li>
<li>Understanding of data structures, functions, and packages within R.</li>
<li>May use R for tasks such as data cleaning, hypothesis testing, regression analysis, and machine learning</li>
</ul>
</li>
<li><p><strong>Objectives:</strong></p>
<ul>
<li>Analyze and interpret data to derive meaningful insights and make data-driven decisions.</li>
<li>Communicate findings through reports, presentations, or visualizations.</li>
<li>Utilize R packages and libraries to streamline analysis workflows and enhance productivity.</li>
<li>Collaborate with colleagues or stakeholders to address specific analytical needs or research questions.</li>
</ul>
</li>
</ul>
<h3 id="heading-r-developer">R Developer</h3>
<ul>
<li><p><strong>Definition:</strong> An R developer is someone who focuses on creating, maintaining, and extending R packages, libraries, and tools for the broader R community.</p>
</li>
<li><p><strong>Skills and Responsibilities:</strong></p>
<ul>
<li>Proficiency in programming with R, including knowledge of object-oriented programming principles, functions, and package development.</li>
<li>Understanding of software engineering practices such as version control, testing, and documentation.</li>
<li>Ability to design, implement, and maintain R packages to address specific needs or solve particular problems.</li>
<li>Familiarity with R package development tools such as <code>devtools</code>, <code>roxygen2</code>, and <code>testthat</code>.</li>
<li>Contribution to the R ecosystem through the creation of new packages, improvement of existing packages, or participation in community discussions and collaborations.</li>
</ul>
</li>
<li><p><strong>Objectives:</strong></p>
<ul>
<li>Develop and release high-quality R packages that provide valuable functionality to users across different domains.</li>
<li>Ensure the reliability, efficiency, and usability of R packages through rigorous testing, documentation, and code review.</li>
<li>Engage with the R community to gather feedback, address issues, and collaborate on package development efforts.</li>
<li>Stay updated on emerging trends, best practices, and advancements in R programming and package development.</li>
</ul>
</li>
</ul>
<h2 id="heading-getting-started">Getting Started</h2>
<p>Now that you understand the difference between an <em>R User ans R Developer</em>, a question arises: "How can one go from being a user to a developer?".</p>
<p>The answer is simple, create something! In this case, create an R Package.</p>
<p>Once you have accumulates more than 2-3 common functions that operate within the same context, that is a primary indicator that you should structure your project as an R Package.</p>
<p>After you have more than one function it starts to get easy to lose track of what your functions do. Similarly, it can start to become difficult to track down, name, and organize the functions and you may be tempted to put all of the functions in one file and just source it. Instead, I propose the best solution is to create an R package.</p>
<h3 id="heading-what-you-need">What you Need</h3>
<p>To begin creating an R Package, you need:</p>
<ul>
<li><a target="_blank" href="https://www.r-project.org/">R</a> and <a target="_blank" href="https://www.rstudio.com/">RStudio</a> installed on your machine</li>
<li><a target="_blank" href="https://git-scm.com/">Git</a> and <a target="_blank" href="https://github.com">GitHub</a></li>
<li>Some initial R functions</li>
<li>R Development Packages:<ul>
<li><code>devtools</code></li>
<li><code>usethis</code></li>
<li><code>roxygen2</code></li>
<li><code>pak</code></li>
<li><code>knitr</code> and <code>rmarkdown</code></li>
</ul>
</li>
</ul>
<p>From there you can continue to naming your package, scaffolding out its structure, adding functions, documentation, metadata, data, license, vignettes, etc.</p>
<h2 id="heading-pre-requisite-resources">Pre-Requisite Resources</h2>
<p>To start, R package developers need to be familiar with the fundamentals of package development, and therefore should be familiar with some of the highest regarded resources available to read.</p>
<p>Anyone who is serious about developing production grade R packages needs to be familiar with most of, if not all of the following resources and guides:</p>
<center><p>Table 1: R Package Developer Essentials</p></center>

<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Resource</strong></td><td><strong>Source</strong></td></tr>
</thead>
<tbody>
<tr>
<td><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">Writing R Extensions</a></td><td><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">CRAN Manuals</a></td></tr>
<tr>
<td><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">R Pac</a><a target="_blank" href="https://cran.r-project.org/manuals.html">kages</a></td><td><a target="_blank" href="https://cran.r-project.org/manuals.html">H</a><a target="_blank" href="http://r-pkgs.had.co.nz/">ad</a><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">ley Wickham</a></td></tr>
<tr>
<td><a target="_blank" href="https://cran.r-project.org/manuals.html">R</a> <a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">Package Pri</a><a target="_blank" href="https://cran.r-project.org/manuals.html">me</a><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">r</a></td><td><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">Karl Br</a><a target="_blank" href="https://cran.r-project.org/manuals.html">oman</a></td></tr>
<tr>
<td><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">Package Gu</a><a target="_blank" href="https://cran.r-project.org/manuals.html">idelines</a></td><td><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">Biocondu</a><a target="_blank" href="https://cran.r-project.org/manuals.html">ctor</a></td></tr>
<tr>
<td><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">rOpenSc</a><a target="_blank" href="https://cran.r-project.org/manuals.html">i Packages</a> <a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">Developer G</a><a target="_blank" href="https://cran.r-project.org/manuals.html">uide</a></td><td><a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">rOpenSci</a></td></tr>
</tbody>
</table>
</div><details><summary>View Citations:</summary><p>
<span class="citation">(<a href="#ref-wickhamb">Wickham and Bryan, n.d.a</a>, <a href="#ref-wickhamc">n.d.b</a>; <a href="#ref-whypacka"><span>“Why Package and Environment Management Is Critical for Serious Data Science,”</span> n.d.a</a>, <a href="#ref-whypackb">n.d.b</a>; <a href="#ref-vidoni">Vidoni, n.d.</a>; <a href="#ref-initiativea">Initiative, n.d.</a>; <a href="#ref-anintro"><span>“An Introduction to Packager,”</span> n.d.</a>; <a href="#ref-gandrud2015">Gandrud 2015</a>; <a href="#ref-glennie2020">Glennie 2020</a>; <a href="#ref-owen-the"><span>“Owen-TheRGuide.pdf,”</span> n.d.</a>; <a href="#ref-riederera">Riederer, n.d.</a>; <a href="#ref-spector2004">Spector 2004</a>; <a href="#ref-teama">Team, n.d.</a>; <a href="#ref-zhua">Zhu and Jianan, n.d.</a>)</span>
</p></details>

<h3 id="heading-writing-r-extensions-manual">Writing R Extensions Manual</h3>
<p>The <a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">Writing R Extensions Manual</a> is perhaps the most crucial resource listed above, and has even been considered the <em>Bible of R Package Development</em>.</p>
<p>As Hadley puts it in his book <a target="_blank" href="http://cran.fhcrc.org/doc/manuals/R-exts.html">Writing R Packages</a>:</p>
<blockquote>
<p><em>"The best resource for the official details of package development is always the official writing R extensions manual. However, this manual can be hard to understand if you’re not already familiar with the basics of packages. It’s also exhaustive, covering every possible package component, rather than focusing on the most common and useful components, as this book does. Writing R extensions is a useful resource once you’ve mastered the basics and want to learn what’s going on under the hood.”</em></p>
<p><em>— Hadley Wickham</em></p>
</blockquote>
<p>Thanks to <a target="_blank" href="https://colinfay.me/">Colin Fay</a>, a more elegant version of the original manual has been created as a bookdown site and published online at <a target="_blank" href="https://colinfay.me/writing-r-extensions">https://colinfay.me/writing-r-extensions</a>.</p>
<p><em>Note: The other manuals listed on the <a target="_blank" href="https://cran.r-project.org/manuals.html">CRAN Manuals website</a> contain a lot of hidden gems that are often overlooked by R developers. These resources contain some of the most crucial, foundational knowledge that anyone using R should eventually be made aware of, therefore I highly recommend you check those out in addition to Writing R Extensions</em>.</p>
<h3 id="heading-r-packages-book">R Packages Book</h3>
<p>The "R Packages" (2nd Edition) Book outlines the importance of packages in R as the fundamental unit of shareable code, combining code, data, documentation, and tests.</p>
<p>It highlights the vast array of over 19,000 packages on CRAN and encourages readers to develop their own packages for easier code sharing and organization. The book aims to automate package development as much as possible, utilizing the <code>devtools</code> and <code>usethis</code> packages and the RStudio IDE for a more efficient workflow.</p>
<p>For a detailed overview, visit the <a target="_blank" href="https://r-pkgs.org/introduction.html">introduction page</a>.</p>
<h3 id="heading-r-package-primer">R Package Primer</h3>
<p>The "R package primer" provides a minimal tutorial on creating R packages, emphasizing their simplicity and utility for code distribution and personal organization. The primer covers essential topics like package creation, documentation, and checking, alongside advanced topics like GitHub integration, CRAN submission, and writing vignettes. It advocates for package development as a practice for better code management and documentation, even for personal use. For more detailed guidance, visit <a target="_blank" href="https://kbroman.org/pkg_primer/">Karl Broman's R package primer</a>.</p>
<h3 id="heading-bioconductor-package-guidelines">Bioconductor Package Guidelines</h3>
<p>The "Bioconductor Packages: Development, Maintenance, and Peer Review" guide offers comprehensive insights into the creation, upkeep, and review process of Bioconductor packages. Authored by Kevin Rue-Albrecht, Daniela Cassol, Johannes Rainer, and Lori Shepherd, it serves as an essential resource for developers within the Bioconductor project, promoting high-quality, well-documented, and interoperable software. Contributions to the guide are welcome via GitHub, indicating a collaborative and open-source approach to improving package development practices. For more details, visit the <a target="_blank" href="https://contributions.bioconductor.org/index.html">Bioconductor contributions guide</a>.</p>
<h3 id="heading-ropensci-packages-development-primer">rOpenSci Packages Development Primer</h3>
<p>The "rOpenSci Packages: Development, Maintenance, and Peer Review" guide is a comprehensive resource designed for developers involved in the rOpenSci project. It covers a wide range of topics from package development, continuous integration, security best practices, to the software peer review process. It also includes guidance on package maintenance, collaboration, and marketing. Authored by the rOpenSci software review editorial team, it is an essential read for anyone looking to contribute to the rOpenSci ecosystem. For detailed information, visit the <a target="_blank" href="https://devguide.ropensci.org/index.html">rOpenSci Development Guide</a>.</p>
<h2 id="heading-r-packages">R Packages</h2>
<p>Next, I will provide a comprehensive list of R Packages that aim to assist the development process.</p>
<h3 id="heading-essentials">Essentials</h3>
<blockquote>
<p>The following packages represent Core Development Libraries <em>and should generally be utilized in all scenarios of package development.</em></p>
</blockquote>
<h4 id="heading-devtools-and-usethis">Devtools and Usethis</h4>
<p><strong>For automating the development workflow:</strong></p>
<ul>
<li><a target="_blank" href="https://devtools.r-lib.org/"><code>devtools</code></a> - The <code>devtools</code> package is a fundamental tool for R package development, providing functions for package creation, documentation, testing, and deployment. It streamlines the development process by automating common tasks like building, checking, and installing packages, making it an indispensable tool for R developers.</li>
<li><a target="_blank" href="https://usethis.r-lib.org/"><code>usethis</code></a> - The <code>usethis</code> package offers a collection of functions for automating package development workflows, including project setup, file creation, and version control integration. It simplifies common tasks like creating package directories, adding functions, and managing dependencies, enhancing productivity and efficiency for R developers.</li>
</ul>
<h4 id="heading-documentation">Documentation</h4>
<p><strong>For generating manual pages and documentation:</strong></p>
<ul>
<li><code>roxygen2</code> - The <code>roxygen2</code> package simplifies the process of documenting R code by generating Roxygen-style comments from function definitions. It enables developers to create consistent, well-formatted documentation for their packages, enhancing readability and maintainability. By automating the documentation process, <code>roxygen2</code> ensures that package documentation stays up-to-date with code changes, facilitating collaboration and code sharing.</li>
<li><code>knitr</code> &amp; <code>rmarkdown</code> - The <code>knitr</code> and <code>rmarkdown</code> packages provide tools for creating dynamic reports, presentations, and documentation in R. They enable developers to embed R code, plots, and text in a single document, facilitating reproducible research and effective communication of results. By combining code and narrative in a single document, <code>knitr</code> and <code>rmarkdown</code> enhance the clarity and transparency of package documentation, making it easier for users to understand and utilize the package.</li>
</ul>
<h4 id="heading-testing">Testing</h4>
<p><strong>For testing:</strong></p>
<ul>
<li><p><code>testthat</code> - The <code>testthat</code> package is a unit testing framework for R that enables developers to write and run tests for their code. It provides functions for defining test cases, running tests, and reporting results, ensuring that packages behave as expected across different scenarios. By incorporating test-driven development practices, <code>testthat</code> helps developers identify and fix bugs early in the development process, improving code quality and reliability.</p>
</li>
<li><p><code>tinytest</code> - The <code>tinytest</code> package is a lightweight testing framework for R that simplifies the process of writing and running tests. It offers a simple and intuitive interface for defining test cases, running tests, and reporting results, making it easy for developers to validate their code and ensure its correctness. By providing a minimalistic testing solution, <code>tinytest</code> streamlines the testing process and enhances the quality and robustness of R packages.</p>
</li>
<li><p><code>shinytest2</code> - The <code>shinytest2</code> package is a testing framework for Shiny applications that enables developers to automate the testing of interactive web applications. It provides functions for recording and replaying user interactions, capturing screenshots, and comparing outputs, ensuring that Shiny apps behave as expected across different environments. By automating the testing process, <code>shinytest2</code> helps developers identify and fix issues in their Shiny apps, improving user experience and reliability.</p>
</li>
</ul>
<h4 id="heading-dependency-management">Dependency Management</h4>
<p><strong>For managing package dependencies:</strong></p>
<ul>
<li><code>pak</code> - The <code>pak</code> package is a lightweight dependency management tool for R that simplifies the installation and management of package dependencies. It provides functions for installing, updating, and removing packages, ensuring that packages are installed from reliable sources and compatible with the current R environment. By automating dependency management tasks, <code>pak</code> streamlines the package development process, reducing the risk of conflicts and errors.</li>
<li><code>remotes</code> - The <code>remotes</code> package offers functions for installing packages from remote repositories like GitHub, GitLab, and Bitbucket. It enables developers to install packages directly from source control repositories, facilitating collaboration and sharing of packages across different platforms. By providing a flexible and extensible interface for package installation, <code>remotes</code> enhances the accessibility and availability of R packages for developers and users.</li>
<li><code>renv</code> - The <code>renv</code> package is a dependency management tool for R that creates isolated project environments with specific package versions. It enables developers to capture and manage package dependencies within a project, ensuring reproducibility and consistency across different environments. By creating project-specific package libraries, <code>renv</code> helps developers avoid conflicts and ensure that packages are installed and loaded correctly, enhancing the reliability and portability of R projects.</li>
</ul>
<h3 id="heading-useful-common-libraries">Useful Common Libraries</h3>
<ul>
<li><code>available</code> - Check if a package is available on CRAN</li>
<li><code>lifecycle</code> - represent package and function development lifecycle stages</li>
<li><code>desc</code> - Manage and edit the package's <code>DESCRIPTION</code></li>
<li><code>pkgdown</code> - Generate package documentation static site</li>
<li><code>testdown</code> - Generate test reports</li>
<li><code>gitdown</code> - Generate git commit messages</li>
</ul>
<h3 id="heading-roxygen-tools">Roxygen Tools</h3>
<ul>
<li><code>roxygen2md</code></li>
<li><code>roxyglobals</code></li>
<li><code>rd2list</code></li>
<li><code>Rd2roxygen</code></li>
<li><code>rd2markdown</code></li>
<li><code>roxygen2comment</code></li>
</ul>
<h3 id="heading-dependency-tools">Dependency Tools</h3>
<ul>
<li><code>attachment</code> - Attach and detach packages</li>
<li><code>automagic</code> - Automatically install and load packages</li>
<li><code>CodeDepends</code> - Identify dependencies between functions</li>
<li><code>dep</code> - Dependency management</li>
<li><code>sysreqs</code> - Identify system requirements for R packages</li>
<li><code>pkgnet</code> - Visualize package dependencies</li>
<li><code>functiondepends</code> - Identify dependencies between functions</li>
</ul>
<h3 id="heading-git-and-github">Git and GitHub</h3>
<ul>
<li><code>gert</code> - Git tools</li>
<li><code>gitdown</code> - Generate git reports</li>
<li><code>git2r</code> - Git interface</li>
<li><code>gh</code> - GitHub interface</li>
<li><code>git4r</code> - Git interface</li>
<li><code>gitGPT</code> - Git interface with GPT-3</li>
<li><code>precommit</code> - Pre-commit hooks</li>
</ul>
<h3 id="heading-configuration">Configuration</h3>
<ul>
<li><code>config</code> - Configuration management</li>
<li><code>options</code> - Set and get options</li>
</ul>
<h3 id="heading-credentials-amp-secrets">Credentials &amp; Secrets</h3>
<ul>
<li><code>keyring</code> - Securely store and retrieve credentials</li>
<li><code>credentials</code> - Securely store and retrieve credentials</li>
<li><code>gitcreds</code> - Securely store and retrieve git credentials</li>
<li><code>ssh</code> - SSH interface</li>
<li><code>askpass</code> - Prompt for passwords</li>
</ul>
<p>plus, base R's <code>Sys.genenv()</code> and <code>Sys.setenv()</code>.</p>
<h3 id="heading-fundamental-low-level-packages">Fundamental Low-Level Packages</h3>
<blockquote>
<p>These packages are not necessarily called directly but are built on top of as dependencies to higher level libraries (i.e. <code>usethis</code>, <code>devtools</code>, etc.)</p>
</blockquote>
<ul>
<li><code>pkgload</code> - Load packages</li>
<li><code>pkgbuild</code> - Build packages</li>
<li><code>pkgdepends</code> - Manage package dependencies</li>
<li><code>pkgapi</code> - Manage package API</li>
<li><code>pkgcache</code> - Manage package cache</li>
<li><code>pkgnet</code> - Visualize package dependencies</li>
</ul>
<h3 id="heading-linting-amp-styling">Linting &amp; Styling</h3>
<ul>
<li><code>goodpractice</code> - Check package quality</li>
<li><code>lintr</code> - Lint R code</li>
<li><code>styler</code> - Style R code</li>
<li><code>formatR</code> - Format R code</li>
<li><code>stylermd</code> - Style R Markdown</li>
<li><code>spelling</code> - Spell check R code</li>
<li><code>roxylint</code> - Lint Roxygen comments</li>
<li><code>cleanr</code> - Clean R code</li>
<li><code>janitor</code> - Clean R Dataframe</li>
<li><code>sanitizers</code> - Sanitize R code</li>
<li><code>refactor</code> - Refactor R code</li>
</ul>
<h3 id="heading-package-documentation">Package Documentation</h3>
<ul>
<li><code>docthis</code> - Document R objects</li>
<li><code>prettydoc</code> - Custom RMardown templates</li>
<li><code>quarto</code> - New RMarkdown'ish package</li>
<li><code>pkgdown</code> - Generate package documentation</li>
<li><code>testdown</code> - Generate test reports</li>
<li><code>autodoc</code> - Automatically document R objects</li>
<li><code>papillon</code> - Create internal functions for launching documentation</li>
<li><code>fusen</code> - RMarkdown driven package development</li>
<li><code>badger</code> - Generate badges for R packages</li>
<li><code>badgen</code> - Generate badges for R packages</li>
<li><code>bookdown</code> - Generate books from RMarkdown</li>
<li><code>bookdownplus</code> - Generate books from RMarkdown</li>
<li><code>altdoc</code> - Generate alternative documentation</li>
<li><code>fledge</code> - Automate <code>NEWS.md</code></li>
<li><code>newsmd</code> - Automate <code>NEWS.md</code></li>
<li><code>autonewsmd</code> - Automate <code>NEWS.md</code></li>
<li><code>docreview</code> - Review documentation</li>
<li><code>covrpage</code> - Generate coverage reports</li>
</ul>
<h3 id="heading-metadata">Metadata</h3>
<ul>
<li><code>codemeta</code> - Generate CodeMeta metadata</li>
<li><code>codemetar</code> - Generate CodeMeta metadata</li>
<li><code>pkgstats</code> - Generate package statistics</li>
<li><code>sessioninfo</code> - Generate session information</li>
</ul>
<h3 id="heading-checks-amp-tests">Checks &amp; Tests</h3>
<ul>
<li><code>rcmdcheck</code> - <code>R CMD CHECK</code> runner</li>
<li><code>testdat</code> - Generate test data</li>
<li><code>validate</code> - Validation and Data Quality</li>
<li><code>realtest</code> - Real world testing</li>
<li><code>roxytest</code> - Test Roxygen comments</li>
<li><code>checkhelper</code> - Helper functions for <code>R CMD CHECK</code></li>
<li><code>codetools</code> - Code analysis tools</li>
<li><code>checkglobals</code> - Check global variables</li>
<li><code>rhub</code> - Check R packages on various platforms</li>
</ul>
<h3 id="heading-validation-and-assertions">Validation and Assertions</h3>
<ul>
<li><code>assertthat</code> - Assertions</li>
<li><code>checkmate</code> - Assertions</li>
<li><code>assertive</code> - Assertions</li>
<li><code>assertthat</code> - Assertions</li>
<li><code>assert</code> - Assertions</li>
<li><code>pointblank</code> - Validation</li>
</ul>
<h3 id="heading-utilities">Utilities</h3>
<ul>
<li><code>fs</code> - File system interface</li>
<li><code>purrr</code> - Functional programming</li>
<li><code>dplyr</code> - Data manipulation</li>
<li><code>tidyr</code> - Data manipulation</li>
<li><code>stringr</code> - String manipulation</li>
<li><p><code>lubridate</code> - Date manipulation</p>
</li>
<li><p><code>DBI</code> - Database interface</p>
</li>
<li><code>dbx</code> - Database interface</li>
<li><code>RPostgres</code> - DBI compliant interface for PostgreSQL</li>
<li><code>dbplyr</code> - Database interface with <code>dplyr</code></li>
<li><code>connections</code> - Database connections</li>
<li><p><code>pool</code> - Database connection pooling</p>
</li>
<li><p><code>dm</code> - Data Modeling</p>
</li>
<li><p><code>datamodelr</code> - Data Modeling</p>
</li>
<li><p><code>plumber</code> - API development</p>
</li>
<li><p><code>cli</code> - Command line interface</p>
</li>
<li><p><code>logger</code> - Logging</p>
</li>
<li><p><code>snakecase</code> - Convert snake case</p>
</li>
<li><p><code>prefixer</code> - Add prefixes to functions</p>
</li>
<li><p><code>addinit</code> - Add script headers</p>
</li>
<li><p><code>shiny</code> - Shiny apps</p>
</li>
<li><code>htmltools</code> - HTML tools</li>
<li><code>shinyjs</code> - Shiny JavaScript</li>
<li><code>golem</code> - Shiny app development</li>
<li><p><code>packer</code> - Package JavaScript with R code</p>
</li>
<li><p><code>roger</code> - R Markdown driven package development</p>
</li>
<li><p><code>patrick</code> - Automate package development</p>
</li>
<li><p><code>cachem</code> - Caching</p>
</li>
<li><code>memoise</code> - Caching</li>
<li><code>qs</code> - Quick serialization for caching</li>
<li><p><code>digest</code> - Hashing</p>
</li>
<li><p><code>R6</code> - Object oriented programming</p>
</li>
<li><p><code>cranlogs</code> - CRAN download logs</p>
</li>
<li><p><code>dlstats</code> - CRAN download logs</p>
</li>
<li><p><code>oysteR</code> - RStudio addin</p>
</li>
<li><p><code>foghorn</code> - RStudio addin</p>
</li>
<li><p><code>actions</code> - GitHub actions</p>
</li>
<li><code>rworkflows</code> - R Workflows</li>
<li><code>tic</code> - timing</li>
<li><p><code>tictoc</code> - timing</p>
</li>
<li><p><code>gpg</code> - GPG interface</p>
</li>
<li><p><code>debugr</code> - Debugging</p>
</li>
<li><p><code>valtools</code> - Validation tools</p>
</li>
<li><p><code>pkgcond</code> - Package conditions</p>
</li>
<li><p><code>riskmetric</code> - Risk metrics</p>
</li>
<li><p><code>represtools</code> - Reproducible research tools</p>
</li>
<li><p><code>containerit</code> - Containerize R code</p>
</li>
<li><code>dockerfiler</code> - Dockerfile generator</li>
</ul>
<ul>
<li><p><code>onetime</code> - One time code execution</p>
</li>
<li><p><code>gitignore</code> - Generate <code>.gitignore</code> files</p>
</li>
</ul>
<ul>
<li><p><code>whoami</code> - User information</p>
</li>
<li><p><code>rprojroot</code> - Project root</p>
</li>
<li><p><code>here</code> - Project root</p>
</li>
<li><p><code>whisker</code> - Templating</p>
</li>
<li><p><code>magick</code> - Image processing</p>
</li>
<li><p><code>waldo</code> - Low-Level R Objects</p>
</li>
<li><p><code>vctrs</code> - Vector manipulation</p>
</li>
<li><p><code>conflicted</code> - Conflict resolution</p>
</li>
<li><p><code>webfakes</code> - Web scraping</p>
</li>
<li><p><code>ps</code> - Process management</p>
</li>
<li><code>processx</code> - Process management</li>
<li><code>callr</code> - Process management</li>
<li><p><code>withr</code> - Process management</p>
</li>
<li><p><code>evaluate</code> - Evaluate R code</p>
</li>
<li><p><code>systemfonts</code> - System fonts</p>
</li>
<li><p><code>later</code> - Future</p>
</li>
<li><code>future</code> - Future</li>
<li><p><code>promises</code> - Promise</p>
</li>
<li><p><code>pillar</code> - Tidy printing</p>
</li>
<li><code>pretyunits</code> - Pretty units</li>
<li><code>progress</code> - Progress bars</li>
</ul>
<ul>
<li><code>bench</code> - Benchmarking</li>
<li><p><code>profvis</code> - Profiling</p>
</li>
<li><p><code>ymlthis</code> - YAML</p>
</li>
<li><p><code>piggyback</code> - Data sharing</p>
</li>
<li><p><code>itdepends</code> - Dependency management</p>
</li>
<li><p><code>dependencies</code> - Dependency management</p>
</li>
<li><p><code>ellipsis</code> - Ellipsis (<code>...</code>)</p>
</li>
<li><p><code>miniUI</code> - Shiny UI</p>
</li>
<li><p><code>rversions</code> - R versions</p>
</li>
<li><p><code>pingr</code> - Ping URLs</p>
</li>
<li><p><code>rcompendium</code> - Research Compendium</p>
</li>
<li><p><code>litr</code> - Literate programming</p>
</li>
<li><p><code>leprechaun</code></p>
</li>
<li><code>pkgverse</code></li>
<li><code>metamakr</code></li>
</ul>
<h2 id="heading-summary">Summary</h2>
<ol>
<li><p>Understanding the Basics: Before delving into the intricacies of package development, it's crucial to grasp the fundamental concepts of R programming. Resources like "R for Data Science" by Hadley Wickham and Garrett Grolemund serve as an excellent starting point for beginners, providing a comprehensive overview of R programming essentials and data manipulation techniques.</p>
</li>
<li><p>Mastering Package Development: Once you've familiarized yourself with the basics, it's time to dive into the world of package development. The "R Packages" book by Hadley Wickham is the go-to resource for understanding the principles of package structure, documentation, and best practices. Additionally, online tutorials from platforms like DataCamp and RStudio provide hands-on guidance for creating your first R package from scratch.</p>
</li>
<li><p>Harnessing the Power of Version Control: Effective version control is essential for managing the development and collaboration of R packages. Platforms like GitHub offer robust version control capabilities, allowing developers to track changes, collaborate with peers, and maintain a history of their package development journey. Resources such as "Happy Git and GitHub for the useR" by Jenny Bryan provide comprehensive guides to mastering Git and GitHub workflows tailored specifically for R users.</p>
</li>
<li><p>Engaging with the Community: The R community is a vibrant ecosystem bustling with passionate developers, users, and enthusiasts. Engaging with online communities such as Stack Overflow, RStudio Community, and the R4DS Slack channel enables you to seek guidance, share insights, and collaborate with fellow developers. Conferences like useR! and rstudio::conf provide opportunities to connect with experts, attend workshops, and stay updated on the latest trends in R package development.</p>
</li>
<li><p>Streamlining Development with Tools and Packages: As you progress on your journey, leveraging tools and packages designed for R package development can significantly enhance your productivity and efficiency. Tools like devtools, roxygen2, and testthat streamline package development tasks such as building, documenting, and testing your code. Additionally, exploring specialized packages like usethis and pkgdown empowers you to automate common development workflows and create polished package documentation and websites with ease.</p>
</li>
</ol>
<h2 id="heading-schedule-with-us">Schedule with Us</h2>
<div class="hn-embed-widget" id="scheduler"></div>]]></content:encoded></item></channel></rss>