<?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[Aderayo Dev Notes]]></title><description><![CDATA[Technical writing on backend engineering, data-intensive systems, distributed applications, databases, APIs, and building reliable AI-enabled software.]]></description><link>https://blog.aderayoadelanwa.com</link><image><url>https://cdn.hashnode.com/uploads/logos/6a96addb74971ca68e6a6233/b5b6a6ad-2792-430a-8fa8-b73cb43be655.png</url><title>Aderayo Dev Notes</title><link>https://blog.aderayoadelanwa.com</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 10 Sep 2026 11:03:09 GMT</lastBuildDate><atom:link href="https://blog.aderayoadelanwa.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How I Refactored a Streamlit Prototype into a Modular Python Application]]></title><description><![CDATA[When I started building the Human Judgment Preservation Index (HJPI), the first proprietary methodology within Responsibility Lens, my priority was simple: make the idea work.
Responsibility Lens is a]]></description><link>https://blog.aderayoadelanwa.com/how-i-refactored-a-streamlit-prototype-into-a-modular-python-application</link><guid isPermaLink="true">https://blog.aderayoadelanwa.com/how-i-refactored-a-streamlit-prototype-into-a-modular-python-application</guid><category><![CDATA[Python]]></category><category><![CDATA[modularity]]></category><category><![CDATA[Applications]]></category><category><![CDATA[product]]></category><category><![CDATA[decision making]]></category><category><![CDATA[DesignStrategy]]></category><category><![CDATA[database]]></category><dc:creator><![CDATA[Aderayo Olamide Adelanwa]]></dc:creator><pubDate>Thu, 10 Sep 2026 09:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a96addb74971ca68e6a6233/888eab3e-1114-4714-a676-d0e3987f7c5b.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I started building the <strong>Human Judgment Preservation Index (HJPI)</strong>, the first proprietary methodology within <strong>Responsibility Lens</strong>, my priority was simple: make the idea work.</p>
<p>Responsibility Lens is a product I am building around <strong>decision responsibility</strong>. The <strong>Human Judgment Preservation Index (HJPI)</strong> focuses on how AI-assisted systems may affect human judgment, agency, responsibility, and meaningful oversight. The first working version was built with <strong>Python, Streamlit, and the logical rules behind the methodology</strong>.</p>
<p>Streamlit was useful at that stage because it allowed me to move quickly from an idea and methodology to something interactive. Users could respond to assessment questions, receive calculated results, view radar charts, and download results as CSV files. At this stage, the application did not yet have a database or API.</p>
<p>It worked. But as I continued learning, reviewing the project, and thinking about how Responsibility Lens might develop, one problem became increasingly obvious: <strong>too many parts of the application lived in the same place.</strong></p>
<p>The application worked, but the structure underneath it was becoming harder to reason about. That was when I decided to refactor it. The first version of Responsibility Lens grew naturally around the Streamlit interface. That meant the application gradually became responsible for several different things at once:</p>
<ol>
<li><p>rendering the user interface;</p>
</li>
<li><p>representing the HJPI methodology;</p>
</li>
<li><p>calculating scores;</p>
</li>
<li><p>storing configuration;</p>
</li>
<li><p>generating charts;</p>
</li>
<li><p>preparing exports;</p>
</li>
<li><p>displaying explanations and results.</p>
</li>
</ol>
<p>This convenience at one stage can become coupling at another and as  the application develops, it becomes harder to distinguish between <strong>what the product was doing</strong> and <strong>how Streamlit was displaying it</strong>.</p>
<p>For example, scoring logic should be concerned with a question such as: Given these assessment responses, what result should the methodology produce? It does not need to know which Streamlit component collected those responses. In the same way, the methodology should describe the dimensions, questions, options, and related information used by the assessment. It does not need to know how a particular page is arranged. These distinctions sound obvious when written down. They were much less obvious while I was focused on getting the first prototype to work.</p>
<h3></h3>
<p>Why I decided to refactor</p>
<p>Responsibility Lens is still using Streamlit, so the goal of the refactor was not to remove Streamlit. Instead, I started asking a different question: What happens if Responsibility Lens grows beyond this interface? That changed how I thought about the codebase. I identified below the four main reasons while I wanted to restructure the app.</p>
<ol>
<li><p>Maintainability: I wanted different responsibilities to have clearer places in the application. That makes basic development questions easier to answer: Where does this calculation happen? Where is the methodology defined? Where should I modify a chart? Where does export formatting belong? Which part of the application owns this behaviour? A clearer structure also reduces the amount of unrelated code I need to think about when making one change.</p>
</li>
<li><p>Testing: Another reason is that business logic embedded inside UI code is difficult to test independently. I wanted to be able to give a scoring function to a known set of inputs, run it directly, and inspect the result without starting Streamlit or manually clicking through the application.That meant the scoring logic needed to exist independently of the interface.</p>
</li>
<li><p>Reuse: Responsibility Lens may not always have only one interface. The underlying methodology may eventually need to support an API, another interface, reports, or other services. If the core logic depends directly on Streamlit, reusing that logic elsewhere becomes unnecessarily difficult.</p>
</li>
<li><p>Preparing for backend development: I am building Responsibility Lens progressively, so while Streamlit remains useful for the current stage of the project, I am also preparing the application for a more conventional backend architecture using technologies such as FastAPI and PostgreSQL. Because of that, modularity became more than a code-cleanliness exercise. It became part of preparing the project for its next stage.</p>
</li>
</ol>
<h3><strong>Moving toward a modular Python structure</strong></h3>
<p>With the above realization, the next step was to create a cleaner structure for the HJPI application. A simplified version looks like this:</p>
<p><code>hjpi/</code></p>
<p><code>├──</code> <a href="http://methodology.py"><code>methodology.py</code></a></p>
<p><code>├──</code> <a href="http://config.py"><code>config.py</code></a></p>
<p><code>├──</code> <a href="http://scoring.py"><code>scoring.py</code></a></p>
<p><code>├──</code> <a href="http://charts.py"><code>charts.py</code></a></p>
<p><code>└──</code> <a href="http://exports.py"><code>exports.py</code></a></p>
<p><code>hjpi_</code><a href="http://app.py"><code>app.py</code></a></p>
<p>Each module now has a clearer responsibility.</p>
<p><a href="http://methodology.py">methodology.py</a> contains the structures that describe the assessment methodology.</p>
<p><a href="http://config.py">config.py</a> contains configuration that should not be scattered throughout the application.</p>
<p><a href="http://scoring.py">scoring.py</a> contains the logic responsible for calculations.</p>
<p><a href="http://charts.py">charts.py</a> handles visualisation-related functionality.</p>
<p><a href="http://exports.py">exports.py</a> handles the generation of exportable results.</p>
<p>And hjpi_<a href="http://app.py">app.py</a> remains responsible for the Streamlit application itself.</p>
<p>This is not a complicated architecture. That is intentional. As I was not trying to introduce abstractions simply because I could. I wanted the structure of the code to reflect responsibilities that had already emerged naturally while building the product.</p>
<h2><strong>Separating business logic from Streamlit</strong></h2>
<p>One of the most important changes was separating <strong>business logic from interface logic</strong>.</p>
<p>Consider a simplified scoring example:</p>
<p><code>def calculate_score(responses, weights):</code></p>
<p>    <code>weighted_total = sum(</code></p>
<p>        <code>responses[key] * weights[key]</code></p>
<p>        <code>for key in responses</code></p>
<p>    <code>)</code></p>
<p>    <code>total_weight = sum(</code></p>
<p>        <code>weights[key]</code></p>
<p>        <code>for key in responses</code></p>
<p>    <code>)</code></p>
<p>    <code>return weighted_total / total_weight</code></p>
<p>This is only a simplified illustration. The actual HJPI methodology contains its own domain-specific rules. What matters here is the architectural principle. The function does not import Streamlit. It does not display a message. It does not create a chart. It does not need to know whether the responses came from a radio button, an API request, a database record, or a test. It receives data, performs a calculation, and returns a result.</p>
<p>The Streamlit application can then use that result:</p>
<p><code>score = calculate_score(responses, weights)</code></p>
<p><code>st.metric(</code></p>
<p>    <code>label="Assessment Score",</code></p>
<p>    <code>value=score</code></p>
<p><code>)</code></p>
<p>This creates a clearer boundary of moving from interface through to application logic and then result. That separation gives the scoring logic a life outside Streamlit. If I later expose parts of the assessment through FastAPI, the underlying logic should not need to be rewritten simply because the interface has changed. That was one of the most important conceptual shifts in the refactor.</p>
<h2><strong>Making the methodology data-driven</strong></h2>
<p>Another area I reconsidered was how the methodology itself was represented.</p>
<p>HJPI contains structured domain information. As the methodology develops, I do not want every new or revised dimension, question, or description to require another manually written block of interface code. As Responsibility Lens develops, some of the areas I want tests around include:</p>
<ul>
<li><p>expected scoring behaviour;</p>
</li>
<li><p>boundary conditions;</p>
</li>
<li><p>missing or invalid inputs;</p>
</li>
<li><p>methodology configuration;</p>
</li>
<li><p>calculations used in results;</p>
</li>
<li><p>transformations used for exports.</p>
</li>
</ul>
<p>The refactor does not automatically make the application reliable. What it does is make reliability easier to build. <strong>The refactor changed how I understood the project.</strong> One thing I did not expect was how much restructuring the code would change the way I thought about Responsibility Lens itself. Initially, I largely thought of what I had built as a Streamlit application. After refactoring, I could see the different parts of the system more clearly:<code>   </code></p>
<p><code>Responsibility Lens</code></p>
<p>        <code>│</code></p>
<p>        <code>├── Methodology</code></p>
<p>        <code>│</code></p>
<p>        <code>├── Domain logic</code></p>
<p>        <code>│</code></p>
<p>        <code>├── Application logic</code></p>
<p>        <code>│</code></p>
<p>        <code>├── Presentation</code></p>
<p>        <code>│</code></p>
<p>        <code>├── Reporting</code></p>
<p>        <code>│</code></p>
<p>        <code>└── Infrastructure</code></p>
<p>That distinction gave the project more meaning for me. Responsibility Lens became less like <strong>a Streamlit app</strong> and more like <strong>a system whose current interface happens to be Streamlit</strong>. That is an important difference. Streamlit is one way of interacting with the system. It does not have to define the system itself. And that has influenced how I am thinking about the next stages of the project. <strong>What I learned from the refactor</strong> The biggest lesson was not that every prototype needs an elaborate architecture from the beginning. I still think there is value in building the first version quickly enough to understand the problem. But once different responsibilities begin to emerge, it becomes important to recognise them. I learned that scoring logic should be able to exist without the interface.</p>
<p>In essence, the refactor helped me begin answering another: <strong>How should I structure this application if I want to continue building it?</strong> Responsibility Lens is still developing, and so is my understanding of backend engineering. But moving the HJPI application from a tightly coupled Streamlit prototype toward a more modular Python structure was an important step. I started with something that worked. Now I am learning how to build something that can continue to evolve.</p>
]]></content:encoded></item><item><title><![CDATA[Starting a Second Career in Backend Engineering]]></title><description><![CDATA[About eight or nine months ago, I began taking my goal of moving into technology more seriously after years of peripheral training. I started with Python, and as I became more comfortable with program]]></description><link>https://blog.aderayoadelanwa.com/starting-a-second-career-in-backend-engineering</link><guid isPermaLink="true">https://blog.aderayoadelanwa.com/starting-a-second-career-in-backend-engineering</guid><category><![CDATA[Philosophy]]></category><category><![CDATA[technology]]></category><category><![CDATA[Technical writing ]]></category><category><![CDATA[Python]]></category><category><![CDATA[backend developments]]></category><dc:creator><![CDATA[Aderayo Olamide Adelanwa]]></dc:creator><pubDate>Wed, 09 Sep 2026 23:24:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6a96addb74971ca68e6a6233/a497ffd3-6607-4699-90cc-72bcf5cfbd02.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>About eight or nine months ago, I began taking my goal of moving into technology more seriously after years of peripheral training. I started with Python, and as I became more comfortable with programming, my interests gradually became clearer. I found myself increasingly drawn to backend engineering, databases, data systems, and the infrastructure that makes applications work beyond what users see on the screen. Due to the fact that I had this as the beginning of a second career for me, I approached the process with a strong desire to understand what I was doing rather than simply move quickly through a list of technologies.</p>
<p>At first, most of my attention was focused on learning. I studied Python syntax, functions, classes, modules, data structures, error handling, APIs, relational databases, frameworks, database concepts, and some foundations in data engineering and artificial intelligence. I worked through tutorials, documentation, exercises, and small projects. The more I learned, however, the more aware I became of what I did not know. Every new concept seemed to reveal three more areas that I needed to understand. That awareness was useful because it helped me identify my weaknesses, but it also created a feeling that I needed to learn much more before I was ready to build anything substantial.</p>
<p>For a while, I thought this was the responsible way to learn. I believed that if I studied enough, I would eventually reach a point where I would feel prepared to build confidently. What I gradually realised was that such a point might never arrive. There would always be another concept to understand, another course to complete, another library to explore, another framework to learn, or another project I could watch someone else build before attempting my own. I could continue preparing indefinitely and still feel like a beginner.</p>
<p>That realisation changed the way I approached learning. At some point, I had to stop treating learning as something that happened before building and allow building to become part of the learning process itself. Instead of waiting until I understood everything I thought I needed to know, I began working on projects that forced me to confront the gaps in my knowledge directly. That shift has probably been one of the most important lessons of the past eight months. I am still early in backend engineering and data systems, and there is a great deal that I do not yet know, but building has changed what I think it means to learn software engineering. </p>
<p>A programming language gives you tools, but backend engineering forces you to think about how those tools should be organised into a system. My questions gradually moved beyond whether a piece of Python code was syntactically correct. I started thinking about where application logic should live, how data should move through an application, what information belonged in a database, what an API should expose, where validation should happen, how failures should be handled, and how different parts of an application should depend on one another. I also started thinking about whether important behaviour could be tested independently and what would happen to the structure of an application as it became larger.</p>
<p>These questions made software engineering feel much bigger than writing code that worked. I began to understand that the challenge was not simply producing the expected output. It was also deciding how responsibilities should be separated, how data should be represented, and how a system could remain understandable as it changed. Concepts such as architecture, modularity, testing, and separation of concerns began to feel less like abstract terminology and more like practical responses to problems that appear when software grows.</p>
<p><strong>Bringing My Previous Work Into Engineering</strong></p>
<p>Backend engineering is a second career for me, but I am not beginning it without another intellectual life behind me. My background in philosophy and research continues to influence the way I approach technical work. I naturally ask questions about concepts, assumptions, judgment, responsibility, evidence, and why one decision follows from another. Increasingly, I see those habits appearing in how I think about software systems.</p>
<p>Software development involves judgment constantly. Why should a particular responsibility live in one part of the application rather than another? Why should data be modelled in one way rather than another? What assumptions does a system make about its users? What happens when it fails? Which decisions should be automated, and which should remain meaningfully under human control? These questions are part of the thinking behind Responsibility Lens, but they are also becoming part of how I approach technology more generally. I am learning how systems work technically while continuing to think about the human decisions surrounding them. I do not yet know exactly where those paths will eventually meet, but that intersection is one of the areas I hope to explore through Aderayo Dev Notes.</p>
]]></content:encoded></item></channel></rss>