<?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[The Technical Leader]]></title><description><![CDATA[Bringing 15+ years of software and development expertise married with decades of leadership experience, I provide a unique and honest take on leading software t]]></description><link>https://blog.dniccumdesign.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>The Technical Leader</title><link>https://blog.dniccumdesign.com</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 09 Jun 2026 08:15:26 GMT</lastBuildDate><atom:link href="https://blog.dniccumdesign.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Staying vigilant in the AI coding gold rush: from generation to delivery]]></title><description><![CDATA[For those who haven't worked inside the corporate world, the continuous tango of "look at metrics, adjust; look at metrics, adjust" is a never-ending cycle that we, as mid-level managers and directors]]></description><link>https://blog.dniccumdesign.com/staying-vigilant-in-the-ai-coding-gold-rush-from-generation-to-delivery</link><guid isPermaLink="true">https://blog.dniccumdesign.com/staying-vigilant-in-the-ai-coding-gold-rush-from-generation-to-delivery</guid><category><![CDATA[AI]]></category><category><![CDATA[Editorial]]></category><category><![CDATA[opinion]]></category><category><![CDATA[codereview]]></category><category><![CDATA[code review]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Fri, 29 May 2026 14:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/8b8791c9-ad3f-4e13-b47d-17fbee8f36cc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For those who haven't worked inside the corporate world, the continuous tango of "look at metrics, adjust; look at metrics, adjust" is a never-ending cycle that we, as mid-level managers and directors, must both endure and champion for our reports. These metrics can be used to analyze almost anything about our personal performance and that of our teams. As the organizations we work for grow larger and more complex, context and awareness (of the application and situation) usually diminish. This awareness is replaced by a focus on delivering features and meeting financial and velocity goals.</p>
<div>
<div>🤔</div>
<div><em>What's ironic is "context" is one of the pillars that quality AI prompts and commands are built on. The more it knows, the better the result.</em></div>
</div>

<p>You might be asking yourself, "What metrics am I talking about?" I'm referring to productivity metrics, <a href="https://dora.dev/guides/dora-metrics/"><strong>DORA metrics</strong></a>, but more specifically: lines of code generated. It would seem logical to equate lines of code written with productivity, right? The more code written, the more is delivered to the customer—making the application better, allowing more features to be sold, which means more money. Again, on the surface this makes sense and has been a point of emphasis in my experience. But the more I think about it, just because we are writing more code with AI <em>are we actually more productive</em>? I am not entirely convinced.</p>
<p>Let's dive into it.</p>
<hr />
<h2>A quick story</h2>
<p>Recently I have attended a series of management meetings where the subject of AI metrics and its usage have been a topic of discussion. Further debates about which models work in which situation, and token-spend among others dominate the forum. Likely a pretty standard "corporate AI" meeting. However one point of discussion always seems to surface again and again: usage. The overwhelming common sentiment between each meeting is the ever-increasing lines of code being generated by our agents. The accompanying narrative being paired with this analysis is:</p>
<blockquote>
<p>Our teams have never been more productive. We are writing more code than we ever have and we are shipping more features than any other point in the company's history.</p>
</blockquote>
<p>Sounds like a pretty successful and celebratory conclusion eh? Initially I thought so. Code makes our applications function, functions create features, features means more money; so more code must be good right? But the more I got to thinking, there are other elements that go into code and features. Things like code reviews, security audits, unit tests, and so on. Technically you could use AI to perform these tasks, but <em>(other than the unit tests)</em> you really shouldn't. These things take time, more time to do it right, and even <em>more time</em> when you include multiple people in the process.</p>
<p>I recognize I am just one manager/developer, one <em>lowly</em> manager/developer. I also recognize that my opinion is just one small grain of sand in the desert that is the AI efficiency discussion. But I cannot help my skepticism of these <strong>MASSIVE</strong> gains surrounding the deployment of AI in software development practices.</p>
<h2>More isn't always better</h2>
<p><em>As a small disclaimer</em>, I am basing a bulk of my argument with the assumption your company is following standard development processes, like writing unit tests, performing code reviews and such. If you <em>aren't</em> doing these things and just deploying AI-generated code to production without even the slightest review, then God's speed to you. Hope you have good insurance when your data gets ransomed.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/48378cae-2048-48aa-9dde-ed0dabe6594f.png" alt="" style="display:block;margin:0 auto" />

