<?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 Rickfactr]]></title><description><![CDATA[Developing software since 1977 or thereabouts... do the math. Yep... more than 45 years... So, maybe... just MAYBE... I've earned the right to a rant or three. ]]></description><link>https://therickfactr.culpepperscorner.com</link><generator>RSS for Node</generator><lastBuildDate>Mon, 20 Apr 2026 09:16:26 GMT</lastBuildDate><atom:link href="https://therickfactr.culpepperscorner.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Break Into AI Development Without Really Trying]]></title><description><![CDATA[A week ago, I was assigned a take-home engineering problem in an interview. On one hand, I was excited to have a reason to dive into some code, but this was all about creating an AI Chat interface using RAG techniques.
The requirements were pretty cl...]]></description><link>https://therickfactr.culpepperscorner.com/how-to-break-into-ai-development-without-really-trying</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/how-to-break-into-ai-development-without-really-trying</guid><category><![CDATA[software development]]></category><category><![CDATA[AI]]></category><category><![CDATA[#ai-tools]]></category><category><![CDATA[job-hunt]]></category><category><![CDATA[interview]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Fri, 04 Apr 2025 16:53:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/2JIvboGLeho/upload/a0c0fc251411cbad121253b3f4f02289.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A week ago, I was assigned a take-home engineering problem in an interview. On one hand, I was excited to have a reason to dive into some code, but this was all about creating an AI Chat interface using <a target="_blank" href="https://aws.amazon.com/what-is/retrieval-augmented-generation/">RAG</a> techniques.</p>
<p>The <a target="_blank" href="https://bluebook-accounting.notion.site/Paul-Graham-Essay-RAG-Stack-1ba39a6192708044aa47cffb944b64bf">requirements</a> were pretty clear. An AI Chat UI to query the content of <a target="_blank" href="https://www.paulgraham.com/articles.html">Jack Graham’s Essays</a> using an LLM. Event though I’d never written any code integrating AI functionality and though my Python skills were shallow at best, still, this seemed easy enough… Right?</p>
<p>First off, I thought that since I would be writing code are AI, maybe I should use AI to help me write the code. I immediately downloaded Cursor. I won’t review Cursor here, but let me just say, “Wow!” It’s literally VS Code with an AI assistant that can generate <em>reams</em> of pretty darned good code. Of course, that code needs to be vetted, sometimes corrected (with the aid of the AI assistant?)… If you haven’t already, I suggest you give it a whirl for a free two-week trial. There is an always-free model in addition to subscription models.</p>
<p>Next, I set up Supabase locally as suggested in the requirements.</p>
<p>With Cursor and Supabase installed, I asked it to generate a Python script for data ingestion. WOW! I had it “working” in about 30 minutes. Now, granted, I rewrote that script several times as my understanding of tools and technical issue grew, but the last version still bears a striking resemblance to the AI-generated original.</p>
<p>Cursor introduced me to the Python “requests” module and Beautiful Soup for web scraping. As I dug into the world of Tokens, Vectors, and Embeddings for documents, learning what each of these concepts represents, I discovered — and learned about — the Supabase (postgreSQL) <code>pgvegtor</code> extension, Supabase migrations, LangChain’s WebLoader, RecursiveCharacterTextSplitter, OpenAIEmbeddings and SupabaseVectorStore components. FWIW, LangChain was a god-send.</p>
<p>As I moved on to the backend app, Cursor did a yeoman’s job of scaffolding Node.js and Express.js to implement a REST API. That code required some tweaking along the way to make use of the JavaScript versions of LangChain’s components and the Supabase client, but it basically did the basic job right from the start.</p>
<p>Then I had Cursor scaffold the Chat API using Next.js and Shadcn UI components. This was a reasonably good UI. I did have to hand-code the integration between the LLM search and the <code>match_documents</code> function that I’d set up early on. This also required some refactoring of <code>match_documents</code> and the Python data ingestion script to ensure that the essay titles were always captured when the essay page did not contain a <code>&lt;title/&gt;</code> element.</p>
<p>Lastly, there was some clean-up and documentation to do. Cursor helped with both.</p>
<p>The final project, <a target="_blank" href="https://github.com/therickfactr/PaulGrahamEssays">PaulGrahamEssays</a>, is publicly available on GitHub. If you feel the need to comment, remember, this was a learning project, not the product of years of experience…</p>
<p>In all, I would say this project was about 60% learning new concepts, tools, and techniques and about 40% writing code.</p>
<p>In the end, even if I don’t get a job offer from this company, I have demystified the basics of developing apps with AI integration for myself. This widens the scope of jobs to which I will be applying. That’s all good!</p>
]]></content:encoded></item><item><title><![CDATA[After the RIF: First Days]]></title><description><![CDATA[I lost my job on Tue, Feb 11, 2025, in a RIF that I didn't see coming...
I am a late-career professional and had hoped to retire from that company in a few years. Now, I’m job-hunting.
I am an early riser. I set my alarm for 5:45am. most mornings I'm...]]></description><link>https://therickfactr.culpepperscorner.com/after-the-rif-first-days</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/after-the-rif-first-days</guid><category><![CDATA[rif]]></category><category><![CDATA[laidoff]]></category><category><![CDATA[job search]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Tue, 18 Feb 2025 14:12:56 GMT</pubDate><content:encoded><![CDATA[<p>I lost my job on Tue, Feb 11, 2025, in a RIF that I didn't see coming...</p>
<p>I am a late-career professional and had hoped to retire from that company in a few years. Now, I’m job-hunting.</p>
<p>I am an early riser. I set my alarm for 5:45am. most mornings I'm up between 3:00 and 4:00 am and turn my alarm off. After I feed the cats, I head to my desk… but since that fateful day, my task is to labor through a job search instead of doing what I love… writing software… CODE.</p>
<p>With the help of a long-time friend, I've spent the last week re-writing my resume. It's been a real challenge… a pain. It seems that the "rules" for writing a resume have changed completely since I was last in the job market. So, I can’t just add my most recent job experience to the old resume and recycle it. It seems like resume-writing has become a "game" where you must “quantify” unquantifiable accomplishments so that the ATS (Applicant Tracking System) can be “objective” in evaluating your resume. Oh, and be sure it’s not more than 1-2 pages in length, never mind your work history which should be limited to the last 10-15 years. Make sure that everything important about you is visible in the top 1/3 of the first page since that is all the recruiter will read. The rules and recommendations are endless, but they are designed to get the ATS to pick your resume over the hundreds, maybe thousands of others that applied for the same position.</p>
<p>I'm trying to fight the depression that is creeping in on me, a gray-haired professional RIF-ed in what should have been the golden years of a successful career. My wife has been a God-send to keep me out of the “poor-pitiful-me” syndrome.</p>
<p>So, I’m working on establishing a routine, but it's tough. The part up to sitting down at my desk all feels the same. But once I sit down, I have to really think about what I am going to do today. After pushing through the morning, I find myself napping in the mid- to late-afternoon hours because I’m just worn out from the tedium of all of this job-hunting.</p>
<p>Meanwhile, I am networking and applying for “interesting” positions. We’ll see where this all leads.</p>
<blockquote>
<p>Note: I used BeamJobs (https://www.beamjobs.com) Resume Writing Assistant which has helpful AI-based reviews to get you to good place. It doesn’t do everything for you, but it will gently lead you into a good result. A 1-year subscription is less than $100.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Change: The Only Universal Constant]]></title><description><![CDATA[Friday, February 14, 2025 (Valentine’s Day), will be my last day working for the organization from which I had hoped to retire.
Once again, change, the only universal constant, comes without warning.
On Monday, February 3, 2025, my employer publicly ...]]></description><link>https://therickfactr.culpepperscorner.com/change-the-only-universal-constant</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/change-the-only-universal-constant</guid><category><![CDATA[opentowork]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Thu, 13 Feb 2025 14:37:43 GMT</pubDate><content:encoded><![CDATA[<p>Friday, February 14, 2025 (Valentine’s Day), will be my last day working for the organization from which I had hoped to retire.</p>
<p>Once again, change, the only universal constant, comes without warning.</p>
<p>On Monday, February 3, 2025, my employer publicly announced the acquisition of another company in the same sector of the CyberSecurity industry. This organization has been around for a good while and has developed internal tooling that is provides some of the same process orchestration features as the internal product for which I’ve been a Principal Software Engineer for the last 4½ years. My entire team learned on Tuesday that our product will not be part of the merged organization and, as such, our services are no longer required.</p>
<p>So, here I sit. In the final years of my career, faced with finding a new job.</p>
<p>I had really hoped to retire in 1-2 year from this organization. However, I am not ready yet — emotionally or financially — to enter retirement. I still love software engineering and the challenges that it presents. I still need to sock away some more cash before I’m ready to retire.</p>
<p>I’ve spent the last few days trying to get organized. My resume is 5 years old and out of date with my current experience and doesn’t meet today’s standards for a successful job search. Thankfully, an old friend who’s helped others with resume updates has offered to guide me through the process. I’ll be honest, the effort required seems daunting and this is not the kind of thing I enjoy doing. Honestly, I’d rather be slinging code.</p>
<p>Also, I don’t relish the thought of the interview/hiring process. It’s always been nerve-wracking and even more so these days with in-depth tech interviews that put you on the spot to write challenging code on the spur of the moment.</p>
<p>And then there’s the issue of age-ism. I am nearing retirement and am already past the “expected” age of retirement. Despite my many years of experience (45+), I know that most technical organizations want to hire young bucks with fancy degrees and flashy web sites that show their UI skills. Being an old dinosaur who’s been a back-end engineer for the vast majority of his career, I don’t have any flash to show. My skills are in REST APIs and back-end databases (SQL &amp; NoSQL) mostly developed in private, enterprise apps. These are almost impossible to “showcase”.</p>
<p>I will persist in my job search and hope to find a place where I can contribute significantly to the success of a software engineering organization for a few years before the curtain falls on my career as a software engineer.</p>
<p>If anyone has any recommendations, I would love to hear about them.</p>
]]></content:encoded></item><item><title><![CDATA[Persistence Pays]]></title><description><![CDATA[We all have our political leanings. Some of us take that to the point of contributing to political candidates whom we support. However, before you pull the trigger on that donation, be prepared. Donating to a political candidate will almost certainly...]]></description><link>https://therickfactr.culpepperscorner.com/persistence-pays</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/persistence-pays</guid><category><![CDATA[politics]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Tue, 15 Oct 2024 12:17:48 GMT</pubDate><content:encoded><![CDATA[<p>We all have our political leanings. Some of us take that to the point of contributing to political candidates whom we support. However, before you pull the trigger on that donation, be prepared. Donating to a political candidate will almost certainly result in an ever-increasing number of requests for additional donations. There will be emails… and text messages… many, many, many of them.</p>
<p>Political fundraising is a highly-consolidated field these days. Each political party has their fundraising “partner” who, generally, coordinates fund-raising for many of the party’s candidates in federal elections (i.e., President, Vice-President, Senate, and House of Representatives).</p>
<p>Once you contribute to a candidate’s campaign, you will begin to receive requests for additional donations. However, not all these requests are what you might think. You <strong><em>MUST</em></strong> read the fine print. However, the fine print is not in the request you receive. no, it is in the web-page that opens when you follow the link in the request.</p>
<p>Back to the fine print. This where you find out where your donation will goThe recipient <strong><em>might</em></strong> be:</p>
<ol>
<li><p>The campaign of your candidate. This is the most direct way to get a contribution to a candidate you support.</p>
</li>
<li><p>A political action committed (aka, “PAC”) that supports your candidate and possibly other candidates as well. This may end up in your candidates coffers… and it may not. PACs are a whole separate topic.</p>
</li>
<li><p>Another candidate <em>whose name you’ve never heard and who is running for office in another state far away!</em> I really despise these requests. If elected, this candidate won’t represent me. Why don’t they limit their fundraising to the district(s) they will represent.</p>
</li>
<li><p>The political party itself. For example, the Democratic National Committee or the Republican National Committee. Donations may be used to pay their expenses… or maybe they are used to pay expenses of the committee… or they might got o candidates. The question is which candidate(s)? My candidate? Who can know?</p>
</li>
<li><p>The organization (business) that sends these donation requests on behalf of candidates. These guys have a bunch of sources of income. For sure, they are charging the candidates for their services or taking a “piece” of each donation. Maybe they get some of the card fees, too. I can’t say for sure. I can say that this is the least likely way to get your donation to your candidate.</p>
</li>
<li><p>Some other beneficiary? I dunno. Maybe. Maybe not.</p>
</li>
</ol>
<p>Oh. I forgot to mention this. As soon as you click on the link in the request to read the fine print, they’ve got you. They now know that YOU are likely to click on the link in a future request. Clickers are MUCH more likely to make a donation. So, once you click, expect the number of requests to increase.</p>
<p>How do you stop the onslaught of requests?</p>
<ol>
<li><p>For text messages, I block the number on my phone, reply “STOP” to the message, and then delete the message. This has to be done for every phone number that sends you one of these messages. Trust me, they have a bunch of them. Keep doing this religiously and the volume will taper off.</p>
</li>
<li><p>For email messages, unsubscribe. Some email servers (e.g., Proton Mail) will provide an Unsubscribe button for any email they can identify as “automated”. Use it. It’s much faster than doing it manually. Otherwise, scan the email for the link to “Unsubscribe” or “Manage You Accounts/Subscriptions”, clink on the link and unsubscribe. <strong><em>READ THE WE PAGE CAREFULLY</em></strong>. Some of them have tricky wording and you might be <strong><em>confirming</em></strong> your subscription and email address rather than unsubscribing. You will have to do this many times, but be persistent and it will slow down the incoming mails.</p>
</li>
</ol>
<p>These solicitors for political donations remind me of the widow described in a story that Jesus told in Luke 18. This widow kept pestering the judge to give her a judgement against her adversary. Finally, the judge gave her what she wanted — not because he thought she was justified in her request, but because he was tired of hearing her request over and over and over again.</p>
<p>These days, I think politicians just keep asking and asking and asking thinking that sooner or later, you’ll give something.</p>
<p>Personally, I’d prefer that they respect that fact that someone has donated and not ask again for a good long while.</p>
<p>But that’s just me… and I’ve never been a candidate, much less raised enough money to get elected.</p>
]]></content:encoded></item><item><title><![CDATA[When One's Job Is Not A Job]]></title><description><![CDATA[I've been at this business of software development since I took a class in FORTRAN at Baylor University's Hankamer School of Business during my Freshman year of college. That was in the Fall of 1977 or Spring of 1978. The rest, as they say, is histor...]]></description><link>https://therickfactr.culpepperscorner.com/when-ones-job-is-not-a-job</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/when-ones-job-is-not-a-job</guid><category><![CDATA[love my job]]></category><category><![CDATA[software development]]></category><category><![CDATA[Career]]></category><category><![CDATA[Retirement]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Fri, 21 Jun 2024 21:15:11 GMT</pubDate><content:encoded><![CDATA[<p>I've been at this business of software development since I took a class in FORTRAN at Baylor University's Hankamer School of Business during my Freshman year of college. That was in the Fall of 1977 or Spring of 1978. The rest, as they say, is history. Fourty-seven years later, I still get my kicks and make a decent living writing software for a large, respected cybersecurity firm.</p>
<p>I've always said that life is too short not to love what you do and I can say, without question, that I still love what I do. Having the opportunity to continue working in the technology business as a Principal Software Engineer is very satisfying... and rewarding!</p>
<p>I am grateful for the career I've had thus far. I am also looking forward to the next few years as I approach retirement. I don't have a certain date in mind but, God willing, I'll keep at this for at least two more years... maybe more.</p>
<p>Lots of people look forward to retirement with great anticipation. For me, retirement is something that will come... eventually. However, it's not (yet) what I live for.</p>
<p>Thank you to all of my employers, co-workers, mentors, customers and colleagues who have supported me over the years. You've made this one heck of a ride!</p>
]]></content:encoded></item><item><title><![CDATA[Honey, It's a Deer!]]></title><description><![CDATA[Apart from the 5 years that we lived in New Mexico, my wife and I have lived in Tennessee most of our lives. For her, New Mexico was the only time she has lived out of state. For me, well... my state of residence has been more fluid over the years, b...]]></description><link>https://therickfactr.culpepperscorner.com/honey-its-a-deer</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/honey-its-a-deer</guid><category><![CDATA[country living]]></category><category><![CDATA[life]]></category><category><![CDATA[Wildlife]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Tue, 23 Jan 2024 11:42:08 GMT</pubDate><content:encoded><![CDATA[<p>Apart from the 5 years that we lived in New Mexico, my wife and I have lived in Tennessee most of our lives. For her, New Mexico was the only time she has lived out of state. For me, well... my state of residence has been more fluid over the years, but I have lived in Tennessee for more than half my life.</p>
<p>Here in the Volunteer state, you are born and bred to watch for wildlife on the roads. Usually, the most dangerous are wild deer out foraging for food or, during rutting season, seeking out a mate. In Tennessee, when driving along with your spouse, you are likely to hear, "Honey, it's a deer!"</p>
<p>In the desert of New Mexico's Middle Rio Grande Valley, deer were not an issue. However, free range cattle, especially near our home on top of a desert mesa, were a big and constant concern. These are cattle -- bulls, cows, calves -- that are owned by a rancher, but are allowed to roam freely to forage for food. It takes a lot more land to sustain a herd when it's covered with desert scrub instead of prairie grass. Driving down the road, you might come up on a small herd of cattle blocking the road at any time. So, In New Mexico, I'd be more likely to hear, "Honey, it's a steer!".</p>
<h2 id="heading-honey-its-a-deer">"Honey, it's a deer!"</h2>
<p>Well, now we're back in Tennessee and, last night, we had a "Hone, it's a deer!" moment. Let me explain.</p>
<p>Yesterday evening, my wife and I had nice, quiet dinner at a quaint little Mexican restaurant about 20 minutes away from our home in the countryside of west Tennessee.</p>
<p>The route to and from the restaurant includes about 10 miles of travel on a well-maintained, two-lane country highway that winds through the hills and trees. The speed limit is 55mph except a 2-mile stretch near the north end through an small farming community where it drops to 45mph. There is always a fair amount of traffic along the narrow-shouldered highway, including some 18-wheelers. At night, most of this stretch of road is lit only by the headlights of the vehicles traveling here. Too, the trees along the highway are seldom more than 20-30 feet from the shoulders of the pavement.</p>
<p>After dinner, we were driving along this dark stretch of highway on our return home when, somewhere in the middle-ish part of this stretch, two small deer appeared at the left side of the road. I think it was either two does or a doe and a fawn, but I can't be sure. It all happened so fast.</p>
<p>Out of concern for the deer and knowing that, even in a big pickup, hitting a deer at ~55mph could be a dangerous, I immediately applied the brakes. Just as I began to slow, the first deer ran across the highway in front of us perhaps 30-50 yards ahead of us. Continuing to brake, I figured instinctively that this first critter would be off the the highway to the right before we arrived.</p>
<p>But there was a second deer... the proverbial "deer in headlights". I could see the glow of it's eyes reflecting our headlights as it stood transfixed. I continued to slow down because, while you never know what these critters will do, it seems they're apt to dart out in front of an oncoming vehicle at the last second.</p>
<p>For a fleeting moment, I thought we might pass without incident.</p>
<p>Tragically, those hope were dashed when, just as we passed, this poor second deer darted out from the highways edge and straight into the driver's side of our truck. I had slowed down significantly (maybe 25-30 mph?) but the impact was pretty hard. There was a loud thump when the deer collided with the rear door on the driver's side and then... well, I think the little deer was run over by the left rear wheel.</p>
<p>Rattled, I immediately came to a stop on the side of the road. On this dark highway, I didn't dare step out of the truck to look for the deer. It was too dangerous. In fact, my wife noticed a driveway directly across the road and we pulled in to gather ourselves for a moment.</p>
<p>Our thoughts went immediately to the poor deer that we'd hit. We just hoped that it hadn't suffered long...</p>
<p>Thankfully, we were both uninjured though we were both upset by the whole incident. After a moment, I got out and used the flashlight light on my phone to assess the damage to the truck. There is definitely a decent-sized dent in the rear door on the driver's side, but nothing serious. This could have been a LOT worse for us and the truck, but we were sick about hitting a poor, helpless deer... but at this point, there was nothing to be done.</p>
<h2 id="heading-historical-oddities">Historical Oddities?</h2>
<p>Oddly, about 6½ years ago -- in late 2017 -- we'd had a similar "Honey, it's a deer!" moment on another, darker, narrower, less busy road in Middle Tennessee. That incident occurred 10 months <strong><em>before</em></strong> we moved to New Mexico. Last night's incident occurred 10 months <strong><em>after</em></strong> we left New Mexico.</p>
<p>Significant? I dunno, but I'd already been thinking about these kinds of things this week.</p>
<p>Over the past 8-9 days, west Tennessee has experienced some unusual, historic winter weather. We got 6" snow in 24 hours followed by bitter cold that kept the snow on the ground for 8+ days. The nighttime lows have been down in to the negative double digits (&lt;-10℉) on a couple of nights and daytime highs have struggled to get into the 20's most days.</p>
<p>It seems like this is the biggest snow anyone around here can remember in recent history and it's happening during the first winter after we moved back to Tennessee.</p>
<p>The first winter we were in New Mexico, a winter storm dropped about a foot of snow right after Christmas and that snow stayed on the ground for a week or more. It was the worst winter storm anyone in New Mexico could remember.</p>
<p>Hmmm... Oh, and have a I mentioned that my wife and I hate cold weather?</p>
<p>As I grow older, it occurs to me from time to time that there have been more than a few of these oddly similar events over my lifetime. Each time I dwell on these events and their similarities, I'm left wondering whether there might be any significance in those similarities... or whether it's all just coincidence.</p>
<p>I reckon I'll probably never know...</p>
]]></content:encoded></item><item><title><![CDATA[Pollution Sucks.]]></title><description><![CDATA[💡
Note: Before I start, let me make it perfectly clear. I will neither start nor be drawn into a discussion about the environment, environmentalists, or environmentalism. In fact, I am headed in an entirely different direction with this. Sorry for p...]]></description><link>https://therickfactr.culpepperscorner.com/pollution-sucks</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/pollution-sucks</guid><category><![CDATA[rookiemistake]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[coding]]></category><category><![CDATA[problem_solving]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Tue, 12 Dec 2023 09:51:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702374980878/c2fc9df1-59be-48c3-ad9c-b76522767bdd.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text"><strong><em>Note</em></strong><em>: Before I start, let me make it perfectly clear. I will neither start nor be drawn into a discussion about the environment, environmentalists, or environmentalism. In fact, I am headed in an entirely different direction with this. Sorry for playing on anyone's emotions with the title.</em> 😳</div>
</div>

