<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: KW Stannard</title>
    <description>The latest articles on DEV Community by KW Stannard (@kwstannard).</description>
    <link>https://dev.to/kwstannard</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F226653%2F62ed8809-742b-4ccd-acb5-bb779acb1dd3.jpeg</url>
      <title>DEV Community: KW Stannard</title>
      <link>https://dev.to/kwstannard</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kwstannard"/>
    <language>en</language>
    <item>
      <title>Avoiding nil errors</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Fri, 16 May 2025 01:06:37 +0000</pubDate>
      <link>https://dev.to/kwstannard/avoiding-nil-errors-hjf</link>
      <guid>https://dev.to/kwstannard/avoiding-nil-errors-hjf</guid>
      <description>&lt;p&gt;Here is a quick way to avoid nil errors and get better failures in Ruby and Ruby on Rails. Convert hashes with known keys into Structs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data = { a: 1, b: 2, c: 3}
...
MyData = Struct.new(:a,:b,:c)
data = MyData.new(a: 1, b: 2, c: 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Structs will throw if you introduce a typo instead of returning nil. This tightens your feedback loops and reduces debugging time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hash[:d] =&amp;gt; nil
struct[:d] =&amp;gt; in 'Struct#[]': no member 'd' in struct (NameError)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is cool. What about in more fluid situations like user input? You can convert arbitrary incoming hashes into known structs quickly with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;params = {a: 1, b: 2, c: 3, x: 9, z: 0}
MyData.new(**params.slice(*MyData.members))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pitfalls
&lt;/h3&gt;

&lt;p&gt;While Structs have much the same interface as hashes, there are some tricky differences.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hash#each is equivalent to Struct#each_pair.&lt;/li&gt;
&lt;li&gt;Hash#keys is equivalent to Struct#members.&lt;/li&gt;
&lt;li&gt;There is no equivalent to Hash#fetch.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Tridactyl and the death of tabs</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Mon, 21 Apr 2025 14:50:00 +0000</pubDate>
      <link>https://dev.to/kwstannard/tridactyl-and-the-death-of-tabs-14gj</link>
      <guid>https://dev.to/kwstannard/tridactyl-and-the-death-of-tabs-14gj</guid>
      <description>&lt;p&gt;This is a simple personal workflow explanation.&lt;/p&gt;

&lt;p&gt;The average number of tabs I keep open is 4. The other day I accidentally closed the last tab and thus the Firefox window. I even hide all Firefox GUI elements so that the page takes the whole window. Yet, I never feel at a loss for how to find a page that I need. The secret is Tridactyl.&lt;/p&gt;

&lt;p&gt;Tridactyl is a Firefox plugin that injects keyboard shortcuts on each page, which is why I started using it. I no longer needed to use the mouse on 99% of web pages that I visit. I still had dozens of tabs though.&lt;/p&gt;

&lt;p&gt;I eventually noticed that the open and tabopen commands showed a list of websites based on the arguments that are being passed. What is happening here is that Tridactyl is taking your history and your bookmarks, concatenating them, and running a search on that list for any websites that match the arguments.&lt;/p&gt;

&lt;p&gt;For example, ":open dockerfile args" will search that list for anything that matches "dockerfile" and "args". I usually get a list with a few items including the direct link to the "args" section of the dockerfile documentation. Very helpful.&lt;/p&gt;

&lt;p&gt;From there it is just a matter of habit of closing tabs the moment you realize you don't need them anymore and then utilizing Tridactyl's history search when you later need something again.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Software Calcification</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Wed, 16 Apr 2025 17:38:37 +0000</pubDate>
      <link>https://dev.to/kwstannard/software-calcification-7nm</link>
      <guid>https://dev.to/kwstannard/software-calcification-7nm</guid>
      <description>&lt;p&gt;Calcification: the gradual, almost imperceptible transformation of a soft, flexible body into a hard, brittle body.&lt;/p&gt;

&lt;p&gt;Software: The original computers were 100% hardware. Inputs were given via wheels, knobs, and cards. Outputs were generated by gears, wheels, transistors, and tubes. The computer had one, maybe two functions it could run. Creation and change were extremely expensive. But, when general purpose computers were invented, you could create and edit functions by merely arranging bits. Thus, "software" was easy and pliable by comparison.&lt;/p&gt;

&lt;p&gt;Software can calcify though. The bonds between parts of the software multiply and strengthen until movement ceases. Eventually, the software faces a stiff wind from an unexpected direction or heavy blow at the wrong place and crumbles, never to recover.&lt;/p&gt;

&lt;p&gt;Sometimes a little calcification is even a good thing. We all have bones, don't we? You don't want your femur fusing to your hip though. Objects in OO can be thought of as planned calcification in a way. We accept that some functions are tied together somehow and that it makes sense that they would move as one.&lt;/p&gt;

&lt;p&gt;How do you know your software is calcifying, even as a non-technical person? You start hearing more and more things like "We could do X, but then we need to change Y". Bugs are taking longer and longer to fix. Features are taking longer and longer to add. Engineers who used to be rising stars are mysteriously burning out and quitting despite no indication of your org being toxic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coupling
&lt;/h2&gt;

&lt;p&gt;The main cause of calcification is a failure to keep coupling to a minimum. Engineering as a profession I think does not understand the threat of excess coupling. Plenty has been written about coupling, but because of the time that passes between when software is first written and when the pain starts getting felt, the coupling gets normalized within your engineering culture. "That function has always gone 5 methods deep into this object and it has never been a problem before." the engineers will say. "We have always used dozens of function mocks per test." they will say. Excessive coupling is normalized in your organization.&lt;/p&gt;

&lt;p&gt;Excessive coupling can be caused by poor:&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain Modeling
&lt;/h2&gt;

&lt;p&gt;Another cause of calcification is bad or out of date domain modeling. Changes are hard because the system does not make sense. This one also tends to be difficult to discover and then the pain gets normalized. "All my design documents have 30 different models, most of which have names only comprehensible to me, and the arrows are going every which way. But, this has worked so far." your architects will say. No one will dare to make a change to something complicated and only barely works for your business.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Willingness to change, adapt, and move are all facilitated by a feeling of security and nothing makes an engineer feel more secure than a good suite of tests. Signs that your test suite is not up to par. "We need to run a full manual UAT program before every deployment" your engineers will say. "We re-run the test suite several times in case of flaking tests" you will hear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Iteration duration
&lt;/h2&gt;

&lt;p&gt;Most software engineering requires some number of loops. There is the micro-loops of Red-Green-Refactor. There is the bigger loop of commit-push-merge. There is the bigger loop still of build-and-release. Slow-downs in these make changes harder. They stiffen and calcify your thinking. When your build time increases, your engineers become less willing to agree to comments on PRs because it will trigger more builds and more waiting. Reviewers will rubber stamp the PR rather than risk getting stuck waiting 30 minutes for their changes to be completed and built. More coupling, bad domain modeling, and bad testing get introduced. The downward spiral of calcification intensifies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prevention
&lt;/h2&gt;

&lt;p&gt;There is no silver bullet here. There are dozens of tools and skills. To name a few:&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Driven Design
&lt;/h3&gt;

&lt;p&gt;TDD is great, but a common pitfall is letting the code dictate the tests, rather than letting tests dictate the code. This is closely related to:&lt;/p&gt;

&lt;h3&gt;
  
  
  Minimal, well defined interfaces
&lt;/h3&gt;

&lt;p&gt;Know your interfaces. Know the levels of your application. Are you running a web app? Your primary interface is http requests. Do you have a job queue? That is another interface. Do you have both a web app and a job queue using the same code? Then you have business logic interfaces as well. Lastly, object and function interfaces.&lt;/p&gt;

&lt;p&gt;Utilize coherence to cut interface sizes down. If you are passing a ton of references or are reaching deep into a reference, there is probably poor coherence somewhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stop using so many mocks please
&lt;/h3&gt;

&lt;p&gt;Your tests are also part of the coupling. Every mock you make is increasing the coupling and causing calcification. For example: instead of writing a test that takes an http request, mocks out 50 things, and returns a result, write a test that takes an http request, mocks out any web requests to external services using something like WebMock, and returns a result. I promise you you will thank me when you realize the client library you were using is no longer maintained and you can swap it out without changing a line of tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Small refactorings
&lt;/h3&gt;

&lt;p&gt;Little problems left to fester will often become very big problems given enough time. Normalize your engineers spending 5-15 minutes per day fixing little issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reversion
&lt;/h2&gt;

&lt;p&gt;I am sorry for you. You will need broad support to turn things around, but if you don’t have that you can do a few things that will might help convince others or at the least, convince youself.&lt;/p&gt;

&lt;h3&gt;
  
  
  fix small things
&lt;/h3&gt;

&lt;p&gt;Pick a small subsystem or class and peck away at it. Reduce the public API from 5 functions to 4 functions. Fix a naming issue. Delete those pointless tests that someone wrote. Add a useful test.&lt;/p&gt;

&lt;p&gt;Do this enough and you will make surprising headway over the course of your tenure. Do not let this spiral and take up your whole day. If the only thing you can think of is a big rewrite, you may want to go read the Refactoring book for ideas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Thanks for reading. This is more of a rough draft on this concept, but hopefully it is helpful.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Naming is a bad place for laziness</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Wed, 16 Apr 2025 14:25:40 +0000</pubDate>
      <link>https://dev.to/kwstannard/naming-is-a-bad-place-for-laziness-32od</link>
      <guid>https://dev.to/kwstannard/naming-is-a-bad-place-for-laziness-32od</guid>
      <description>&lt;p&gt;A very common problem I have seen in pretty much every code-base is lazy naming and it is costing you time and money every day.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is lazy naming?
&lt;/h2&gt;

&lt;p&gt;Lazy naming is a form of tech debt. It is the author throwing up their hands and saying "I don't really understand why I am making this code, so in order to complete the task I will give it a meaningless or generic name". This causes issues for everyone else as the name does not help the team with understanding and encourages other people to accept poor naming. This is a cause of application calcification.&lt;/p&gt;

&lt;p&gt;Lets look at a couple types of lazy naming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grab-bag names
&lt;/h3&gt;

&lt;p&gt;A grab-bag is a pile of mostly unrelated code. Sometimes those methods cannot even function on their without importing other code. Perhaps the author was tasked to move everything out of a big file and ran out of time so they created a grab-bag for all the stuff they didn't get to. Perhaps the author ran out of steam and wanted to get back to it later but it is still there a decade later.&lt;/p&gt;

&lt;p&gt;An example here is ActiveRecord::Core. What is a Core? Who knows. What goes in a Core? Anything. Core is a module with a grab bag of methods that should be in other modules. This causes everyone to jump between files to follow code flows and complete tasks. You cannot use Core without every other ActiveRecord module. You also cannot use other ActiveRecord modules without Core. So, really, the extraction of ActiveRecord::Base into modules did nothing.&lt;/p&gt;

&lt;p&gt;Solution: move what you can to other modules and what you cannot into the root class. Coherence is the name of the game here. If you cannot use a module outside its original context, then there was no point in making the module.&lt;/p&gt;

&lt;h3&gt;
  
  
  ThingDoer names
&lt;/h3&gt;

&lt;p&gt;These are names where there is a clear purpose to the code contained within, but the author failed to use the name to inform future readers as to what to expect inside. This can accellerate purpose drift and feature creep.&lt;/p&gt;

&lt;p&gt;Some common ThingDoer names: ThingProcessor, ThingHandler, ThingFunction.&lt;/p&gt;

&lt;p&gt;Solution: Take a minute to try to describe the code in a few words. Perhaps your SaleProcessor could be a SaleDocumentIngestor. Perhaps your UsernamePasswordHandler could be UserAuthenticator.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Proper naming is key to ensuring that your application can continue to grow and change. Take the time to do it right.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Development as a warehouse</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Mon, 14 Apr 2025 15:32:01 +0000</pubDate>
      <link>https://dev.to/kwstannard/development-as-a-warehouse-1i1p</link>
      <guid>https://dev.to/kwstannard/development-as-a-warehouse-1i1p</guid>
      <description>&lt;h3&gt;
  
  
  Analogy time.
&lt;/h3&gt;

&lt;p&gt;Software and system design are difficult to comprehend without a framework. Analogies can help clarify things. So, in order to help, lets analogize your application as a warehouse and features are boxes that business wants to put in your warehouse. As a software developer, your job is to help manage the warehouse.&lt;/p&gt;

&lt;p&gt;Now, as a new warehouse manager, you start with an empty warehouse/application. You want to get to market as soon as possible. Unfortunately, you have never seen or heard of a warehouse before, so you pick up a box, walk two feet in the door to the warehouse, and place it down. You get another box, walk two feet in the door, and place it down. Another box, you put it on top of the first two.&lt;/p&gt;

&lt;p&gt;Soon you are creating pyramids of boxes. Mazes of boxes. You feel like a genius when you put a new box in. Your boss is amazed and makes you chief warehouse executive.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But&lt;/em&gt;, soon you cannot keep up with the demand. Some boxes are buried in the wrong places. Some boxes are starting to mold. The owners have hire a small army of assistant box management people but the maze of boxes is incomprehensible to anyone but you. The warehouse is losing money hand over fist and eventually is sold for pennies on the dollar to StoringSpoons who fires everyone and collects the money as the warehouse crumbles into dust.&lt;/p&gt;

&lt;p&gt;How can you, the fresh and intrepid warehouse manager, stop this grim future? Warehouses have learned how to scale to massive sizes and with a few practiced tools in your belt you can too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extension
&lt;/h3&gt;

&lt;p&gt;This is kind of like having a roller line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ┌─────────┐                  ┌───────────┐   
  │         │                  │           │   
  │         │    ┌────────┐    │           │    
  │         │    │        │    │           │   
  └─────────┘    └────────┘    └───────────┘   
ooooooooooooooooooooooooooooooooooooooooooooooo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New boxes are added to the front of the line and all the existing boxes roll down the line. The line is "open to extension". If you want to remove a box, you pull it off the line and that does not affect adding more boxes to the line.&lt;/p&gt;

&lt;p&gt;Example of extension: Lists are lines of items. If you can reduce your concept to a list of things, it is probably extension.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encapsulation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ┌─────────┐  ┌─────────┐
  │ ┌┐┌────┐│  │         │
  │ └┘│    ││=&amp;gt;│         │
  │   └────┘│  │         │
  └─────────┘  └─────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boxing. You need to send out manuals, dials, motors, cases, and basins to the customers. You could have them all individually and have 5 work items, or you encapsulate them in a box labeled "washing machine kit" and have one item.&lt;/p&gt;

&lt;p&gt;Example: Files. Files are really just thousands, millions, or billions of bits in memory, but if you encapsulate those bits into a "file" with a set of functions to perform tasks on those bits, then it becomes easier to think about than needing to handle those bits yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Composition
&lt;/h3&gt;

&lt;p&gt;A type of encapsulation and alternative to inheritance. The washing machine kit box "has a" dial. The dial is put into the box.&lt;/p&gt;

&lt;p&gt;Example: Directories "have many" files as a way to organize and think about the files. One can move all the files in a directory with one command instead of many commands. Just like one can move the contents of a box by moving the box.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inheritance
&lt;/h3&gt;

&lt;p&gt;A way to group objects by shared attributes and functionality. You as the warehouse manager might need to store large things and small things so you make two bins for empty boxes. "Big", and "Small". As time goes on you may subdivide this further, but do note that you probably need to throw away the old groupings to prevent confusion as the groupings are conceptually linked.&lt;/p&gt;

&lt;p&gt;Example: Executable files are a subtype of files. They also are a collection of bits and can be manipulated the same as all files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Injection
&lt;/h3&gt;

&lt;p&gt;You hire your first employee, Devin. You start writing down what needs to happen at the warehouse. "Devin preps 30 boxes." "Devin fills 30 boxes." etc. One day, Devin quits and you hire Billy. Oops, now you need to change everything. Instead, you could have written "Box prepper preps 30 boxes" and "box filler fills 30 boxes" then given Devin the titles of Box prepper and Box filler.&lt;/p&gt;

&lt;p&gt;Example of dependency injection: arguments to your executable are you injecting dependencies. You don't write a custom file mover for every file in the system. You pass the file to the mv function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;These are all tools that need practice and exercise. No one builds a perfect warehouse the first time around, much as no one builds a perfect application. The goal is that when you discover why the application is wrong, that you can quickly fix the problem. This might be more of a series as I think of more patterns that can be like a warehouse.&lt;/p&gt;

</description>
      <category>development</category>
    </item>
    <item>
      <title>How to manage developers</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Tue, 14 May 2024 17:47:06 +0000</pubDate>
      <link>https://dev.to/kwstannard/how-to-manage-developers-54d3</link>
      <guid>https://dev.to/kwstannard/how-to-manage-developers-54d3</guid>
      <description>&lt;p&gt;Hey you!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Me?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yeah, we need you down here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We need to see how fast you can walk.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Uh, ok. Let me come down.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks. Can you please walk from here to that cone.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sure thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Alright, you can walk about 3 miles per hour.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why did you need to know that?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I need to tell the board how long it will take you to get to Chicago.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But why are you measuring me walking?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, running will wear you out.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But, I am a goose, why aren't you measuring how fast I can fly?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We don't know how to measure flight. Now, get walking. we will see you in Chicago.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is software development? (It’s management)</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Wed, 10 May 2023 13:28:43 +0000</pubDate>
      <link>https://dev.to/kwstannard/what-is-software-development-8nn</link>
      <guid>https://dev.to/kwstannard/what-is-software-development-8nn</guid>
      <description>&lt;p&gt;A lot of people have expended a lot of words asking what software development is metaphorically. Are we construction workers? Are we factory workers? Are we gardeners? Are we architects? Lets look at what we know.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Where is the value in software? The value that is produced is in the data that our users want to see on their machines. So, value == data + presentation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What makes the value? The application provides data generation and presentation, so the application is ultimately the value generator.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the relationship between the software developer and the application? The software developer creates detailed instructions for the application on how to generate value, determines and monitors metrics to see how well the application is generating value, and makes decisions based on those things.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What does this mean? What other occupation does things like making metrics, monitoring them, and using them improving value production through things like documentation and instruction? There is an answer to this that should be immediately understandable to non-technical people. Software development is a type of management. The “workers” are the processes running on computers.&lt;/p&gt;

&lt;p&gt;Imagine a factory that has all the management go on a retreat. The workers will continue to make product for some amount of time until a failure happens that is not accounted for previously. Perhaps no workers were informed of how to hire a technician to fix a critical machine.&lt;/p&gt;

&lt;p&gt;The same is true in software. If a development team leaves one day, the application will continue to provide value until it fails in a way that was unaccounted for.&lt;/p&gt;

&lt;p&gt;Why does this matter? For one thing, I think this has implications on how a business needs to grade software developers.&lt;/p&gt;

&lt;p&gt;What would you grade a manager on and how would that map to software? I think the most obvious thing would be the application metrics. How many requests are getting served? How long does it take a user to get what they want?&lt;/p&gt;

&lt;p&gt;What are we grading developers on now that do not make sense to grade managers on? Do we grade managers on how many instructions they give to workers? Is it a good idea to grade them on lines added to the employee handbook?&lt;/p&gt;

&lt;p&gt;What else does this metaphor help with? Are there types of software development that don't fit into this metaphor?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>discuss</category>
    </item>
    <item>
      <title>An easy safety in git</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Tue, 03 May 2022 04:21:34 +0000</pubDate>
      <link>https://dev.to/kwstannard/an-easy-safety-in-git-2a5h</link>
      <guid>https://dev.to/kwstannard/an-easy-safety-in-git-2a5h</guid>
      <description>&lt;p&gt;So, everyone's git right of passage is to nervously try to run a git command and then realize with horror that you just lost your work on your local repo. Then you run to google and try to find out how to reverse what you just did and run some archaic commands to find the lost commits.&lt;/p&gt;

&lt;p&gt;With a small amount of foresight, you can just create a new branch called "backup" pointing to your work and reset back to it if necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git branch -C backup
# mess up your git branch
$ git reset backup --hard
# good to go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>git</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Things that are controllers</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Fri, 25 Mar 2022 02:03:08 +0000</pubDate>
      <link>https://dev.to/kwstannard/things-that-are-controllers-3m27</link>
      <guid>https://dev.to/kwstannard/things-that-are-controllers-3m27</guid>
      <description>&lt;ol&gt;
&lt;li&gt;ActionControllers for the http interface.&lt;/li&gt;
&lt;li&gt;Rake tasks are controllers for the cli interface.&lt;/li&gt;
&lt;li&gt;Workers are controllers for the async job queue interface.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Just a random thing more people should know about.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Quadragonal</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Wed, 23 Mar 2022 13:51:31 +0000</pubDate>
      <link>https://dev.to/kwstannard/quadragonal-3m19</link>
      <guid>https://dev.to/kwstannard/quadragonal-3m19</guid>
      <description>&lt;p&gt;Bob: My tests take so long!&lt;/p&gt;

&lt;p&gt;Steve: Why do they take so long?&lt;/p&gt;

&lt;p&gt;Bob: My records take forever to create and save to the database!&lt;/p&gt;

&lt;p&gt;Steve: Why does your records taking forever affect your test run so much?&lt;/p&gt;

&lt;p&gt;Bob: Because my logic is pulling and storing stuff in the database and I need to test it.&lt;/p&gt;

&lt;p&gt;Steve: Why is your logic pulling and storing in the database?&lt;/p&gt;

&lt;p&gt;Bob: uhhh... because that is how I learned how to write Rails? You aren't about to lecture me about Hexagonal are you?&lt;/p&gt;

&lt;p&gt;Steve: No, but have you ever seen a fast test suite with the way people normally write Rails?&lt;/p&gt;

&lt;p&gt;Bob: No, but I feel like you are about go on about something, so go ahead and get it over with.&lt;/p&gt;

&lt;p&gt;Steve: So, the key to a fast test suite is to separate handling of logic from handling of state as much as possible. That is fairly easy in most cases. First, you extract the data from the database. Then, you run the logic on the data. Finally, you save the result to the database in a transaction. What does that get you?&lt;/p&gt;

&lt;p&gt;Bob: I think I see, you don't have costly database dependencies within the business logic.&lt;/p&gt;

&lt;p&gt;Steve: Yes, and the tests for the full unit only needs a success and failure case, because none of it matters unless the transaction runs and succeeds.&lt;/p&gt;

&lt;p&gt;Bob: Thats all nice, but ActiveRecord has so many methods that can query the database, it is easy to get tripped up.&lt;/p&gt;

&lt;p&gt;Steve: Yes, that is a tricky one. You may want to do something like disabling the connection. This for example prevents calling the database by switching to a non-existing connection specification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_no_connection!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;old_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection_specification_name&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection_specification_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'with_no_connection active'&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection_specification_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;old_name&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bob: I could perhaps use that during testing but not in production so that I don't get 500s from test concerns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_no_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test?&lt;/span&gt;
      &lt;span class="n"&gt;with_no_connection!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Steve: Good call.&lt;/p&gt;

&lt;p&gt;Bob: To go over it one more time. We improve our testing speed by avoiding calls to the database within the logic. First extract all the needed data, then run the logic on the data, and finally save back to the database. Do you have a little example?&lt;/p&gt;

&lt;p&gt;Steve: That sounds right. Here is an example in a controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MovesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="c1"&gt;# query db, build objects&lt;/span&gt;
    &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:places&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;old_place&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current_place&lt;/span&gt;
    &lt;span class="n"&gt;new_place&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:new_address&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c1"&gt;# pass objects to stateless logic&lt;/span&gt;
    &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_no_connection&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="no"&gt;Move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old_place&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_place&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# save state in transaction&lt;/span&gt;
    &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
      &lt;span class="n"&gt;old_place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
      &lt;span class="n"&gt;new_place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="ss"&gt;:no_content&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bob: That looks pretty close to normal Rails, plus in the Move tests I do not need anything in the database! Interesting. What is with the title of this article anyways?&lt;/p&gt;

&lt;p&gt;Steve: Quadragonal is a play on Hexagonal, but there are only 4 parts. The controller, the state, the logic, and the view.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Composition and Inheritance</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Fri, 25 Feb 2022 16:00:55 +0000</pubDate>
      <link>https://dev.to/kwstannard/composition-and-inheritance-eno</link>
      <guid>https://dev.to/kwstannard/composition-and-inheritance-eno</guid>
      <description>&lt;p&gt;&lt;em&gt;Content Warning: scatological example&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I was discussing composition over inheritance with a friend recently and he sent me this as a way to help clarify the subject.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Inheritance
class Animal
  def eat
    # eats
  end
end

class Dog &amp;lt; Animal
end

# Composition?
module Pooping
  def poop
    # poops
  end
end

class Cat
  include 'pooping'
end

# Composition?
class Farting
  def fart
    # farts
  end
end

class Hamster
  has_a :farting
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, first off, one extremely common misconception is that the second scenario is OO composition. It is not. Only the third example is OO composition because OO composition is an object containing references to other objects. However in the third example the name Farting is bad because Farting is a state of being and not an thing that can be encapsulated by a hamster. Names are important for clarity.&lt;/p&gt;

&lt;p&gt;After reading this I decided to show him what OO composition might look like for the case of modeling animal digestion.&lt;/p&gt;

&lt;p&gt;First off you need to consider the objects involved. An animal is obviously there. There is also a system of organs in an animal for digestion called the gastrointestinal (GI) tract. For simplicity sake I will avoid modeling the individual organs of the GI tract and move on to writing some code for eating.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Animal
  def initialize
    @gi_tract = GITract.new
  end

  def eat(food)
    @gi_tract.injest(food)
  end
end

class GITract
  def initialize
    @contents = []
  end

  def injest(food)
    @contents &amp;lt;&amp;lt; food
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, now we have an animal that eats and successfully passes the food to its GI tract. How about pooping?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Animal
  ...
  def poop
    @gi_tract.evacuate
  end
end

class GITract
  ...
  def evacuate
    Waste.new(@contents.shift)
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is nice, but not quite right. Usually irl I get told I need to go poop by my gi_tract. We need a two way relationship between the animal and gi_tract in order to model that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Animal
  def initialize
    @gi_tract = GITract.new(owner: self)
  end
  ...
end

class GITract
  def initialize(owner:)
    @owner = owner
    @contents = []
    @waste = []
  end

  def digest
    @contents &amp;lt;&amp;lt; nil
    @waste &amp;lt;&amp;lt; @contents.slice!(1..-5).compact.map{|food| Waste.new(food) }

    @owner.poop if @waste.any?
  end

  def evacuate
    @waste = []
  end
  ...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, that is looking good. We have now modeled an Animal eating and pooping by having a GI tract. But, what about modeling subtypes of Animal? Here is where we can introduce inheritance back in as inheritance is for modeling subtypes. Lets use Cats and Hamsters because they eat different things and have different subtypes of GI tracts and cats have a different pooping behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Cat &amp;lt; Animal
  def initialize
    @gi_tract = CarnivoreGITract.new
  end

  def poop
    hide
    squat
    @gi_tract.evacuate
  end
end

class Hamster &amp;lt; Animal
  def initialize
    @gi_tract = HerbivoreGITract.new
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! Lets wrap this up. We have successfully encapsulated a lot of behavior inside of GI tract objects. By having that behavior encapsulated we can make changes with much more confidence and with fewer errors. We could from here fairly easily model a cat that is herbivorous or a carnivorous horse.&lt;/p&gt;

&lt;p&gt;Leave comment on what you would do next!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ruby</category>
      <category>tutorial</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Mixins are inheritance</title>
      <dc:creator>KW Stannard</dc:creator>
      <pubDate>Fri, 31 Dec 2021 03:09:14 +0000</pubDate>
      <link>https://dev.to/kwstannard/mixins-are-inheritance-2dc6</link>
      <guid>https://dev.to/kwstannard/mixins-are-inheritance-2dc6</guid>
      <description>&lt;p&gt;Inheritance is getting a bad rap and rightfully so in my opinion. Inheritance has turned out to be a specialist tool for specific situations and was unfortunately overused. Long story short, &lt;a href="https://en.m.wikipedia.org/wiki/Composition_over_inheritance" rel="noopener noreferrer"&gt;try composition before inheritance&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, that said, I have come across developers who understand the above and yet still fall unwittingly into the trap of inheritance over-use. This happens because they think mixins are composition, but mixins are actually &lt;a href="https://ruby-doc.com/docs/ProgrammingRuby/html/tut_modules.html" rel="noopener noreferrer"&gt;Ruby's answer to multiple inheritance&lt;/a&gt;. Don't believe me?&lt;/p&gt;

&lt;p&gt;Here is an example of classic inheritance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Superclass; def talk; "world"; end; end
class Subclass &amp;lt; Superclass; def talk; "hello #{super}"; end; end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now here is an example usage and a look under the hood.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;puts Subclass.new.talk
#&amp;gt; hello world
puts Subclass.ancestors.inspect
#&amp;gt; [Subclass, Superclass, Object, PP::ObjectMixin, Kernel, BasicObject]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, here is the same code using mixins. Note that the method signature is identical.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module Superclass; def talk; "world"; end; end
class Subclass; include Superclass; def talk; "hello #{super}"; end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And again, a usage and a look under the hood. Note that they are identical to the classic inheritance implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;puts Subclass.new.talk
#&amp;gt; hello world
puts Subclass.ancestors.inspect
#&amp;gt; [Subclass, Superclass, Object, PP::ObjectMixin, Kernel, BasicObject]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To sum up, mixins are going to run into most of the problems you would get with inheritance because they are a type of inheritance.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