<p>Now let's continue.</p>
<hr />
<p>When we leverage AI to rapidly generate code, it's hard to not be in awe of the speed and accuracy it is able to do so. Some outlets are reporting developers are seeing as much as a <a href="https://sloanreview.mit.edu/article/the-hidden-costs-of-coding-with-generative-ai/">55% percent increase of productivity</a>, with a reduction of lead time for tasks by as much as half. More often than not, the code that is generated is pretty accurate and clean; especially if your <a href="https://linear.app/developers/aig">agent guidelines</a> are clear and actionable. The magic of typing a prompt and getting a working output will inevitably lull you into this result-driven comatose. It certainly has for me. The ease and luxury provided to you by your coding agent of choice makes it very easy to simply bypass the processes and protocols you would normally follow for your own code: unit tests, user-acceptance testing, quality assurance, security analysis, and so on. If the code works, why would I change it and why would I test it?</p>
<h3>The "mechanism of structural decay"</h3>
<p>If you have worked with AI long enough, you are likely to notice the trend of: <em>write, create, write, append, write, refactor</em>. The agent's immediate response to a prompt is to write code, regardless if you need it to or not. According to a study done by <a href="https://www.gitclear.com/ai_assistant_code_quality_2025_research">GitClear</a> and <a href="https://www.sonarsource.com/blog/the-inevitable-rise-of-poor-code-quality-in-ai-accelerated-codebases">Sonar</a> citing:</p>
<blockquote>
<p>an 8-fold increase in the frequency of code blocks containing five or more duplicated lines, confirming a significant decline in code reuse. Furthermore, 2024 was the first year where the number of copy/pasted lines exceeded the number of moved (refactored) lines.</p>
</blockquote>
<p>What this crazy statistic ultimately points to is ever-growing code bases that are discarding the DRY (<strong>D</strong>o not <strong>R</strong>epeat <strong>Y</strong>ourself) principles that were drilled into us as junior developers. What this <em>also</em> means is our code is growing larger and thus reducing efficiency and long-term maintainability. This quote from Sonar's article says it beautifully, "structural debt arises because LLMs prioritize local functional correctness over global architectural coherence and long-term maintainability." So despite the numerous additions and augmentations to our code, we could be only making it worse and thus damning our application to the pits of volatility.</p>
<h3>Instability at the cost of insatiable productivity</h3>
<p>According to a <a href="https://cloud.google.com/resources/content/2025-dora-ai-assisted-software-development-report">Google 2025 DORA Report</a>, the folks over at Google found a 90% increase in AI-generated code also brought about a 9% increase in reported bugs and over a 150% increase in pull/merge request size. If you take these numbers at face value, there are a few big things that should jump out at you:</p>
<p><em><strong>Our code bases are growing at an alarming rate.</strong></em> I recently reviewed a merge request in GitLab that included 388 lines of net new code (not changes or deletions). Let's assume the developer of this merge request does this four more times over the course of a week. In a month, this means a single developer will have <strong>introduced 13,580 net new lines</strong> of code into the project, in a single month. If that amount of new code is being written and merged into the repository at that rate, I would have some genuine concerns over the amount of duplicated code, and code that is just unnecessary.</p>
<p><em><strong>The number of bugs will grow as well.</strong></em> On the surface, a 9% increase of reported bugs does sound like a lot, but I believe it is so much worse than that. All developers know all bugs are not created equal. They require time to analyze and troubleshoot, and even more time to fix regardless if you use AI or not. As the code base grows, the introduction of bugs is inevitable no matter the amount of testing or QA is done to prevent them (unless your company's name is <a href="https://linear.app/">Linear</a>. Those guys know how to produce a clean product; props). But I digress.</p>
<p>Let's go back to the example we were using above. Let's assume for every three merge requests, one bug is introduced. In addition to this, another bug is introduced for every 5,000 lines of code. This means, keeping to the cadence of this developer's AI-powered productivity, in one month, our developer would have <strong>introduced around eight bugs</strong>. Now, as I was hinting at earlier, these issues could be very simple and depending your CI/CD process, a resolution could be deployed in a matter of minutes. No harm, no foul right? However some of these issues could be debilitating outages, causing lost progress and lost revenue for your business; <em>all from a single developer</em>.</p>
<div>
<div>🤨</div>
<div>Please know, the numbers that I used above are not actual numbers from me or any of my team. They are simply just examples .</div>
</div>

<p><em><strong>This code needs to be tested and reviewed.</strong></em> If you are following prototypical development processes, we are probably aligned in the fact of code should be tested by both a human (QA) and a machine (automated unit/feature testing). All of these things takes time, even testing that has been automated. Depending on the size of the code base and testing coverage you have for your application, these tests take time to run. And if you are running these tests on dedicated resources, they also cost money. Code reviews by humans also cost money. Yes, it takes time for another developer to review, test, and smoke check the code. This has a cost. But what people don't think about is the productivity that is also lost due to that developer not coding. So in essence, every code review costs <em>twice</em> of what a developer costs during that same timeframe.</p>
<h2>The cost of doing it right</h2>
<p>For those of us in the tech and software industry, you are likely aware of the meme: "You can have it good, fast, or cheap, but it cannot be all three." Quality, at speed, comes with a cost. This also applies to testing, but even <em>more so when it comes to AI generated code.</em></p>
<p>A 2025 study showed that senior engineers spend an average of 4.3 minutes evaluating AI-generated suggestions, versus 1.2 minutes for code written by humans. Meanwhile, teams that rely heavily on AI are delivering substantially more pull requests. Faros AI examined data from over 10,000 developers and found a 98% rise in PR volume. Consequently, PR review time increased by 91%, even though the code generation process itself became faster. A <a href="https://www.qodo.ai/reports/state-of-ai-code-quality/">Qodo survey</a> found that 68% of senior engineers report quality improvements from AI, but only 26% would ship AI-generated code without review (I'm surprised its that high).</p>
<p>So lets play this out. Lets assume you have a development team that makes the following hourly rates:</p>
<ul>
<li><p>Junior/intermediate developers: about \(50 per hour (or \)0.83 per minute)</p>
</li>
<li><p>Mid-level developers: about \(100 per hour (or \)1.67 per minute)</p>
</li>
<li><p>Senior/lead developers or architects: about \(180 per hour (or \)3.00 per minute)</p>
</li>
</ul>
<p>If you were to have these developers review <em>human code</em> at their hourly rate it would cost:</p>
<ul>
<li><p>Junior/intermediate developers: about $1 per code review</p>
</li>
<li><p>Mid-level developers: about: $2 per code review</p>
</li>
<li><p>Senior/lead developers or architects: $3.60 per code review</p>
</li>
</ul>
<p>If these same developers were to review <em>AI-written code</em> at their same hourly rate, it would cost:</p>
<ul>
<li><p>Junior/intermediate developers: about $3.57 per code review</p>
</li>
<li><p>Mid-level developers: about: $7.01 per code review</p>
</li>
<li><p>Senior/lead developers or architects: $15.48 per code review</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/ab5c0f01-2a77-4a73-883c-35a048445b88.png" alt="" style="display:block;margin:0 auto" />

<p>It is worth mentioning these numbers do not account for the lost productivity of the code reviewer as well, much like I mentioned above. Another item that is worth considering is the time added to timelines and lead times for features that can increase your company's bottom line. You will also need to keep an eye on the code bloat and potential regressions, as these can obviously affect these numbers too.</p>
<h2>When you think about it...</h2>
<p>Keep in mind, the numbers that I have provided are very much an approximation and estimate of your team's productivity. There are a fair amount of other caveats like language, code size, complexity, current technical debt, etc. But I think you get my point when you start to think of productivity and output in dollars and cents. As I also mentioned above, I myself have seen the benefits in my own work and undoubtedly you have as well. But with the security risks, bloat, and code duplication AI usage can introduce, <em>AND</em> you combine that with the increased code review time and associated costs with the potential delays and regressions; is it worth it?</p>
<p>As leaders, we have a direct responsibility to make decisions, and to put our teams into the best possible places/opportunities to succeed. This includes selecting tools and services to use. However when we are being pushed by our bosses and their bosses to use AI to optimize our work, I believe we owe it to our reports and the companies that we represent to at least take a second and really think about the outcomes of our decisions. We are very likely to not see the long-term effects for quite some time, but months and even years from now, are our AI-driven decisions going to really make our work better? Probably, but I am highly skeptical it will be this "slam dunk" we are being told it will be.</p>
<h2>To put a bow on it</h2>
<p>The AI coding gold rush is real — but so are the risks of mistaking generation for delivery. As organizations scale, context and awareness often get compressed into simplistic metrics. Lines of code and raw output from AI tools can feel like progress, but they are a poor proxy for actual customer value, reliability, and long-term maintainability.</p>
<p>To stay vigilant, treat AI as an amplifier, not a replacement, for disciplined software delivery. Anchor decisions in outcome-oriented metrics (customer impact, lead time, MTTR, change-failure rate), maintain strong feedback loops, and preserve human oversight across design, review, and deployment. Invest in observability, automated testing, security scanning, and provenance tracking so generated code is verifiable and safe to ship. Foster a culture that rewards quality, learning, and shared context—document assumptions, keep prompts and models auditable, and run blameless postmortems when things go wrong.</p>
<p>Practical steps:</p>
<ul>
<li><p>Prioritize outcome metrics over LOC; use DORA metrics thoughtfully and complement them with product and user metrics.</p>
</li>
<li><p>Require tests, code review, and CI/CD for all AI-generated code before it reaches production.</p>
</li>
<li><p>Capture context: rich prompts, architectural notes, and intent annotations so AI output is traceable and maintainable.</p>
</li>
<li><p>Automate safety checks (security, license, performance) and monitor runtime behavior post-deploy.</p>
</li>
<li><p>Train teams on effective prompting, model limits, and how to validate AI outputs.</p>
</li>
</ul>
<p>In short: harness AI to accelerate engineering, but measure and manage what actually matters—delivery, quality, and customer value. Vigilance, not hype, will determine who benefits from this gold rush.</p>
]]></content:encoded></item><item><title><![CDATA[Keeping your code hygiene fresh and clean.]]></title><description><![CDATA[Over the past week I have had a couple conversations with a new co-worker of mine, Kayla, about the implications of code standards, practices, conventions, or choose another complicated noun to insert]]></description><link>https://blog.dniccumdesign.com/keeping-your-code-hygiene-fresh-and-clean</link><guid isPermaLink="true">https://blog.dniccumdesign.com/keeping-your-code-hygiene-fresh-and-clean</guid><category><![CDATA[Editorial]]></category><category><![CDATA[clean code]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Thu, 14 May 2026 13:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/d288e9e7-2728-48bf-96fc-b562c035dc43.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Over the past week I have had a couple conversations with a new co-worker of mine, Kayla, about the implications of code standards, practices, conventions, or choose another complicated noun to insert here. When joining a new team you always want to be respectful to previous habits and conventions when styling and organizing your code. Naturally I didn't want to be "that guy" who just did things wrong. While each informative banter concluded differently with equally different subject mater, in the end of each conversation we <em>essentially</em> arrived at the same conclusion: there is no <strong>right or good</strong> way to build a project; it all depends on the eye of the beholder.</p>
<p>Now what does this mean? Well let me give you an example as it pertains me to and my habits; good and bad. Through out my professional career one thing that I have <strong>always</strong> taken pride in is the neatness and quality of my code. I have even received numerous compliments from potential employers on the neatness and organization. For myself, there is nothing like seeing the systematic nesting flow of HTML and CSS within my files.</p>
<p>Notice how I said neatness and organization, and not efficiency. I can even say that upon peer code reviews that I don't always write CRUD code. Sometimes I don't think things all the way through because I get lazy or get in a hurry. In this scenario, think of someone who was unfamiliar with the project and was needed to make some changes. According to <a href="http://www.cs.umd.edu/~mvz/pub/eworkshop02.pdf">a study done by the University of Maryland</a>, "about 40-50% of the effort on current software projects is spent on avoidable rework." That could be four to five thousand dollars saved on a ten thousand dollar bug fix. At that point, who cares if my code is a work of art; art can be expensive if it is careless.</p>
<h2>Your living space</h2>
<p>For most of us programmers and developers, we love our jobs. Just about every day of our lives we have our faces in our computer screens, sucking down some Code Red (or other stimulating beverage of choice) and write line after line. Lets face it, again for most of us we eat, sleep, and just <em>live</em> development.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/4451e00d-7f31-48aa-a002-2770d5bb882d.png" alt="" style="display:block;margin:0 auto" />