<p>If you have read my post, <a target="_blank" href="https://hashnode.com/post/clc9ndm6f000308l7hykxcfdy">Dev Retro 2022: What I learned in my 43rd year...</a>, you know I've been in the software development game for a long time. However, it's only recently -- the last three years or so -- that I have used Javascript and Typescript professionally -- and exclusively -- in my role as a full-stack MERN engineer. <em>(Note: Hereinafter, when I mention Javascript or JS, know that I'm including Typescript (TS) unless I clearly state otherwise.)</em></p>
<p>There are days when I love JS/TS. The language's rich prototypes for objects and arrays; the wealth of utilitarian methods available on those prototypes; the economy of expression that is possible in one's code; the freedom to use Type-based code (ES6+/Typescript) when it serves a REAL purpose; the freedom to eschew type-based code when it becomes a limiting factor. All of these aspects of the language are useful and, perhaps, are among the reasons that Javascript has become the language of choice for many Web apps both on the client and server side.</p>
<p>...but "da devil be lurkin' in dem details..."</p>
<p>This particular devil bit me this week. I managed to pollute the <code>Array</code> constructor in one mistyped line of code that brought testing to a halt for several hours while a handful of extremely experienced engineers -- including me -- puzzled over an error being thrown deep inside the code of a third-party package: <code>Array.isArray is not a function</code>.</p>
<p>It took several hours to identify the culprit -- an errant line of code in the app itself. Here's what the code looked like, essentially.</p>
<pre><code class="lang-typescript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">wasWorkingUntilRecentChanges</span>(<span class="hljs-params">...args</span>) </span>{

    <span class="hljs-comment">// do some stuff for 10-15 lines of high-density code</span>

    <span class="hljs-keyword">const</span> thisArray = <span class="hljs-built_in">Array</span>&lt;Record&lt;<span class="hljs-built_in">string</span>,<span class="hljs-built_in">any</span>&gt;&gt; = 
        thatArray.filter(<span class="hljs-function">(<span class="hljs-params">i</span>) =&gt;</span> i.property);

    <span class="hljs-comment">// do some more stuff for 10-15 lines of high-density code</span>

    <span class="hljs-comment">// Suddenly, this line of code has begun throwing an Error</span>
    <span class="hljs-comment">// with the message `Array.isArray is not a function`</span>
    <span class="hljs-keyword">const</span> myResult = em.find(MyType, {});
</code></pre>
<p>Do you see it? I suppose the problem might be incredibly obvious here since I have elided the surrounding code that obfuscated the mistake.</p>
<h6 id="heading-example-1-the-simple-line-of-code-that-should-have-been">Example 1 - The simple line of code that should have been</h6>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> thisArray: <span class="hljs-built_in">Array</span>&lt;Record&lt;<span class="hljs-built_in">string</span>,<span class="hljs-built_in">any</span>&gt;&gt; = 
        thatArray.filter(<span class="hljs-function">(<span class="hljs-params">i</span>) =&gt;</span> i.property);
</code></pre>
<p>This was what was intended -- declaring an array with a specific type to catch the result of <code>thatArray.filter()</code>.</p>
<h6 id="heading-example-2-the-similar-looking-though-monstrously-fateful-line-of-code-that-was">Example 2 - The similar-looking, though <em>monstrously fateful</em> line of code that was</h6>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> thisArray = <span class="hljs-built_in">Array</span>&lt;Record&lt;<span class="hljs-built_in">string</span>,<span class="hljs-built_in">any</span>&gt;&gt; = 
        thatArray.filter(<span class="hljs-function">(<span class="hljs-params">i</span>) =&gt;</span> i.property);
</code></pre>
<p>This was the actual code that was committed -- a multiple assignment statement that polluted (over-wrote) the <code>Array</code> constructor object.</p>
<p>Note that the damage caused here didn't result in any errors or warnings from Javascript, Typescript or ESLint in VS Code. They all silently approved.</p>
<p>There was no complaint from the Typescript compiler when the code was built.</p>
<p>Only when the code (a CLI) was run in Node.js did the monstrous result become manifest: <code>Array.isArray is not a function</code>.</p>
<p>Wha...?!?!?!</p>
<p><code>Array</code> is the constructor function for <strong><em>every</em></strong> array in Javascript (see <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a> on MDN). It is provided as part of the Javascript engine in the execution environment -- Node.js, the Browser, etc. When you write <code>const myArray = [];</code> The <code>Array</code> constructor is used to create that object.</p>
<p>In addition, both <code>Array</code> and <code>Array.prototype</code> provide a number of utilitarian methods for handling arrays including <code>Array.isArray()</code>; the ubiquitous methods <code>Array.prototype.map()</code> and <code>Array.prototype.filter()</code>; and a host of others.</p>
<p>However, <code>Array</code> is not an immutable (read-only) object because <em>there is no such thing</em> in Javascript. In fact, the JS <code>Array</code> function is just like any object in Javascript. It is <em>writable</em>. Herein lies the problem.</p>
<p>So, the perfectly legal, mutiple-assignment statement in Example 2 runs afoul of these JS "features". Here's what happens.</p>
<ol>
<li><p><code>thatArray.filter(...)</code> is called.</p>
</li>
<li><p>The result of the function call is stored in <code>Array&lt;Record&lt;string, any&gt;&gt;</code> which actually means <code>Array</code>.</p>
</li>
<li><p>The value stored in <code>Array</code> (i.e., now the value returned by the function) is stored in <code>thisArray</code>.</p>
</li>
</ol>
<p>The net result here is that the <code>Array</code> function has been obliterated (over-written) by the results of <code>thatArray.filter(...)</code>. In this case, that was just a POJO from an imported <code>.json</code> file.</p>
<p>The consequence is that, from this point forward, any JS code in this routine -- including code in packages -- that attempts to use <code>Array</code> in its official capacity will fail.</p>
<ul>
<li><p><code>const myArray = []</code> will fail because it attempts to call the <code>Array</code> function behind the scenes.</p>
</li>
<li><p><code>Array.isArray(myObj)</code> will throw <code>Array.isArray is not a function</code> because... well... it is no longer a function.</p>
</li>
<li><p><code>myArray.map((a) =&gt; ({ ...a, ...b})</code> will continue to work because these functions are on <code>Array.prototype</code> which is a <em>different</em> object than <code>Array</code> and any existing <code>Array</code> already has a reference to <code>Array.prototype</code> in it's own <code>.prototype</code> property.</p>
</li>
</ul>
<p>The truly heinous thing here is that the problem may not show up immediately. Until the program reaches a line of code that must create an array or check whether an object is an array, the devastation will be buried.</p>
<p>...and when the program runs headlong into this pit of devastation -- which it almost certainly will -- the error messages, though helpful, will be confusing. "How can Array.isArray <em>not</em> be a function? It's <em>always</em> a function..."</p>
<p>Well, until it's not. 😉</p>
<p>If this happens to you, go looking for something like Example 2 above in <em>your own code</em> -- not in the package that threw the error.</p>
<p>Your first instinct might be to search for this error message related to the package that threw it. I did... for several hours... which was both fruitless and frustrating.</p>
<p>Remember. The package that threw the error is an innocent victim. Your own code is the villain.</p>
]]></content:encoded></item><item><title><![CDATA[Advent of Code 2023. Go Figure.]]></title><description><![CDATA[2022 - History
In November of last year, my older daughter proposed that she, her brothers and I participate in Advent of Code (AoC). While I didn't know anything about AoC except what my daughter described, this sounded like it could be fun. Each of...]]></description><link>https://therickfactr.culpepperscorner.com/advent-of-code-2023-go-figure</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/advent-of-code-2023-go-figure</guid><category><![CDATA[adventofcode2023]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[family]]></category><category><![CDATA[coding]]></category><category><![CDATA[coding challenge]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Mon, 11 Dec 2023 11:47:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702375055811/d24cb02c-ebd9-4ce1-b255-2aec37a0572f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-2022-history">2022 - History</h3>
<p>In November of last year, my older daughter proposed that she, her brothers and I participate in <a target="_blank" href="https://adventofcode.com/">Advent of Code</a> (AoC). While I didn't know anything about AoC except what my daughter described, this sounded like it could be fun. Each of us is a professional software developer (engineer?) with a strong streak of curiosity and a competitive spirit.</p>
<p>If you aren't familiar with AoC, it is an annual software-development-focused, problem-solving competition that runs from Dec 1st to Dec 30th -- the season of Advent, hence the name.</p>
<p>During the competition, part one of that day's challenge is published on the AoC website at midnight EDT. Using any technology stack, development language, or computation tool, each competitor must solve the problem -- Part One and Part Two -- as quickly as possible. The description of the problem and <em>competitor-specific</em> input data are provided by AoC. The criteria for success is entering the answer -- always a single number -- into the AoC website page. When the correct solution to Part One has been entered, AoC provides Part Two of the problem which generally increases the complexity of the Part One problem.</p>
<p>Past solutions have been crafted in every imaginable development language with the possible exception of <a target="_blank" href="https://www.ibm.com/docs/en/gddm?topic=examples-system370-assembler-programming-example">IBM System 370 Assembler</a>. In 2022, the leaderboards for AoC were dominated by participants who used generative AI tools (e.g., ChatGPT). Every day, solutions were posted in under a minute, sometimes within seconds. The outcry from "legitimate" competitors was deafening. For 2023, the use of AI tools has been <strong><em>strongly</em></strong> discouraged, at least for the official competition. Yeah. RIght.</p>
<p>...but I digress. Back to the story</p>
<p>For my family, the 2022 challenges were fun for the first week or so. As the difficulty increased, the solutions became more time-consuming... much more time-consuming.</p>
<p>Since we all have real jobs that pay the bills and real lives, one by one each of us found it necessary to drop out. By the beginning of Week 3 (Day 15 or 16), we were done. I will only say that I was the last of our group to drop out... and that finishing AoC could have become a full-time pursuit by the end of the month! In the end, the only clear winner was AoC. It had beaten us! 😳</p>
<h3 id="heading-2023-thistory-this-story">2023 - Thistory ("this story" 😉)</h3>
<p>This year, my daughter and two sons opted out of AoC leaving me and my oldest son, <a target="_blank" href="https://github.com/marshall">Marshall</a>. Not surprisingly, we had the same idea. Rather than using AoC as an individual competition, we could collaborate on the problems and use AoC as an opportunity to learn (a) a new language and (b) spend more time <strong><em>together</em></strong>. We decided to ignore the "competition" element of AoC -- ignoring the leaderboard completely -- and to move at our own pace since our objectives were decidedly <strong><em>not</em></strong> competitive. After agreeing on this approach and after some discussion, we decided to use <a target="_blank" href="https://go.dev">Go</a> as our development language this year.</p>
<p>As of today, AoC 2023 has posted 11 daily challenges. We finished the first 4 days' challenges rather quickly, learning some fundamentals of Go coding. Day 5 was a decidedly bigger challenge. We decided to dive deeper into Go and take our time solving this problem. We definitely weren't after the fastest solution, but certainly one that provided the correct answer.</p>
<p>Over a period of 8 days -- off and on -- we wrote some pretty wicked Go code -- delving into objects, separating code into packages, playing with generics, writing go-routines that use channels, etc. Generally, we were shaking down Go based on our experience with literally dozens of other languages (e.g., C, C++, C#, COBOL, Fortran, JavaScript, Rust, LUA, et al).</p>
<p>Our solution to Day 5 was big... and slow 🐌. Part 1 only ran for a few seconds. Part Two ran for 40 minutes. This was <strong><em>after</em></strong> implementing go routines to get parallel processing and consuming 10 AMD Epyc CPUs (on a 24-CPU Linux host). This was the epitome of the "Brute Force" approach 🤣. Thankfully, the answer it produced was correct 😮‍💨.</p>
<h3 id="heading-go-hysteri-a">Go - Hysteri-a</h3>
<p>Now, for my thoughts on Go. Already, it's a love-hate relationship -- on many levels.</p>
<p>While Go syntax is more or less like other members of the C/C++/C#/Java/Javascript family, there are some departures. In general, it feels like Go does not provide the economy of expression of some other languages. Take, for example, another, more performant solution for AoC 2023 Day 5f, I mean that equivalent functionality in Go and, for example, Typescript</p>
<p>The syntax for defining objects, methods, and interfaces took some time to feel "normal". In particular, the lack of (a) function overloading, (b) optional function arguments, and (c) default argument values means many additional, uniquely named functions to cover the various signatures required in a library. If you are the library's author, that can be a lot of extra code to maintain. If you are the library's consumer, it can mean a confusing list of annoyingly similar but different method or function names to navigate.</p>
<p>Error handling in Go is also idiosyncratic. The idiomatic practice of a function returning a second value to report an <code>error</code> -- or just <code>ok</code> -- makes it all but impossible to chain function and/or method calls together in the style of so-called fluent APIs. This is touted as one of Go's strengths, but I find it somewhat annoying. It certainly creates more verbose code.</p>
<p>The highly opinionated Go toolchain also takes a bit of settling in. You just have to get used to the fact that your IDE with Go tools set up is going to reformat your code every time you save your code... and your code won't run if there's any kind of an error in syntax, usage, type-matching or whatever. You simply MUST fix these things.</p>
<p>On the other hand, the efficiency and speed of the GO toolchain and your compiled programs -- WOW! It's just amazing. Likewise, the small size of your compiled programs.</p>
<p>Finally, Go has been around a while (see the Wikipedia article in the footnotes) and the amount of information available from the official website, StackOverflow and other independent sources is pretty substantial. A Google search for a go-related issue generally turned up a solution in a minute or two.</p>
<h3 id="heading-conclusions-mastery">Conclusions - Mastery</h3>
<p>In the first 10 days, it is clear that we are already achieving our objectives for AoC 2023. We have learned a <strong><em>lot</em></strong> about Go, spent more time together, and committed to continuing our efforts on the AoC 2023 challenges into 2024, albeit at a more leisurely pace. We'll still be using Go to develop more proficiency, but we'll move forward at a more leisurely pace.</p>
<p>If you are a professional developer these days, knowing something about Go is, at the very least, helpful. For some, it's required knowledge. The good news is that, in a week or so, you can get a pretty solid foundation in Go and be off to the races.</p>
<h3 id="heading-links">Links</h3>
<ul>
<li><p><a target="_blank" href="https://github.com/nqzyx/advent-of-code/tree/main/2023/cmd/day05">Day 5 by Brute Force</a> - Our AoC 2023 Day 5 solution on GitHub</p>
</li>
<li><p><a target="_blank" href="https://adventofcode.com/">Advent of Code Website</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/marshall">Marshall on GitHub</a></p>
<ul>
<li><p>My oldest son</p>
</li>
<li><p>Space software entrepreneur extraordinaire</p>
</li>
</ul>
</li>
<li><p>Go language</p>
<ul>
<li><p><a target="_blank" href="https://go.dev">The official Go website</a></p>
</li>
<li><p><a target="_blank" href="https://en.wikipedia.org/wiki/Go_(programming_language)">Go Wikipedia article</a></p>
</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[On Novelty and Antiquity]]></title><description><![CDATA["[C. S. Lewis] showed me that newness is no virtue and oldness is no vice. Truth and beauty and goodness are not determined by when they exist. Nothing is inferior for being old, and nothing is valuable for being modern. This has freed me from the ty...]]></description><link>https://therickfactr.culpepperscorner.com/on-novelty-and-antiquity</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/on-novelty-and-antiquity</guid><category><![CDATA[isam]]></category><category><![CDATA[MongoDB]]></category><category><![CDATA[RDBMS]]></category><category><![CDATA[databasemanagement]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Tue, 28 Nov 2023 13:02:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1701177488121/43afc7ed-8fd0-4e7d-ae11-32a214d5e84f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>"[C. S. Lewis] showed me that newness is no virtue and oldness is no vice. Truth and beauty and goodness are not determined by when they exist. Nothing is inferior for being old, and nothing is valuable for being modern. This has freed me from the tyranny of novelty and opened for me the wisdom of the ages."</p>
<p>-- John Piper, How C. S. Lews Awakened John Piper to the "Realness" of Life, April 02, 2018.</p>
<p>**<sup>9</sup>**What exists now<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17325ah"><sup>ah</sup></a><sup>]</sup> is what will be,<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17325ai"><sup>ai</sup></a><sup>]</sup><br />and what has been done is what will be done;<br />there is nothing truly new on earth.<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17325aj"><sup>aj</sup></a><sup>]</sup><br /><strong><sup>10 </sup></strong>   Is there anything about which someone can say, “Look at this! It is new”?<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17326ak"><sup>ak</sup></a><sup>]</sup><br />It was already<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17326al"><sup>al</sup></a><sup>]</sup> done long ago,<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17326am"><sup>am</sup></a><sup>]</sup> before our time.<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17326an"><sup>an</sup></a><sup>]</sup><br /><strong><sup>11 </sup></strong>   No one remembers the former events,<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17327ao"><sup>ao</sup></a><sup>]</sup><br />nor will anyone remember<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17327ap"><sup>ap</sup></a><sup>]</sup> the events that are yet to happen;<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17327aq"><sup>aq</sup></a><sup>]</sup><br />they will not be remembered by the future generations.<sup>[</sup><a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET#fen-NET-17327ar"><sup>ar</sup></a><sup>]</sup></p>
<p>-- <a target="_blank" href="https://www.biblegateway.com/passage/?search=ecclesiastes+1&amp;version=NET">Ecclesiastes 1:9-11, New English Translation</a></p>
</blockquote>
<p>So, why am I quoting a renowned Christian author and the Old Testament here? Because, even in technology, in software development, there is nothing new under the sun. Let me explain...</p>
<p>In the last two years, I have been learning about MongoDB. Now, if you have any current knowledge of software development tools, you probably know <em>something</em> about MongoDB... unless you are a mainframe COBOL programmer with no intellectual curiosity whatsoever. ;) Of course, the most well-known fact about MongoDB is that it is a "NoSQL" database which is to say that it is decidedly <strong><em>not</em></strong> relational.</p>
<p>For many years before my introduction to MongoDB, I was a relational database junkie using on or the other RDBMS as the backing store for my applications. Over the years, I believe that I had become -- and still am -- a pretty darned decent relational database architect, designer and developer.</p>
<p>As I began to explore the world of MongoDB (my own personal "Oz"), many of the relational database tenets I have long held dear and perhaps even inviolate have caused twinges and cringes and gasps ("Oh, my!").</p>
<p>For example, joining a document (a row?) from one collection (a table?) with one or more documents in another collection is discouraged. Rather, one is encouraged to create sub-documents in one of the collections containing the document(s) from the other collection which thereby eliminates the need for a second collection.With joins greatly discouraged, it was no surprise to find that 3NF is not a thing, either.</p>
<p>"What is 3NF?", you say? You know... 3rd Normal Form... where "Every column is dependent on the key, the whole key and nothing but the key, so help me, Codd!" What? You never heard of that? Right. Anyway... 3NF is not a thing in the non-relational world. Well, actually, it <em>is</em> a thing but seemingly a <em>bad</em> or <em>undesirable</em> thing.</p>
<p>The more I learn about MongoDB, the more it starts to feel familiar... like... I've seen something similar to this before. This "knowing" continued to grow for a while and then, one day... click... whir... there it was! Indexed Files.</p>
<p>Do you remember <a target="_blank" href="https://en.wikipedia.org/wiki/Indexed_file">Indexed Files</a>? This was a "flat file" with indexes to directly access records in the file. There were variations of this theme on every operating system. IBM's mainframes had <a target="_blank" href="https://en.wikipedia.org/wiki/ISAM">ISAM</a> and <a target="_blank" href="https://www.ibm.com/docs/en/cics-ts/5.3?topic=files-vsam">VSAM</a> files; DEC's VMS, <a target="_blank" href="https://comp.os.vms.narkive.com/qfaFbq0J/vms-indexed-files-how-did-they-work">RMS Indexed files</a>; HP's MPE, KSAM files; MS-DOS, <a target="_blank" href="https://en.wikipedia.org/wiki/Btrieve">Btrieve</a> (3rd party)... the list goes on and on. Generally, these indexed file systems required one <em>unique</em> index for the records while supporting one or more additional indexes that might or might not be unique. However, the format of individual records was not required to be consistent.</p>
<p>Document databases are very similar. Sure, there is general support for JSON input and output and the fields in each document are named, but the concept of a document schema is very, very loose. Validation is generally provided by external code or logic (in apps or ORM/ODM definitions). Their forté is lightning-fast access to data -- perhaps multi-level documents.</p>
<p>Relational databases -- which provide similarly flexible indexing options -- provide a much stronger definition of the data and relationships being stored. Used properly, this ensures that an application cannot store inconsistent data in the database.</p>
<p>In the end, it seems to me that a document database sits somewhere between the archaic indexed file systems -- which left everything except the indexing up to the application -- and relational databases -- which provide highly evolved facilities for data validation and integrity.</p>
<p>To my way of thinking, there is not that much new about document databases. They are a mashup of indexing facilities and "roll-your-own" content with the server-side processing provided by most relational databases.</p>
<p>Getting back to my original point...</p>
<p>Relational databases -- old and antiquated though they may be -- are not necessarily "bad". In fact, a decent RDBMS provides validation, constraints and integrity that are meager to non-existent document databases (i.e., MongoDB)... unless you use a third-party library (e.g., Mongoose or MikroORM).</p>
<p>For that matter, indexed file systems though older than relational databases, are not necessarily "worse". For applications written in certain environments in legacy languages, they may be the best choice.</p>
<p>Likewise, a document-oriented (NoSQL) DBMS, though the newest of all, are not necessarily "better" or "best" for every circumstance. Certainly, though, there are many use cases where NoSQL reigns, particularly in Web-based apps.</p>
<p>Lastly, I am not here to argue that a good RDBMS (e.g., PostgreSQL, SQL Server, Oracle, etc.) is the "right" data store for every purpose. However, there are many line-of-business applications where a relational -- or object-relational -- data store provides data integrity features that are beyond compare.</p>
<p>When it comes to data storage, old and new technologies alike have strengths and weaknesses. Choose your platform(s) carefully.</p>
]]></content:encoded></item><item><title><![CDATA[Dev Retro 2022: What I learned in my 43rd year...]]></title><description><![CDATA[43 years ago, in 1979, I began writing software... professionally. I got paid $500 to write an inventory-management app in AppleSoft Basic on an Apple IIe with 64K of RAM and one 5.25" Floppy drive and a tiny CRT of a screen.
There was no database. I...]]></description><link>https://therickfactr.culpepperscorner.com/dev-retro-2022-what-i-learned-in-my-43rd-year</link><guid isPermaLink="true">https://therickfactr.culpepperscorner.com/dev-retro-2022-what-i-learned-in-my-43rd-year</guid><category><![CDATA[#oldgeezer]]></category><category><![CDATA[#icanstillwritesomeseriouscode]]></category><category><![CDATA[#DevRetro2022]]></category><category><![CDATA[Hashnode]]></category><dc:creator><![CDATA[The Rickfactr]]></dc:creator><pubDate>Thu, 29 Dec 2022 22:18:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702375212098/f0b164d9-6581-4bc9-b338-b8b70adc74ab.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>43 years ago, in 1979, I began writing software... professionally. I got paid $500 to write an inventory-management app in AppleSoft Basic on an Apple IIe with 64K of RAM and one 5.25" Floppy drive and a tiny CRT of a screen.</p>
<p>There was no database. I hand-crafted indexed file management routines. There was no GUI. Every prompt &amp; input was carefully placed on the 24x80 monochrome screen. There was no virtual memory. All of my code had to fit into 64KB or less.</p>
<p>In the years since 1979, I wrote code in more languages, accessed data in more data storage technologies, used more methodologies and sold to and consulted with more customers than I could possibly count. I even co-founded, managed and sold a consulting company. It's been a grand journey.</p>
<p>From 1997 to 2020, I made my living with Microsoft Development Tools and Technologies. Not so much out of preference as out of practicality. That's where the opportunities were for me as an engineer.</p>
<p>Up until 2020, I'd never used a document database. I looked down on Javascript development. "Can't we use a real OOP language?" Express and Node.js were just tools in the Javascript ecosystem that I had no interest in learning.</p>
<p>That all began to change in late 2020 when I joined a startup selling a DevOps platform that was built on the MERN stack. I joined as a pre-sales DevOps Engineer, but there was a healthy dose of consulting with customers to build solutions around the tool. In early 2021, a cash-flow crisis resulted in the departure of several members of the development team. I got asked to fill in. I never looked back.</p>
<p>In the 18 months since that time -- in the 43rd year of my software development career -- I have learned a bit about Javascript development, MongoDB, React, Node.js, AWS APIs and... well, a bunch of stuff I never thought I'd learn.</p>
<p>The message here is that, even after 43 years of software development, I am still learning. If you hang around for 43 years, I bet you'll still be learning, too.</p>
]]></content:encoded></item></channel></rss>