About me
I'm a web developer focused on building and maintaining websites, applications, and integrations with Python, Django, and Wagtail.
My work ranges from public-facing websites and content management systems to custom applications that connect Salesforce, learning platforms, payment systems, and other services. I also work with the infrastructure around those applications: deployment, databases, cloud storage, security, accessibility, testing, documentation, monitoring, and long-term maintenance.
That breadth is intentional. I enjoy writing application code, but I'm equally interested in what happens before and after the code is written: understanding the problem, choosing an appropriate architecture, making the system usable for the people who maintain it, getting changes safely into production, and keeping everything working as requirements and technology change.
Most of the applications I work on are not short-lived projects. They become systems that people depend on and that need to continue evolving for years. That has shaped how I think about development.
I try to avoid two common extremes: building elaborate solutions for hypothetical future requirements and making short-term decisions that unnecessarily limit reasonable future changes.
Flexibility does not require abstraction everywhere. Conventional frameworks, clear boundaries between components, and well-defined interfaces often provide more useful flexibility than attempting to design a generalized solution for every possible future requirement.
My preference is to solve the problem that exists today while leaving practical paths for tomorrow. If an application does not need background workers, a dedicated search service, or another piece of infrastructure, I don't think a client should pay to build and operate one simply because it might someday be useful.
At the same time, today's expedient solution should not unnecessarily paint the application into a corner. New capabilities should be able to be introduced when there is a demonstrated need for them without automatically requiring the existing investment to be discarded.
And when an earlier decision no longer fits, the fact that time or money has already been invested in it should not make that decision permanent. Requirements change. Technology changes. Good systems - and the people maintaining them - need to be able to change too.
Good design matters. It establishes hierarchy, improves usability, supports accessibility, and makes information easier to understand. But design cannot compensate for content that is unclear, inaccurate, outdated, or simply not useful.
I sometimes describe this by saying that good content can survive a poor design, but good design cannot save poor content.
That means some of the most important questions on a website project have little to do with colors or layouts. What are people coming here to find? Can they find it? Is the information understandable? Who is responsible for keeping it accurate? Will maintaining it require someone to update the same information in three different places?
Design should support the answers to those questions rather than distract from them.
The same principle affects how I build content management systems. Content managers should be able to concentrate on creating, organizing, and maintaining information without needing to understand the technical details of HTML, responsive layouts, or accessibility.
I try to give content managers meaningful control over their content while allowing the application to take responsibility for how that content is presented.
Or, put somewhat less formally: don't make content managers solve developer problems.
Accessibility is most effective when it is part of ordinary design and development rather than a compliance exercise performed at the end of a project.
I generally work toward WCAG 2.2 AA as a baseline, considering semantic structure, keyboard interaction, focus behavior, color and contrast, responsive layouts, image alternatives, forms, and content-management decisions while components are being built.
Automated testing and accessibility scanning are useful safeguards, but they do not replace thoughtful implementation or manual review. Content management matters as well: a website that is accessible when it launches can gradually become less accessible if the CMS makes it easy to introduce structural problems later.
The objective is therefore not simply to make an accessible website. It is to build a system that makes keeping the website accessible easier.
I enjoy automation, but the ability to automate something is not by itself a reason to do it.
Automation is most valuable when a process needs to happen consistently, is repetitive, is easy to forget, or is particularly susceptible to human error. Database backups, automated testing, data synchronization, broken-link auditing, accessibility scanning, and operational checks are good examples.
A useful automation also needs to be observable. If a scheduled process fails silently for six months, automating it may have created more confidence than reliability. Important failures should be logged and, where appropriate, brought to someone's attention.
My general rule is to automate obligations, not possibilities. Automation should remove unnecessary toil without removing accountability for the result.
Software rarely remains the exclusive responsibility of the people who originally built it.
Applications eventually need to be understood, maintained, and extended by developers, content managers, administrators, and other people who were not part of the original design process. That possibility influences how I structure code, design administrative interfaces, document systems, and choose technologies.
I tend to favor established conventions and understandable architecture over clever solutions that require specialized knowledge to maintain. Where a system is complicated because the problem itself is complicated, documentation becomes particularly important.
I use Sphinx to maintain extensive technical documentation for the applications I manage, covering areas such as architecture, configuration, development and deployment, integrations, scheduled processes, data flows, administrative tools, and troubleshooting. Content managers and other users receive documentation appropriate to the parts of the system they actually operate.
Code can tell the next developer a great deal about what an application does. It is much less effective at explaining why a decision was made, what external assumptions it depends on, or what someone should investigate when something stops working.
A system should not depend on institutional knowledge held only by the person who happened to build it.
I don't consider an application finished when it works on my computer.
Source control, automated testing, pull requests, Review Apps, staging environments, backups, logging, security, monitoring, deployment, and recovery are all part of delivering software that other people can depend on.
The same is true after launch. Frameworks need updating. APIs change. Credentials expire. Databases need upgrading. External services fail. Content evolves. Requirements that seemed permanent turn out not to be.
Robust software isn't software that never experiences a problem. It is software designed so that problems are visible, understandable, and recoverable.
That operational responsibility is part of application development, not somebody else's problem once the code reaches production.
I like technology, and I enjoy experimenting with new tools. But the objective of a project is not to use as much technology as possible.
Sometimes the right solution is a custom application. Sometimes it is a small extension to an existing one. Sometimes a managed service is worth paying for because it eliminates substantial operational work. And sometimes the right answer is simply a scheduled task and a PostgreSQL table.
I try to choose technology according to the problem, the people who will maintain the system, and the value the additional complexity provides.
The result I am looking for is not the most impressive architecture diagram. It is software that solves the problem, can be understood, can be changed, and can continue doing its job long after the initial project is complete.