<p>For a moment lets think of our code as our bedrooms. Each item has it's place; our bed has a place of prominence, and our clothes are located in or around or dresser/closet, and so on and so forth. However if one thing is out of place, it is next to impossible to find. If we can't find it we tear the place apart; more often than not leaving the room in a worse state than we found it. An intricate function or library can be the exact same thing. If our indentations are off we cannot find where a function begins or ends, function chaining can be next to impossible to sort, and we could even possibly comment out a variable that the entire code set needs to run. And just like our room, if we cannot find what we are looking for, a weird concoction of line comments and copy/pastes ensues.</p>
<p>Now lets take this a step further. Remember that feeling as a child when your mother would come into your room and attempt to clean therefore moving all of your things that only knew where they were located? The same can be said if one or more developers cracks the lid on your code. I'm sure that we have all been in the same situation: where we quietly curse the previous developer and question their methodology and reasoning for doing <strong>everything</strong> they did.</p>
<p>This is why habits followed by documented reinforcement are important. Take <a href="http://code.tutsplus.com/tutorials/top-15-best-practices-for-writing-super-readable-code--net-8118">this post by NetTuts</a> for instance. While all of the suggestions cited here are great for a foundation, if one developer follows 8 out of the 15 best practices, and another developer follows a 7 different practices, the code just won't look the same.</p>
<h2>Invest for those of us who don't</h2>
<p>Being a developer in multiple disciplines and languages, I have somewhat of a rare ability to be able to take a step back in scour the landscape of development as a whole. One thing that I can safely conclude is that we as developers while creatures of habit, will go out of our way to avoid doing any other additional work; even it requires several hours worth of work. My wife would call that <strong>being lazy</strong>. Larry Wall, author of the PERL programming language said the three great virtues of a programmer are laziness, impatience and hubris. I think that this probably comes to no surprise to no one. <a href="http://blog.pluralsight.com/7-reasons-clean-code-matters">Cory House from Pluralsight</a> says that laziness is usually derived from not wanting to put forth the effort at the beginning of project with the intent to clean it up later. But what we fail to realize that this lapse in quality will only have a ripple effect down the road. Developers almost expect their predecessors to compose thorough and soundly correct code so further down the line we can make a couple bug fixes and move on.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/0d2f98d1-ec31-4333-b912-704f0f4d0a68.png" alt="" style="display:block;margin:0 auto" />

<p>I have found that the absolute kiss-of-death comment that any developer can give about another developer is when someone, "Pulls a [insert a name]." Cory House also labels this as <em>"becoming a verb."</em> There is nothing worse than leaving a legacy laced with negative undertones and teeth-grinding hatred. This only leads back-stabbing camaraderie and people just despising the air you breath. No one wants that.</p>
<h2>So what I would do...</h2>
<p>While I am not in the business of getting up on my soapbox and trying to convince you why my opinions are better than someone else's, I would simply give you a few things I would do; and also because the subject matter of this post demands it.</p>
<h4>Have a plan</h4>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/f7d5e43b-4c49-4e59-bf4a-8170f3b841af.png" alt="" style="display:block;margin:0 auto" />

<p>While this may sound like I ripped this off of a motivational speaker of financial advisor, you always need to have a plan when you are scaffolding out a website or application. Functions go here, routes go there; its more of a personal statement of organization than anything. Now this is important, <strong>your plan can change</strong>. Things like scale and feature requests can quickly derail the perfect plan. But never fear! If you have invested the time and organized your code in the appropriate directories and libraries, these changes will be easier to bear.</p>
<h4>Punctuation and space</h4>
<p>The item that I am most particular about (and I can get somewhat heated about) is indentations and punctuation. Functions, arrays, and even SASS nodes all deserve the time and care to have their children and parent elements to receive the appropriate indentations; the further your traverse within a function, the more it should be indented. <strong>It's that simple.</strong> This allows your IDE to copy and paste code snippets from one file to another, it allows you to quickly spot parameters to be used within further functions and callbacks, and just simply looks better.</p>
<p>Punctuation plays a separate yet equally painful part of a developers life. Even when using CSS, which can be debated as the most forgiving language of all, you need to place semicolons at the end of every line or it won't work. While languages like PHP don't really care about how the code is structured as long as it is punctuated correctly, other languages such as Ruby and Python utilizing indentations as it's own form of punctation; failure to do so results in bugs and errors.</p>
<h4>Write it down</h4>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/e4adaf69-5d27-4e1d-a3ac-52edc0ad26a5.png" alt="" style="display:block;margin:0 auto" />

