Category: professional

  • Craft, Curiosity, and Code: My Approach to Software Engineering

    Craft, Curiosity, and Code: My Approach to Software Engineering

    How I Approach Software Engineering

    As a software engineer, my role goes far beyond writing code that compiles. Real engineering is about solving meaningful problems, communicating clearly, and understanding the broader impact of technical decisions. That includes how code behaves, how users experience it, and how it fits into the product’s long-term goals.

    This post is not a résumé or a list of frameworks. It’s a reflection of the habits, principles, and mindset that guide how I work—regardless of the tech stack.

    Strong Foundations That Go Beyond Any Framework

    Some of the most valuable skills I’ve learned aren’t tied to one language or library. Clean code, separation of concerns, testable design, and clear thinking apply whether you’re building in Angular, React, or a backend service. When you understand the patterns and ideas behind the tools, it becomes easier to adapt, improve, and contribute across environments.

    Frontend Expertise (Angular and Beyond)

    I’ve worked extensively with Angular, including modern techniques like Signals and Standalone Components. My focus is on building modular, maintainable applications with clear structure and strong reusability.

    I’ve also designed systems with complex asynchronous flows using RxJS, Angular signals, and service-based facades. On projects with real-time requirements, I’ve integrated SignalR to manage multiple live data streams. These implementations typically involve synchronising authentication, API states, and socket connections to ensure components only render when the right data is available.

    Although Angular is my primary frontend tool, my deeper value lies in understanding where complexity lives and how to manage it. I focus on making that complexity predictable and easy for teams to work with.

    Testing and Code Quality

    I treat testing as a core part of development, not a separate phase. Whether using Jasmine, Jest, or writing code with testability in mind, I aim to bake quality into every layer.

    I structure components to be as lean and “dumb” as possible, using input and output bindings to keep them focused on presentation. This design makes components easier to test, easier to reuse, and easier to showcase in tools like Storybook.

    I consistently include data-testid attributes as part of my markup, not as an afterthought. These allow developers to write robust unit tests and enable QA teams to create automated scripts without chasing DOM changes. For me, writing test-friendly code means thinking about the entire lifecycle of the feature—from implementation through to testing and maintenance.

    Clean Code and Clear Thinking

    I prioritise readability over cleverness. I write small, purposeful functions, use clear naming, and separate concerns to keep complexity under control. Where appropriate, I introduce wrappers or facades early to reduce future refactor pain and keep teams focused on business logic, not boilerplate.

    The goal isn’t to write perfect code. It’s to write code that’s easy to understand for my future self, my teammates, and the business that depends on it.

    Practical, Delivery-Focused Approach

    I have strong experience delivering MVPs, scoping features, and shipping under real-world constraints. That includes:

    Collaborating with product teams to define realistic outcomes

    Delivering in small, testable increments

    Communicating technical trade-offs without jargon

    Using CI/CD pipelines, code reviews, and static analysis tools as daily habits

    I don’t just implement tickets. I solve problems with attention to quality, context, and end-user value.

    Curiosity That Drives Consistency

    Books That Shape My Thinking

    I read regularly across topics like psychology, marketing, and personal development. Books like Thinking, Fast and Slow, Atomic Habits, The Psychology of Money, and The Mom Test influence how I think about user experience, product decisions, and clear communication.

    Staying Current with the Tech Landscape

    I follow engineering blogs, changelogs, and newsletters to stay up to date without chasing trends for their own sake. I stay aware of what’s evolving—framework updates, architectural shifts, tooling improvements—and choose what to adopt with intention.

    Using AI with Intention

    AI is part of how I work, but never a replacement for real engineering judgment. I use tools like ChatGPT and x.ai to explore ideas, compare strategies, and generate variations, especially when brainstorming or drafting. I take time to test outputs, question assumptions, and validate anything that feels uncertain.

    I also design prompts to avoid echo chambers and reduce bias. For topics where AI has limitations, I follow up with practical research. AI supports my thinking—it doesn’t make decisions for me.

    What I’m Not

    Knowing what you don’t do is just as valuable as knowing what you do.

    • I’m not a trend chaser. I adopt tools when they solve problems, not because they’re new.
    • I’m not a “rockstar” developer. I favour collaboration, clarity, and consistency over complexity or bravado.
    • I’m not tied to Angular. It’s where I’ve built deep experience, but my core practices apply across frameworks.
    • I don’t just complete tasks. I think about what happens next—how it’s tested, maintained, and evolved over time.

    Conclusion: Building With Intention

    Whether I’m writing code, reviewing work, or collaborating with product teams, I bring a thoughtful, disciplined approach. I aim to write software that is not only functional, but dependable, understandable, and ready to scale.

    I’m always learning and always looking for ways to improve. If you’re building something and this approach resonates with you, feel free to reach out.

  • Building Well, Even When Moving Fast

    Building Well, Even When Moving Fast

    Introduction

    In many of the projects I’ve worked on, especially greenfield builds or early-stage MVPs, there’s often a clear need to move quickly. Teams are trying to validate an idea, meet a funding milestone, or get something usable in front of people as soon as possible. Speed becomes the focus, and that makes sense.

    Over time, though, I’ve found that working fast doesn’t have to mean ignoring structure or skipping the basics. There’s a way to keep things light while still building with care. A few small habits, used thoughtfully, can actually make the work smoother and more adaptable.

    This isn’t about adding unnecessary complexity or slowing things down. It’s about laying just enough groundwork to avoid getting stuck later. Whether it’s writing simple tests, organising logic cleanly, or naming things in a way that helps the next person understand what’s going on, these small choices can make a big difference over time.

    The habits I tend to rely on—like clean code, functional patterns, facades, and clear data boundaries—are tools that help me stay focused and reduce friction, even when timelines are tight. I’ve found them helpful not because they’re perfect, but because they give projects a better chance to evolve without becoming hard to work with.

    Sections

    A Professional Mindset

    Approachable Code

    I try to approach software development with a sense of care rather than complexity. That means thinking not just about whether something works today, but how easily it can be understood, maintained, or adapted in the future. I am not aiming to make the code impressive. I am aiming to make it approachable.

    Early Discipline

    In fast-moving environments, it can be tempting to skip structure in order to deliver quickly. But I have found that a small amount of discipline early on can save a lot of time later. Simple habits like separating responsibilities, choosing clear names, or writing a basic test can make a project easier to work with without getting in the way of progress.

    More than One Right Way

    The approach I follow has come from experience. It is shaped by working on different types of teams and projects, and by making plenty of mistakes along the way. I do not believe there is one right way to build software, and I do not follow patterns just for the sake of it. Instead, I try to use what I have seen work in practice.

    Keep Things Steady

    The goal is not to slow things down or aim for perfection. It is to keep things steady enough that we can move quickly without losing confidence in what we are building.

    Core Practices You Use

    Over time, I’ve developed a handful of habits that help me write code that’s not just functional, but maintainable and flexible. These are simple practices that can quietly support a project’s long-term health, even when time is tight.

    Unit Testing

    I write unit tests to catch regressions early and give myself the confidence to change things without breaking them. Even a small set of targeted tests can help confirm that the core behaviour of a feature remains consistent, especially when requirements evolve. Testing also helps me work with fewer unknowns, which in turn speeds things up.

    Snapshot Testing

    I use snapshot tests to quickly detect unexpected changes in output, especially in UI components or serialised data. They’re useful for locking down the shape of something and getting fast feedback when it shifts. I treat snapshots as a lightweight safety net, not a replacement for more targeted tests.

    Functional Coding

    Where it makes sense, I lean toward functional patterns. Pure functions, immutability, and predictable data flow help reduce unintended side effects and make logic easier to understand. This can be especially helpful in teams, where clarity matters as much as correctness.

    Facade Services

    I often introduce facade services early, even in smaller projects. They create a clean boundary between parts of the application and help isolate complexity. This separation makes it easier to refactor, mock, or swap out implementations later without touching the rest of the codebase.

    DTOs (Data Transfer Objects)

    I use DTOs to define and control the shape of data passed between layers or components. This adds a layer of clarity and safety, especially when dealing with external APIs or shared contracts. It also helps prevent accidental coupling between unrelated parts of a system.

    Clean Code

    I try to write code that someone else (or future me) can easily read and reason about. That means keeping things small, naming things clearly, removing duplication where possible, and choosing simplicity over cleverness. Clean code does not have to be perfect, just understandable and practical.

    Collaborative Practices and Task Refinement

    I value practices like backlog refinement, shared understanding of work, and space for open technical discussion. Taking time to define and discuss tasks clearly helps avoid confusion and misalignment. In my experience, this upfront effort pays off by reducing churn later in the process.

    Why These Matter Early

    When working on an MVP or a greenfield build, the natural instinct is to move quickly and keep things simple. That’s a good instinct. The challenge is knowing which shortcuts are safe to take, and which ones might become costly later on.

    In my experience, applying a bit of structure and discipline early on can make a big difference. It does not need to slow things down. In fact, it often speeds things up in the long run. A few well-placed tests, a clear service boundary, or a cleanly named DTO can save hours of confusion later. These small choices help keep the code understandable, predictable, and easier to adapt when the direction inevitably shifts.

    Tech debt is not always about poor decisions. Sometimes it comes from good decisions made in a hurry, without enough information. That is why I try to build in a way that keeps options open. When something changes, whether it’s a new requirement, a different data shape, or another developer joining the project, I want the code to be in a state where we can respond with confidence.

    Starting with habits like clean code, tests, and separation of concerns also makes it easier to scale the team. New developers can understand what is happening faster, contribute sooner, and make changes without fear of breaking things.

    In the early stages of a project, things move fast. But if the foundations are steady, the pace is easier to sustain. That’s why I try to apply these practices from the beginning, even when the goal is to ship quickly.

    Closing Thoughts

    I have found that successful projects rarely hinge on adopting every practice under the sun. Instead, they benefit from doing a few key things consistently and doing them well. For me, that means writing clear code, adding the tests that matter, and keeping boundaries tidy. These habits are small enough to fit inside an ambitious timeline yet strong enough to keep the foundations steady.

    None of this came from following a rulebook word for word. It grew out of years spent on different teams, learning what helps and what hinders when the pressure is on. Each project taught its own lessons about balancing speed with quality, and these practices are simply the ones that have proven useful again and again.

    Your context may be different, and that is perfectly fine. The important part is to stay thoughtful. Choose the habits that ease your path rather than weigh it down, and keep an eye on how today’s shortcuts might feel six months from now. Build with care, even when you need to build quickly, and the next stage of the project will thank you for it.

  • How I Like to Work

    How I Like to Work

    For any team I join, these practices are a baseline. They are not extras or advanced techniques. They are the minimum I bring to help ensure the work stays maintainable, testable, and adaptable.

    If your team already uses practices like clean code, testing, clear data structures, and thoughtful boundaries, that is great to see. We are already aligned, and I would love the chance to contribute.

    If these habits are not yet part of your process, that is not a problem, as long as there is a clear commitment to head in that direction. I am not looking for perfection. What matters most is a shared mindset and a willingness to improve together.

    If that sounds like a good fit, I would be glad to connect.

    Why I’m Sharing This

    Over the years, I’ve worked on a range of teams, across different industries and project styles. Some of those teams were a great fit. Others, less so. With time, I’ve learned to pay attention to what makes a good working environment for me, and where I can genuinely contribute my best.

    I try to approach my work as a professional. That means being reliable, thoughtful, and holding myself to a consistent standard, even when no one is asking for it. The practices I’ve shared above are not just technical choices. They reflect how I think about quality, collaboration, and responsibility. They are part of my core values.

    When these values are shared across a team, things tend to go well. Communication is easier, trust builds faster, and the work is more enjoyable. But I’ve also learned that if a team does not value these practices or is not open to them, I struggle to stay engaged. I am not at my best in environments where quality is always an afterthought or where shortcuts become the default.

    This is not about judging other teams or trying to set rules for how everyone should work. Every project has its own realities. But I know from experience that I do my best work in teams that care about how things are built, not just how fast they are delivered.

    That is why I’m sharing this. It is not just a list of preferences. It is an honest picture of how I work and what I bring. And it is a way of making sure that if we do work together, we are starting from a place of shared understanding and mutual respect.

  • About Me

    About Me

    I’m a senior Angular engineer with 15+ years in software development, delivering robust, maintainable applications across enterprise, startup, and independent business environments.

    I specialise in building modern Angular frontends (Angular 2 through 18), with a strong focus on clean code, functional practices, and test-driven development. I lean on tools like facade services, DTOs, and layered abstractions early—even in MVPs—because I believe that sound structure now is cheaper than deep refactoring later.

    Recent roles have seen me lead frontend teams through architectural overhauls, moving from tech-debt-heavy monoliths to cleaner, micro frontend-style applications. I’ve introduced stateless patterns, immutability, shared component libraries, and private registries, as well as reusable web components across codebases.

    I balance delivery with thoughtful engineering, prioritising minimal, meaningful code and clear test coverage. My toolbox includes Angular signals, RxJS observables, and the ability to compose reactive logic across auth, API, and live data layers (e.g. SignalR).

    Earlier in my career, I designed full-stack systems for local businesses—everything from stock control to eCommerce to custom CMS platforms. These experiences sharpened my ability to listen to users and build exactly what’s needed.

    I’ve also mentored developers in Git, Agile, Docker, and Kubernetes, always encouraging simplicity and sustainable practices.

    Whether I’m leading a refactor or prototyping a new feature, I bring curiosity, pragmatism, and a commitment to building things that last.

  • From Hobbyist Sites to Principal Consultant – 15 Years of Clean-Code Front-End


    From hobbyist sites to lead engineer: my 15-year quest for clean, scalable front-end code

    1. A hobby that turned into a career (2008 – 2014)

    I started out building e-commerce sites for local shops in Warwickshire.


    Those evenings taught me that users don’t care about frameworks – they care about speed and clarity.

    Tools then: PHP, plain JavaScript, SEO on a shoestring.


    2. Shipping faster through teaching (2014 – 2020)

    At eTech Solutions I wasn’t just a senior dev – I became the in-house trainer.
    Over 5.5 years I introduced:

    • Git branching (we killed “last-day-merge” panic).
    • Agile ceremonies (stand-ups that finish on time 🕒).
    • Docker & Kubernetes POCs (cut dev-box setup from hours to minutes).

    Lesson #1: Teaching forces you to master the “why”, not just the “how”.


    3. Leaning into leadership & micro-frontends (2020)

    At Mortgage Advice Bureau I inherited a monolith drowning in technical debt.
    We reacted by:

    1. Refactoring to stateless RxJS + immutable data.
    2. Splitting the codebase into micro-frontends and private Nexus libraries.
    3. Coaching a team of three to deliver business value and raise the bar.

    Result: build times down 40 %; new features released weekly instead of monthly.


    4. Principal consultant era (2021 – 2023)

    Virgin Media TV Streaming

    • Angular + Apollo GraphQL
    • Storybook for design-system governance
    • Led six-person squad; coordinated with product, design, QA.

    Lesson #2: Clean code isn’t an aesthetic choice – it’s a performance lever.


    5. Bringing AI into the workflow (2023 → present)

    At Actify I:

    • Integrated GitHub Copilot into our review cycle – 22 % fewer low-value PR comments.
    • Built a GPT-powered Angular schematic that scaffolds unit tests; team adoption hit 90 % in two sprints.

    6. What I can do for your team (summary)

    • Framework depth: Angular 2 → 18, React, RxJS signals.
    • DevEx: CI/CD in Azure DevOps, micro-services, Storybook, Cypress.
    • AI leverage: prompt-engineering, OpenAI API, cost monitoring.
    • Leadership: mentoring, standards, outcome-first agile.

    7. Let’s talk

    I’m open to permanent or contract roles where clean code, functional patterns and AI-assisted delivery matter.
    👉 Linkedin