This post hypothesizes a path from ideation to assessment of candidate use-cases for AI-enabled systems, along with techniques for assessing behavior of systems in relation to prompts. Throughout, we’ll consider building a customer inquiry chatbot for a music equipment supplier. By the end, we’ll have explored prompt engineering and techniques for evaluating the ability of an AI system to meet a target use-case.
I assume the reader has experienced AI to some degree, even if only casually via systems like ChatGPT or Google Gemini.
large language models
AI
artificial intelligence
LLM
LLMs
A colleague of mine is currently trying to study and learn Design Patterns. For the
uninitiated, the term Design Pattern often refers to a set of well-known patterns
used to solve problems that often present themselves in software. The primary work
was originally written by Gamma et. al in Design Patterns: Elements of Reusable Object-Oriented Software.
My colleague was reading an article on the internet on the Strategy Pattern,
and voiced frustration at how contrived the examples were in the article, and how this
seems to be a recurring pattern (no pun intended) when we create content around Design Patterns for
one another.
This post is my attempt to clarify information about the Strategy Pattern for my colleague,
and my hope is that this effort will benefit a large audience of developers experiencing the
same frustrations. Let’s get started.
I recently decided to pick up a copy of the book Designing Data-Intensive Applications by Martin
Kleppmann. I work on a Manufacturing Execution System (MES) that is responsible for collecting data
across several disparate sources, replicating it to long-term durable storage as well as short-term
durable message queues, and finally, processing some subset of that data as close to real time as we
can get. I’ve seen this book referenced a number of times when discussing system design (and
specifically, preparing for system design interviews), and decided to pick it up to continue my own
learning. This post outlines some of my background and experience, a sample of a problem of the sort
my team would solve in our system, and a brief overview of the first chapter in the book.
I’ve been a software developer for nearly ten years now. I’ve read comments
in nearly every language and code-base I’ve worked in, and written them in
most. Over time, my opinion has shifted quite a bit on what makes a comment
useful. This post is a reflection on that collective experience, and I hope
will influence you in the comments you write.
I recently purchased a new computer for home use. My old Surface Pro 3 with 4GB
of RAM was just not cutting it for the sorts of things I would like to do on a
home computer, and while it’s great for many use-cases, the form factor isn’t
ideal in every scenario. One of my primary uses of that computer was for
writing this blog, and I haven’t had a need to touch the tool-chain in almost 3
years. Sadly, when I tried to get it all setup again on my new computer, I was
met with very prompt failure, but alas, was able to resolve it with the help of
a fellow blogger using Jekyll,
Dave Mateer’s blog post on ‘Running Jekyll on WSL2’. Following the
steps he outlined in that post, I was able to get up and running again very
quickly.
I recently shipped a service that simplifies the implementation of
custom business rules for a lot of my applications. This post talks
about the original problem I had, some instances of similar solutions,
in other applications, and how I created a more general solution that
can be leveraged in most of my applications.
I recently ran into an issue using HttpClient in ASP.NET Core and the built-in
Dependency Injection system. This post aims to highlight what I found, what I
believe the issue was, and how I was able to get my app working again.
My team has started adopting feature flags recently. I wanted to take some time
to discuss what feature flags are, some best practices my team has discovered
along the way, enumerate some of the situations where using feature flags might
make sense for your team, and give some tips on how to get started.
I was working on a PowerShell script this afternoon, and found that I was passing the same
parameters over and over again. As a developer, I’d normally just wrap calls to the desired
function, and handle any necessary abstraction in my wrapper function for common parameters,
but PowerShell has this wonderful language feature called Splatting that
is really well suited to solving this problem in a really concise way. I also decided I wanted
to lift some of this wonderful goodness to a JSON configuration file, because that enables some
other really interesting scenarios. Let’s dig in!
I think Git may reasonably be my favorite piece of software ever
written. I love the C# Programming Language, and I’m a huge fan
of TypeScript. Visual Studio is pretty cool, and so is Azure, but at
the center of nearly all the development work I do (including this blog), I use
Git. It’s simply amazing. I’ve spent a ton of time deconstructing my own commit
history, ranging from the most simple, linear commit graphs, to graphs
including several merges (particularly, multiple merges on experimental
development branches). This post explores some of the features that I feel are
most pertinent to understanding and using Git.
I’m a huge fan of command-line utilities (aka, console apps). In general, I
find console apps to have much lower barriers to use than traditional
window-based systems: in many respects, they’re much easier to build than other
alternatives (such as Windows Forms and Windows Presentation Foundation apps),
with generally lower barriers to entry. That said, I hate writing argument
parsers. It’s not that it’s super-difficult, but it’s tedious, and for such a
common task, I’d really like to use a library. I’m aware of a few, and found
what is easily my favorite recently, CommandLineParser. In this
post, I’ll explore what my preferences are, and why I’ve recently selected this
one as the default when starting new .NET projects. I’ll also explore how I go
about selecting new dependencies for projects that I’m working on.
Have you ever been nervous about making a change to an application, or
interested in benchmarking your code in order to demonstrate the efficacy of
a proposed change? I recently wanted to change the behavior of a core piece of
application code, but wanted to be sure that it was going to be an improvement
to the system, beyond simplifying the mental model for the code. To justify my
changes, I spent time measuring them, using a tool called
BenchmarkDotNet.
I recently started working on improving some code I wrote in college, and
like many software projects, hit a wall in trying to improve the thing I
originally set out to do. This post talks about the struggle, and the
struggle is real.
I’ve been working as a technology professional for a little while now. For a
long time, I chased the stick of “this or that tool,” and held this notion that
the “next thing” would somehow “fix” whatever problem I was trying to solve
(real or perceived). Over time, my perspective has changed quite a bit. This
post outlines my current thinking, and describes a model I’ve come to refer to
as “People, Process, Tools.”
I recently did a whole bunch of work with trying to automate ClickOnce project
builds. While I was unfortunately unsuccessful in achieving that goal, I did
learn a ton about MSBuild, and had what I felt was a great idea about how
those of us that use SQL Server projects in Visual Studio can manage our
application’s reference data. This post shows you how.
In the previous post, [Reviewing C# foreach, Part 1]({% post_url 2019-01-22-Reviewing-foreach-Pt1 %}),
we looked at how the C# compiler transforms our foreach loops over the
IEnumerable<T> interface into something the runtime understands. In this post,
we’ll look at what code the compiler emits when an object is statically known to
be an array.
If you’re a C# developer, you probably use the foreach language
keyword all the time. I love this keyword, because it drastically simplifies a
lot of the boilerplate we’d otherwise have to write ourselves. It makes
consuming Iterators very easy, and aligns the programming
language very closely to natural language constructs. With that said, have you
ever looked at the code that gets generated by the C# compiler? That’s the
topic of this post, so let’s dig in!
Do you ever program in TypeScript? Do you use the Promise
API? Have you ever used the new async/await functions in
TypeScript (or JavaScript) with inner-asynchronous request code? And have you
ever wondered how you can achieve similar results using RxJS? In this
post, we’ll explore how to take advantage of RxJS operators as part of an
asynchronous workflow, and how to reduce the complexity of having inner
subscriptions.
The Observable API is extraordinarily useful for
asynchronous programming. It enables us to decouple data sources from
data processing targets, create sophisticated processing pipelines, and create
deterministic sequences. In RxJS, there are also a number of
functions for creating Observable instances. This post will give you a brief
overview of the history of the Reactive Extensions (RX), as well as
an introduction to one of my favorite RX operators,
fromEventPattern.
I recently faced an issue at work with identifying when a critical
initialization API stopped being called in one of our applications. This post
outlines how I used the Git log to identify the offending commit,
and explores some other ideas I have about software architecture, managing
work, and collaborating with others.
I spent quite a bit of effort trying to get this blog from idea to running.
For a long time (around twelve months), I’ve had ideas about how I wanted to
store, version, and deploy my blog. Thist post will take you through what I
finally settled on.
As developers, we’re encouraged to write testable code, but what does that
actually mean? What makes our code testable? To answer this question, let’s
take a step back and assess the basic function of any useful computer
program.
I’ve been working as a developer for a modest three years. Throughout the
learning process, and my short time as a professional, I’ve faced the same
challenges that I believe most people face in the transition from hobbyist or
student to professional. This blog is my way of contributing to the developer
community as a whole. It is, in principle, a coding blog, but I may
occassionally take time to explore other things, such as books, podcasts,
and other resources that I’ve found useful.