<p>I'm sure some of my previous co-workers would laugh if they read this part due to the overwhelming irony but realistically it is just as important. Documentation is one of the easiest yet most important of working on a application with a large team. A centralized location for dependencies as well as basic a basic description of application infrastructure helps speed up with the learning curve/ramp-up time when imploring a the services of another developer.</p>
]]></content:encoded></item><item><title><![CDATA[Troubleshooting NodeJS installation/run issues]]></title><description><![CDATA[When a requested update or bugfix comes across my desk, there is nothing more daunting when a fresh clone/fork of repository completes and then the installation process ensues. If you are like me, you]]></description><link>https://blog.dniccumdesign.com/troubleshooting-nodejs-installation-run-issues</link><guid isPermaLink="true">https://blog.dniccumdesign.com/troubleshooting-nodejs-installation-run-issues</guid><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Wed, 13 May 2026 18:56:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/20fd6490-5f77-4eb0-8606-e7e5d0f17a46.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When a requested update or bugfix comes across my desk, there is nothing more daunting when a fresh clone/fork of repository completes and then the installation process ensues. If you are like me, you almost don't even want to look at your screen in fear of that system alert or red text to appear within your console, meaning only one thing: there are installation errors.</p>
<p>But let's assume for a second that your installation goes without a hitch. NPM gives you a grand success message and everything was installed without a hiccup. You then proceed to type <code>gulp watch</code> or whatever your task manager of choice and then the whole process crashes followed by you slamming your fist on your desk in frustration.</p>
<p>The two examples that were listed above are more common than we would like to admit. It can be just as simple as a syntax error or as bad as a deprecated package that simply doesn't exist anymore. As I'm sure that most developers are aware of, one of the largest and problematic issues of working with legacy projects is how to manage project dependencies.</p>
<p><em>While this fiasco persists within all facets of development, for the sake of this post, we will focus on the front-end side (whew).</em></p>
<h2>Diagnosing the problem</h2>
<p>While I don't consider myself a genius when it comes sifting threw the <em>needle in a haystack</em> that is an error log, for most developers a <code>npm install</code> error log can deciphered with ease. I can say that most NodeJS packages now-a-days do a pretty good job of explaining what the problem is in layman terms. It could be just as simple as saying that a package doesn't exist or something is <em>undefined,</em> and this can remedied by performing an additional installation command.</p>
<p>Where diagnosing becomes difficult is when multiple dependencies of a NodeJS module and in turn their dependencies start throwing errors. As I'm sure most of us can agree, this is what we as developers begin to lose sleep over.</p>
<h2>A couple different solutions</h2>
<p>In my experience, the two scenarios that I briefly outlined above can be solved about 80-90% of the time with a couple different or a combination of tactics.</p>
<h3>NodeJS version</h3>
<p>If the project that you are trying to work on is more than 2-3 years old, it is very possible the version of NodeJS that is installed on your machine is too recent for the dependencies that are listed within the <code>package.json</code> that accompanies your project.</p>
<h3>NodeJS modules</h3>
<p>A common mistake that we all make when we are building our <code>package.json</code> file and utilizing the <code>npm install</code> command is that we just tell NPM to retrieve the most stable and recent version of a package and added as a dependency. In doing so, our dependency list could look like this:</p>
<pre><code class="language-json">"dependencies": {
    "bower": "^1.7.2",
    "connect-redis": "1.4.5",
    "ejs": "~0.8.4",
    "grunt": "0.4.2"
}
</code></pre>
<p>The issue with this JSON object is the <strong>~</strong> and <strong>^</strong> punctuation (<a href="https://docs.npmjs.com/files/package.json">source</a>) before the version numbers. What these mean, respectively, is the version is approximately this number or it needs to be compatible with the listed version. While for one package it is not detrimental, spreading this level of variability throughout the entire project can be disastrous.</p>
<h2>So what's next?</h2>
<p>Yeah so what's next? Well here are a couple routes you can take to trouble shoot these issues that can creep up during an installation/run.</p>
<h2>Using n to change your version of NodeJS</h2>
<p>NodeJS gives a tool called <a href="https://github.com/creationix/nvm">NVM</a> (Node Version Manager) to control our versions of NodeJS that are active on our machines. I have found that this module can be clunky at best and the command line syntax is just <em>weird</em>.</p>
<p>I recommend using <a href="https://github.com/tj/n">n</a>. n is a simpler version of NVM and allows you to easily transition between versions of NodeJS on your machine.</p>
<h3>How to install/use n</h3>
<p><strong>1.</strong> Before we install anything, we need to make sure that your user has read/write access to the <code>/usr/local/bin/</code> directory on your machine so we can modify the "node" directory that will live there. To do this, enter the following command followed by your user password:</p>
<pre><code class="language-shell">\( sudo chown -R \)(whoami) /usr/local
</code></pre>
<p><strong>2.</strong> After that is complete, now we need to install n globally on your machine like so:</p>
<pre><code class="language-shell">$ npm install -g n
</code></pre>
<p><strong>Note:</strong> If you computer asks you to perform this action as an Administrator, simply prefix this command with <code>sudo</code>.</p>
<p><strong>3.</strong> Now that n is installed, we can see all of the actions that are available to us by simply entering the following command:</p>
<pre><code class="language-shell">$ n
</code></pre>
<p>which should look like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/994dcda7-f9e6-47e6-9f0e-4c3798fc85c8.png" alt="" style="display:block;margin:0 auto" />

<p><strong>Note:</strong> Once versions of NodeJS are installed, to be able to return to this screen use the <code>n --help</code> command.</p>
<p><strong>4.</strong> Before we start getting crazy with installing all sorts of NodeJS on your machine, lets give ourselves a good baseline to work from by install the current version of NodeJS on our machine. First enter:</p>
<pre><code class="language-shell">$ node -v
</code></pre>
<p>The result that is outputted should look like this: <code>v5.3.0</code>. Note the version number (not including the v) and then enter this command:</p>
<pre><code class="language-shell">$ n [your current version]
</code></pre>
<p>This will install your current version of NodeJS within n. Next enter this command to install the most recent stable version of NodeJS:</p>
<pre><code class="language-shell">$ n latest
</code></pre>
<p>Once finished, enter the <code>n</code> command again and you should see something like this (note your version numbers could be different):</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/a87590bb-c338-44a6-a82f-e45379bbac3f.png" alt="" style="display:block;margin:0 auto" />

<p>Now you can use your arrow keys to navigate the versions installed and then hit Enter to select your version, or just use Ctrl + C to exit. Go ahead and select the newest version that you have, and then hit Enter. Give your machine a second to process the change and then it will exit the screen. Afterwards test your version with:</p>
<pre><code class="language-shell">$ node -v
</code></pre>
<p><strong>Note: Make sure you have killed all of your NodeJS servers/process!</strong></p>
<p>Assuming you did everything correctly you should see your version change. But that's not all! You can go back as easily as you can go forward. If you enter:</p>
<pre><code class="language-shell">$ node ls
</code></pre>
<p>This will output all of the versions of NodeJS that are available to install. You can simply copy the version number that you want and then repeat the process to be able to install legacy versions of NodeJS. It's that easy! Once you have found a version that you think will work (it may take some trial and error), purge the <code>node_modules</code> directory and the retrying the install and run commands.</p>
<h2>Fix your module versions</h2>
<p>As I touched on earlier, another way we can troubleshoot these errors is not allow NPM to install versions of our dependencies that are not explicitly what we ask for. The punctuation marks (^, ~) that are prepended to our version numbers can cause modules to be full feature versions ahead of what we want; causing major compatibility issues.</p>
<p>To fix this, simply remove any prepended ^ or ~ marks within your <code>package.json</code> file, purge the <code>node_modules</code> directory and the retrying the install and run commands.</p>
<h2>Disclaimer</h2>
<p>Again, restating what I said earlier, I have found these two methods of debugging to solve about 80-90% of my compatibility issues. However keep in mind that other things can go wrong, things that are not covered here. But hopefully this will get you pointed in the right direction.</p>
]]></content:encoded></item><item><title><![CDATA[Setting yourself above: speaking at a conference]]></title><description><![CDATA[Whenever I tell a colleague that I am speaking at a conference, the common response is usually along the lines of, "you get up in front of people and talk? I could never do that." The fact that I am h]]></description><link>https://blog.dniccumdesign.com/setting-yourself-above-speaking-at-a-conference</link><guid isPermaLink="true">https://blog.dniccumdesign.com/setting-yourself-above-speaking-at-a-conference</guid><category><![CDATA[Editorial]]></category><category><![CDATA[speaking ]]></category><category><![CDATA[conference]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Wed, 13 May 2026 18:38:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/db033c1f-3c95-4d0d-aa69-d609509b1148.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whenever I tell a colleague that I am speaking at a conference, the common response is usually along the lines of, "you get up in front of people and talk? I could never do that." The fact that I am here in the flesh writing to you now proves that this daunting task is easier than many think. What's more is the fact that it's not just about doing something intimidating or challenging, it's all about sharing that little bit of knowledge that you have with someone to make them better.</p>
<p>It has been said that when you attend a conference (technical or creative) the speakers at that conference represent the top 5% of minds in your respective fields. Essentially the cream of the crop. While the attendees can very easily benefit from this type of talent and knowledge, speaking at a conference can benefit you just as much. Surrounding yourself with this type of knowledge is in infectious; which can only improve you as a person, personally and professionally, and as a subject matter expert.</p>
<p>So you may be saying to yourself, "Ok so I can get smarter and/or more knowledgable. Big deal. Is that all?" Well no of course not. Keep reading.</p>
<h2>Investing in your skill</h2>
<p>I can speak from experience that there is nothing more embarrassing than getting up in front of a group of people and you start receiving questions that you don't know the answers to; especially when you are live-coding. It's awkward for you and the people attending your talk. So how do you avoid this?</p>
<p>It's simple: do your homework.</p>
<p>While you may be pretty comfortable with your subject matter, there is always an opportunity for you to add just a few extra facts to help draw in your audience even more. More often than not, these facts, pointers, or how-to's are items that you probably don't already know. A common requirement for conferences is for you to stage your code on GitHub or any other equivalent with any associated documentation. A bi-product of this requirement is clean code and detailed how-to's; all extremely effective tools who may not be experts. It's these little nuggets that help validate you even more as a speaker.</p>
<h3>What it did for me</h3>
<p>For example, in preparation for a session that I was going to give on the <a href="http://ionicframework.com/">Ionic Mobile Framework</a>, I had to familiarize myself with multiple deployment platforms. I am an Apple/Mac guy: I have multiple iPads, several iPhones, and a couple Apple computers at home. However to think that everyone else works on the exact same devices I do would be naive and frankly, stupid. So I invested in a cheap PC as well as an Android phone so I could broaden my scope of documentation; allowing me to understand the ins and outs of Android Studio and the Java SDK (software developer kit). Boy am I glad I did. I found more than a couple "gotchas" that could have easily derailed my talk.</p>
<p>All of these items require time. This is time that you spend becoming even more familiar with the documentation and processes and thus committing even more information to memory. In the end you solidify yourself within the minds of your attendees as a subject matter expert.</p>
<h2>Building yourself up</h2>
<p>If you want to speak publicly, you don't necessarily have to immediately jump into the conference environment. Speaking in front of complete strangers with zero context on who you are or where you come from can be frightening. I get it. Fortunately I can vouch for the fact that there are several other opportunities for you to speak before taking the conference plunge.</p>
<h3>Client meetings</h3>
<p>One opportunity that commonly gets overlooked is client meetings. While you may not be speaking in a traditional workshop session type setting, you are in fact speaking to people who are not familiar with your content; requiring your to explain in detail how you came to a certain conclusion. What's more is you may receive questions on your conclusions forcing you to think quickly on your feet thus placing even more emphasis on your preparation.</p>
<h3>Focus groups</h3>
<p>Another type of meeting that is common in the agency setting is a focus group. This can be a meeting that was called between like-minded people to decide on a process for the larger masses, or this could be an open forum during a lunch and learn. Each setting has a different type of audience make up all with unique skillets and knowledge, but each requires you to be prepared and explain your content in detail to ensure no one is left behind.</p>
<h3>Screencasts</h3>
<p>While not necessarily formal, putting yourself on a YouTube video screencast is another great starting place for you to begin speaking. You don't have the pressure of a live audience, allowing for additional focus on your diction and flow of the presentation. As an added benefit, if your videos get popular you begin to make a little ad revenue as well!</p>
<h2>Promotion - self and company</h2>
<p>Being in the industry that we are in, it could be safe to say that we take the concept of marketing for granted. We consistently market a product or idea to others while not necessarily putting a lot of effort in marketing ourselves or our employer's brand. It's this notion of brand recognition, of either ourselves or our company, that attracts like-minded talent and brand recognition.</p>
<p>People and thus word of mouth are the best way for a message to spread. I'm sure that all of you social media people can agree. This is how viral threads get started, word of mouth, or a social presence; which is in fact an extension of our voice. The more advocates and content that is in the public eye with your brand being connected to only fuels the message.</p>
<p>In my opinion, a common misconception of brand recognition comes associated with award winning work. Design periodicals and other marketing resources continuously push the draw of awards to their readers. Don't get me wrong, awards are great: they create great magazine material and are awe-inspiring when you enter the front doors of the office, seeing all of those trophies on the walls. However these awards can be all but useless if the message of your brand is lost.</p>
<p>Stereotypically when you speak at a conference, you introduce yourself and the company that you work for. At this moment you are instantly bringing your employer's brand to the fore-front of your attendee's minds. Just like a creative TV advertisement, that recognition will be associated with the content that you are about to present; not only making you appear better but your employer as well.</p>
<h2>So you want to speak? Great you have help.</h2>
<p>While you prepare for your session, one thing to keep in mind while you prepare is to remember that you do not have to go through this process alone.</p>
<p>Your company leadership has a number of professionals that have attended conferences of various sizes that have an enormous wealth of information. While the subject matter may be different, that doesn't matter. Having a fresh perspective on your content can only help you during the preparation and feedback stages.</p>
<p>Refer to the section above about the various settings that you can utilize to help you get your feet wet in speaking publicly. I understand that this is not an easy task for everyone. I can place myself in that category at one point in time. However just like everything else, practice makes perfect. Keep reviewing your notes and always be open to feedback; good and bad.</p>
<p>At the end of the day, the people who attend your talks want you to succeed. No one attends your sessions looking for you to fail. Determination and hard work yields quality for your talk and for you as a presenter.</p>
]]></content:encoded></item><item><title><![CDATA[Passing uploaded files between Laravel Livewire components]]></title><description><![CDATA[I recently discovered a need to be able pass temporary (without being saved to your filesystem) uploaded files using Laravel Livewire for an API that I am building for my 9-5 job. Essentially (thinkin]]></description><link>https://blog.dniccumdesign.com/passing-uploaded-files-between-laravel-livewire-components</link><guid isPermaLink="true">https://blog.dniccumdesign.com/passing-uploaded-files-between-laravel-livewire-components</guid><category><![CDATA[Laravel]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[Livewire]]></category><category><![CDATA[development]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Fri, 06 Nov 2020 16:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/34414f18-8332-4cde-b11b-fda45ae1d8e6.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I recently discovered a need to be able pass temporary (without being saved to your filesystem) uploaded files using Laravel Livewire for an API that I am building for my 9-5 job. Essentially (thinking with my VueJS cap) I wanted to build a uniform file-upload input that I could use multiple times within my application.</p>
<p>Again, using my VueJS-centered brain, I just assumed that I would be able to simply emit up the <code>TemporaryUploadedFile</code> class that Livewire generates with a file-upload. Naturally I was incorrect. <strong>My problem:</strong> when you attempt to pass this class to a parent/child component all you get is:</p>
<p>Obviously you cannot do anything with this. So after some discovery, I was able to come up with a scalable solution.</p>
<h2>The result</h2>
<p>For the sake of being thorough, I am going to show you all of my code, so you can replicate the entire component for yourself. It is worth noting that I also used Alpine.JS and Tailwind for this component.</p>
<p>In the next few steps, this is what we are going to build:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/aa8fbcfe-1b2a-4b96-94e4-e8b163f6182d.png" alt="Step 1" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/a0134fc9-a2c0-439f-a404-5eedd330335f.png" alt="Step 2" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/cc92266d-d821-4487-a1f1-2225a09a2657.png" alt="Step 3" style="display:block;margin:0 auto" />

<p>Yours <em>MIGHT</em> look a little different as I have modified my <code>tailwind.config.js</code> file a bit.</p>
<h2>How I did it</h2>
<p>Assuming you have at least skimmed the documentation for <a href="https://laravel-livewire.com/docs/2.x/file-uploads">Laravel Livewire on file uploads</a>, you can see that once a file is uploaded, Livewire stores the file in a temporary directory within your filesystem; whether it is remote or locally depends on your infrastructure. The response of this action is an object with a bunch of other meta data named <code>Livewire\TemporaryUploadedFile</code>. From there you can extract any information that you need and save/move the file around where you need it. Again, you can <a href="https://laravel-livewire.com/docs/2.x/file-uploads#storing-files">refer to the documentation</a> for further details.</p>
<p>Like I said above, if you simply try to use the <code>emit()</code> action to pass the result to other components, all that is passed is the disk path. I even tried JSON encoding the object, but that didn't work either. After dissecting the <code>Livewire\TemporaryUploadedFile</code> class, I discovered there is an exposed method <code>getRealPath()</code> that returns the temporary location of the file. Furthermore, I found that the path of the file is the parameter required to construct a new instance of the <code>TemporaryUploadedFile</code> class. Passing strings with Laravel Livewire is easy, so that was my ticket: emitting the full <em>real</em> path of the temporary file, and then simply re-constructing the <code>TemporaryUploadedFile</code> class in the parent/listening component.</p>
<p>Once finished, then you can either move/save the emitted file like so:</p>
<pre><code class="language-php">class FileUpload extends Component
{
    use WithFileUploads;

    public $file;
    
    ...
    
    public function fileComplete()
    {
        $this-file-&gt;storePubliclyAs(
            'documents',
            'sample',
            config('filesystems.default'),
        );
    }
}
</code></pre>
<h2>Full code</h2>
<h3>Child Component Template</h3>
<pre><code class="language-html">&lt;div
    x-data="{ isUploading: false, progress: 0, name: null }"
    x-on:livewire-upload-start="isUploading = true"
    x-on:livewire-upload-finish="isUploading = false; $wire.fileComplete()"
    x-on:livewire-upload-error="isUploading = false"
    x-on:livewire-upload-progress="progress = $event.detail.progress"
&gt;

    &lt;div class="overflow-hidden relative w-64 mt-4 mb-4"&gt;
        &lt;label class="font-sans py-2 px-4 border border-transparent text-sm font-semibold tracking-wider rounded-md transition duration-150 ease-in-out uppercase border-gray-300 text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue inline-flex cursor-pointer" x-show="!name"&gt;
            &lt;svg fill="#FFF" height="18" viewBox="0 0 24 24" width="18" xmlns="http://www.w3.org/2000/svg"&gt;
                &lt;path d="M0 0h24v24H0z" fill="none"/&gt;
                &lt;path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/&gt;
            &lt;/svg&gt;
            &lt;span class="ml-2"&gt;Select File&lt;/span&gt;
            &lt;input class="hidden" type="file" wire:model="file" x-on:change="name = $event.target.files[0].name"&gt;
        &lt;/label&gt;
        &lt;div class="text-gray-500" x-show="name"&gt;
            &lt;span x-show="isUploading"&gt;Uploading... Please wait.&lt;/span&gt;
            &lt;div class="flex items-center" x-show="!isUploading"&gt;
                &lt;div class="flex-1 truncate mr-2"&gt;
                    &lt;span x-text="name"&gt;&lt;/span&gt;
                &lt;/div&gt;
                &lt;button type="button" class="inline-flex items-center justify-center h-7 w-7 rounded-full bg-red-600 hover:bg-red-800 text-white shadow-lg hover:shadow-xl transition duration-150 ease-in-out focus:bg-red-700 outline-none focus:outline-none" x-on:click="progress = 0; name = null; \(wire.file = null; \)wire.fileReset()"&gt;
                    &lt;svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"&gt;
                    &lt;path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" /&gt;
                &lt;/svg&gt;
                &lt;/button&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- Progress Bar --&gt;
    &lt;div class="relative pt-1" x-show="isUploading"&gt;
        &lt;div class="overflow-hidden h-2 mb-4 text-xs flex rounded bg-green-200"&gt;
            &lt;div :style="`width: ${progress}%`" class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-green-500"&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<h3>Child component</h3>
<pre><code class="language-php">&lt;?php

namespace App\Http\Livewire;

use Livewire\Component;
use Livewire\WithFileUploads;

class FileUpload extends Component
{
    use WithFileUploads;

    public $file;

    public function render()
    {
        return view('livewire.file-upload');
    }

    public function updatedFile()
    {
        $this-&gt;validate([
            'file' =&gt; 'file|max:8192', // 8MB Max
        ]);

        \(this-&gt;emitUp('fileUploaded', \)this-&gt;file);
    }

    public function fileComplete()
    {
        \(this-&gt;emitUp('fileUpload', \)this-&gt;file-&gt;getRealPath());
    }

    public function fileReset()
    {
        $this-&gt;emitUp('fileReset');
    }
}
</code></pre>
<h3>Parent Component</h3>
<pre><code class="language-php">&lt;?php

namespace App\Http\Livewire;

use Livewire\Component;
use Livewire\TemporaryUploadedFile;

class ParentComponent extends Component
{
    protected $listeners = [
        'fileUpload',
        'fileReset',
    ];
    
    public $file;
    
    public function fileUpload($payload)
    {
        \(this-&gt;file = new TemporaryUploadedFile(\)payload, config('filesystems.default'));
        
        /* When you are ready to store the file */
        /*
        $this-&gt;file-&gt;storePubliclyAs(
            'documents',
            'sample',
            config('filesystems.default'),
        );
        */
    }

    public function fileReset()
    {
        $this-&gt;file = null;
    }
}
</code></pre>
<p>Hopefully you can find this useful. I was banging my head against the wall for a couple hours with this, and naturally the solution was easier than anticipated.</p>
<img src="https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExc3RvazZwMXV3Z2N2ajlsODBlMHV4YjVjMW5xZGF4M2RhdHd0NmllYiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/xT5LMzIK1AdZJ4cYW4/giphy.gif" alt="" style="display:block;margin:0 auto" />]]></content:encoded></item><item><title><![CDATA[Adding documentation to your Laravel Nova installations]]></title><description><![CDATA[Documentation (especially good documentation) for an application can make a good application and experience for a client, a great application. Once we as developers complete an application that we hav]]></description><link>https://blog.dniccumdesign.com/adding-documentation-to-your-laravel-nova-installations</link><guid isPermaLink="true">https://blog.dniccumdesign.com/adding-documentation-to-your-laravel-nova-installations</guid><category><![CDATA[Laravel]]></category><category><![CDATA[Nova]]></category><category><![CDATA[documentation]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Wed, 13 Feb 2019 16:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/6185fce7-4921-454b-9502-5c215f79e744.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Documentation (especially good documentation) for an application can make a good application and experience for a client, a <em>great</em> application. Once we as developers complete an application that we have worked and potentially even lost sleep over, will live on well after we stop working on it. Despite our best efforts, clients and customers tend to forget things that we show them on how to manage their application. That's where documentation comes in.</p>
<img src="https://images.unsplash.com/photo-1509239129736-8c395375220d?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="" style="display:block;margin:0 auto" />

<p>I'll come right out and say it: I hate writting documentation; regardless for what it is for. My normal avenue's of implementation documention are via Word document, or even a repository wiki. Recently I even used this <a href="https://larecipe.binarytorch.com.my/docs/1.3/overview">awesome documentation package called LaRecipe</a>, that I thorougly enjoyed using. However these solutions didn't solve my pain point of the documentation isn't all in the same place. It required a client to open up another application or web browser and comb through a few different pages. It was these issues that was the inspiration behind a new Nova tool that I built to solve.</p>
<h2>Building yet another tool</h2>
<p>So like I said, to solve my own pain, I built a <a href="https://github.com/dniccum/nova-documentation">new Laravel Nova tool called Nova Documentation</a> (creative name right?).</p>
<p>What this tool essentially does is convert Markdown files and then passes them to the Vue component within the tool. Ultimately it is that simple, however there are a few other things that I added that I think will be useful:</p>
<ul>
<li><p>Syntax highlighting to code blocks (thanks to <a href="https://highlightjs.org/">highlight.js</a>)</p>
</li>
<li><p>Dynamic navigation/table of contents</p>
</li>
<li><p>Document nesting with url rewriting</p>
</li>
<li><p>Flexible configuration settings</p>
</li>
</ul>
<h2>Installation</h2>
<p>To start, lets install the Nova tool with:</p>
<pre><code class="language-shell">composer require dniccum/nova-documentation
</code></pre>
<p>Next, we need to publish the tool's configuration file and a couple markdown files with examples to get you started:</p>
<pre><code class="language-shell">php artisan vendor:publish --provider="Dniccum\NovaDocumentation\ToolServiceProvider"
</code></pre>
<p>By default, the sample markdown files that the tool uses to render it's content will be added to <code>resources/documentation</code> path. If you would like to move this directory, be sure to update this setting within the <code>config/novadocumentation.php</code> configuration file:</p>
<pre><code class="language-php">/*
|--------------------------------------------------------------------------
| Home Page
|--------------------------------------------------------------------------
|
| The markdown document that will be used as the home page and/or entry
| point. This will be located within the documentation directory that resides
| within your application's resources directory.
|
*/

'home' =&gt; 'documentation/home.md',
</code></pre>
<p>And finally, just like every other Nova tool, we need to register the tool within the NovaServiceProvider:</p>
<pre><code class="language-php">use Dniccum\NovaDocumentation\NovaDocumentation;

...

/**
 * Get the tools that should be listed in the Nova sidebar.
 *
 * @return array
 */
public function tools()
{
    return [
        // other tools
        new NovaDocumentation,
    ];
}
</code></pre>
<p>Assuming that you have done everything correctly, you should see a "Documentation" link in your Nova sidebar with this as a homepage:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/10e8732c-25dc-48ae-86f7-48ab14ab4d75.png" alt="Documentation tool home page" style="display:block;margin:0 auto" />

<h2>Using the tool</h2>
<p>Assuming that you are using the default installation configuration, the directory where all of the markdown file will be stored in the <code>resources/documentation</code> directory. Again, if you use the default settings, the <a href="http://home.md"><code>home.md</code></a> file that will be found there will represent the home page:</p>
<pre><code class="language-markdown"># Welcome to your documentation

Within this area, you can:

* Define features
* Add how-to's
* Link to tutorial videos/images

To see any other Markdown syntax and examples, please see [the sample](sample.md).
</code></pre>
<h3>Generating your content</h3>
<p>A few things you should note:</p>
<ul>
<li><p>Any and all markdown is allowed in these markdown files.</p>
</li>
<li><p>You should be able to add any other HTML that you want to render within the page; excluding any Javascript as I am using Vue.js template compiler to build the page and any Javascript-based content probably won't render correctly.</p>
</li>
<li><p>I did add the necessary CSS to clean up some of the appearance of standard HTML tags like ordered/un-ordered lists, headers, block quotes, etc from the base stylesheet that Taylor Otwell constructed for the Nova dashboard. If you happen to find something that isn't quite styled correctly, drop me a line on the <a href="https://github.com/dniccum/nova-documentation/issues">issues page on Github</a>.</p>
</li>
<li><p>Feel free to organize your markdown files as you wish; whether everything is in the base directory or if you would like to add files within directories. The tool will detect them and build their url's accordingly.</p>
</li>
</ul>
<h3>Setting your titles</h3>
<p>It is important to note that the H1 tags within each of these files will be dynamically pulled to build the sidebar navigation. With that said, make sure your titles are descriptive yet short in length to prevent the sidebar from becoming cluttered.</p>
<h2>Other features?</h2>
<p>As you continue to work with this tool, let me know if there are any other features that you would like to add. Thank you for your interest!</p>
]]></content:encoded></item><item><title><![CDATA[Customizing your Laravel Broadcasting payloads]]></title><description><![CDATA[One piece of the Laravel documentation that is somewhat glanced over in my opinion is the ability to customize the payload that is sent out to your Laravel Echo listeners upon new events or broadcast ]]></description><link>https://blog.dniccumdesign.com/customizing-your-laravel-broadcasting-payloads</link><guid isPermaLink="true">https://blog.dniccumdesign.com/customizing-your-laravel-broadcasting-payloads</guid><category><![CDATA[Laravel]]></category><category><![CDATA[pusher]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Wed, 30 Jan 2019 16:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/7e15dc56-1047-4697-b978-1b233f296e5e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>One piece of the Laravel documentation that is somewhat <em>glanced</em> over in my opinion is the ability to customize the payload that is sent out to your Laravel Echo listeners upon new events or <code>broadcast</code> methods. This can be extremely important when results from the models passed to these events are large and/or bloated; for example: when you are storing chunks of HTML in your database.</p>
<p>By default, the Broadcasting functionality within Laravel serializes any and all classes/models that you pass to the events. What does this mean? Well lets say for example that you have a model that has 15 columns for each result, however during your select method you only query 3 columns; like so:</p>
<pre><code class="language-php">$user = \App\Models\User::where('id', 6)
	-&gt;select(['id', 'name', 'email'])
	-&gt;first();

event(new \App\Events\UserLoggedOut($user));
</code></pre>
<p>If you pass this model to the event all 15 columns will be queried; regardless of what you select, or the number of <code>unset</code> methods you use. If you are using a service like that of <a href="https://pusher.com/">Pusher</a>, you could run into character limits that will ultimately lead to errors and failed messages.</p>
<p>In order to prevent our broadcasts from erroring, we need to customize the payload that is sent to Pusher or any other platform. We can do that by playing a <code>broadcastWith</code> method within our event class. Let's to back to the example above, where we only want to broadcast the id, name, and email address. Our broadcastWith method would look like this:</p>
<pre><code class="language-php">/**
 * Specifically broadcasts the necessary array keys
 *
 * @return array
 */
public function broadcastWith()
{
    return [
        'user' =&gt; [
            'id' =&gt; $this-&gt;user-&gt;id,
            'name' =&gt; $this-&gt;user-&gt;name,
            'email' =&gt; $this-&gt;user-&gt;email,
        ]
    ];
}
</code></pre>
<p>By implementing this method, your broadcasts will be significantly simplified and thus carry a light payload. But that's not all! Because this is a method, and not a variable, you can perform additional logic within this method to conditionally add content to the payload. Refer to another example below:</p>
<pre><code class="language-php">/**
 * Specifically broadcasts the necessary array keys
 *
 * @return array
 */
public function broadcastWith()
{
    $payload = [
        'configuration' =&gt; [
            'id' =&gt; $this-&gt;configuration-&gt;id,
            'name' =&gt; $this-&gt;configuration-&gt;name,
            'user' =&gt; [
                'first_name' =&gt; $this-&gt;configuration-&gt;user-&gt;first_name,
                'last_name' =&gt; $this-&gt;configuration-&gt;user-&gt;last_name,
            ],
        ]
    ];

    if (!empty($this-&gt;configuration-&gt;jurisdictions)) {
        \(jurisdiction = \)this-&gt;configuration-&gt;jurisdictions-&gt;first();

        $payload['jurisdiction'] = [
            'id' =&gt; $jurisdiction-&gt;id
        ];
    }

    if (!empty($this-&gt;configuration-&gt;comments)) {
        \(payload['comments'] = \)this-&gt;configuration-&gt;comments;
    }

    return $payload;
}
</code></pre>
<p>What I have done is that I have assigned the initial associative array to a variable and performed some basic if-statements to conditionally add content to the payload.</p>
<p>While this isn't necessarily rocket science, using this method of customizing your broadcasts can simplify your application and save you a bunch of time wrestling with the Pusher/websockets APIs.</p>
]]></content:encoded></item><item><title><![CDATA[The end is nigh for Bower?]]></title><description><![CDATA[Over the last four or five years, I have come to have a deep adoration for the front end package manager Bower. Going to the official jQuery or Angular repositories to download dependencies was a thin]]></description><link>https://blog.dniccumdesign.com/the-end-is-nigh-for-bower</link><guid isPermaLink="true">https://blog.dniccumdesign.com/the-end-is-nigh-for-bower</guid><category><![CDATA[Editorial]]></category><category><![CDATA[bower]]></category><category><![CDATA[yoeman]]></category><dc:creator><![CDATA[Doug Niccum]]></dc:creator><pubDate>Thu, 22 Sep 2016 15:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a04a785a0c154027750e770/65f030b8-8556-4c61-860f-da64ea16169b.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Over the last four or five years, I have come to have a deep adoration for the front end package manager <a href="https://bower.io/">Bower</a>. Going to the official jQuery or Angular repositories to download dependencies was a thing of the past. The even deeper integrations with scaffolding tools like Yeoman even made the attraction even more irresistible. The fact I could build a basic project with a couple shell commands just blew my mind the first few times.</p>
<p>Now that Angular 2 has <strong>finally</strong> been released and is no longer in the purgatory of beta or release candidate, I am starting to see a trend with the support of public projects and the technologies that supports them. This trend is that <strong>these new projects are not supported by Bower.</strong></p>
<p>While I would like to note that these trends are somewhat specific to brand new projects like that of Angular 2 and <a href="http://ionicframework.com/docs/v2/getting-started/installation/">Ionic 2</a>. Projects like Angular 1 and Ionic 1 that are currently being maintained, though not improved, are still supported with Bower compatible packages; I digress...</p>
<p>But why would I be thinking about this? Is there something that Bower did wrong to seal it's demise? I have a few ideas.</p>
<h2>It's a NodeJS package</h2>
<p>So what if it is a NodeJS package? We use helpers like Grunt and Gulp all of the time to process code and to make our lives easier as developers. Why would Bower be any different? Here's my theory: because it is a required dependency to install further dependencies with its own set of shell commands; <em>automation</em> in other words.</p>
<p>When working with CMS applications like <a href="http://www.adobe.com/marketing-cloud/enterprise-content-management.html">Adobe Experience Manager</a> or even platforms like <a href="https://laravel.com/">Laravel</a> (PHP-based), these tools ship with scaffolding tools or provide a tool for you to create your own. The majority of these assets require you to use Node Package Manager (npm) to install and run their associated dependencies. It has become so common that it is second-nature for us as developers to clone a repository and then run <code>$ npm install</code>. Configuring AEM to run this command isn't very hard either. The issues that I can identify lies in the fact that:</p>
<ul>
<li><p>Bower downloads is packages differently than NodeJS does</p>
</li>
<li><p>It has a different set of configurations and requires additional files to apply these configurations</p>
</li>
<li><p>It is discouraged to store your Bower-related files or <em>bower_components</em> in the same place as your node modules. Bad things start to happen when you do</p>
</li>
</ul>
<p>Each of these points could become troublesome if you are trying to develop in an existing ecosystem that was never designed to support Bower.</p>
<p>Additionally, in most instances you have to have Bower installed globally on your machine. If not, for instance it is a dependency of your NodeJS application, then you are limited to calling the Bower command like so:</p>
<pre><code class="language-shell">/usr/local/bin/bower install
</code></pre>
<p>Now you are liable to manage two different sets errors and feedback. And as I pointed out earlier, if this Bower project has been automated, debugging these errors can be troublesome.</p>
<h2>The lack of updates</h2>
<p>If you look at the <a href="https://github.com/bower/bower/releases">Bower repository release page</a>, you can see that the platform hasn't been touched (at the time of this article being written) since April. A platform that was as widely used as this, and when you throw in the recent macOS update of Sierra, the lack of updates should come as a bit of an alarm to you.</p>
<h2>No new project adaptation</h2>
<p>As I said above, if you are familiar with Angular 2, Ionic 2, or even <a href="http://foundation.zurb.com/">Zurb's Foundation</a>, currently <strong>none</strong> of these projects have developed Bower components. It is also worth touching on that these three projects also have a corresponding command line interface (CLI) to be able to initializes or compile its assets. As you would expect, these CLI's using NodeJS to install their dependencies. With not relying on Bower to install their dependencies applications such as these can scaffold a project without having to call additional shell commands; resulting in both supplementary speed and stability within the applications.</p>
<h2>Just a few thoughts</h2>
<p>As I draw this <em>techy</em> rant to a close, keep in mind that I am basing my conclusions purely off of observations and some basic research. I proudly disclose that I have not spoken to the Bower guys about the longevity of their project, or do I have any usage metrics to show a decline. Again, just a few thoughts that I tied together into a hypothesis. For all I know, Bower could be alive and well.</p>
<p>But nevertheless, we as developers have to take note of this evidence and begin to make decisions when we are scaffolding a new project or making enhancements to existing projects.</p>
]]></content:encoded></item></channel></rss>