<?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" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Philip Beel, Solution Engineering]]></title><description><![CDATA[Head of Solution Engineering, B2B Enterprise SaaS]]></description><link>https://theodin.co.uk/</link><image><url>https://theodin.co.uk/favicon.png</url><title>Philip Beel, Solution Engineering</title><link>https://theodin.co.uk/</link></image><generator>Ghost 5.58</generator><lastBuildDate>Wed, 10 Jun 2026 02:53:30 GMT</lastBuildDate><atom:link href="https://theodin.co.uk/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Turbo charging demos with AI]]></title><description><![CDATA[AI has reshaped the B2B enterprise landscape, and where there is fear, there often lies opportunity. Vibe coding prototypes is a game changer for solution engineers.]]></description><link>https://theodin.co.uk/turbo-charging-demos-with-ai/</link><guid isPermaLink="false">68f56a962f4c38043c500418</guid><category><![CDATA[AI]]></category><category><![CDATA[Vibe Coding]]></category><category><![CDATA[Solution Engineering]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Sun, 19 Oct 2025 23:41:32 GMT</pubDate><content:encoded><![CDATA[<p>AI has reshaped the B2B enterprise landscape, and where there is fear, there often lies opportunity. You can think of impact at three levels:</p><ol><li><strong>Individual:</strong> increasing the impact of your specific contribution. </li><li><strong>Team:</strong> applying patterns that benefit those around you.</li><li><strong>Product:</strong> creating delight for customers in a margin increasing way.</li></ol><p>There is an indelible link between each level and so optimising for yourself, could result in a net benefit to your team and perhaps even on product.</p><h2 id="api-first-product-demos">API first product demos</h2><p>Demoing API first products presents a challenge, how do you convey value in a way the prospect can appreciate? Showing an API call in <a href="https://www.postman.com/?ref=theodin.co.uk">Postman</a>, often leads to confusion for non-technical stakeholders, blank expressions, or worse, questions like &quot;who&apos;s JSON?&quot; can undermine your flow.</p><p>Tailoring demonstrations is vital, but building a point of view demo that incorporates API behaviours can be complex and time consuming. Busy solution engineers simply can&apos;t afford to do this at scale. This is amplified in early stage startups where enablement is often lacking.</p><h2 id="enter-vibe-coding">Enter VIBE coding</h2><p>AI vibe coding tools such as <a href="https://base44.com/?ref=theodin.co.uk">Base44</a>, and <a href="https://lovable.dev/?ref=theodin.co.uk">Lovable</a> have unlocked the perfect use-case for busy solution engineers. Coding a tailored demo that would have taken days can now be achieved in hours. Quickly iterating on a prototype that is &quot;good enough&quot; is a liberating experience when done right. this is especially powerful when integrating an API that enables &quot;real&quot; functionality:</p><ul><li>Rapidly flesh out a prototype using a prospects colours/branding/UX</li><li>Use the <a href="https://praxent.com/blog/using-8020-rule-web-design?ref=theodin.co.uk">Pareto principle</a> (80/20) to cover the core experiences to demo, knowing the demo will be controlled by a solution engineer. </li><li>Integrate your product API&apos;s securely using <a href="https://docs.base44.com/Guides/Setting-up-backend-functions?ref=theodin.co.uk">backend functions</a>, or <a href="https://n8n.io/saas/?ref=theodin.co.uk">N8N</a> to orchestrate requests flows (Rest API&apos;s, Webhook callbacks, etc)</li><li>Ephemeral prototypes by design, meaning you can throw them away with little to no maintainence cost. </li></ul><p> </p><figure class="kg-card kg-image-card"><img src="https://theodin.co.uk/content/images/2025/10/Screenshot-2025-10-20-at-18.05.06.png" class="kg-image" alt loading="lazy" width="2000" height="1454" srcset="https://theodin.co.uk/content/images/size/w600/2025/10/Screenshot-2025-10-20-at-18.05.06.png 600w, https://theodin.co.uk/content/images/size/w1000/2025/10/Screenshot-2025-10-20-at-18.05.06.png 1000w, https://theodin.co.uk/content/images/size/w1600/2025/10/Screenshot-2025-10-20-at-18.05.06.png 1600w, https://theodin.co.uk/content/images/size/w2400/2025/10/Screenshot-2025-10-20-at-18.05.06.png 2400w" sizes="(min-width: 720px) 720px"></figure><p></p><h2 id="individual-team-benefits">Individual &amp; Team benefits</h2><p>If you are a solution engineer/consultant exploring ways to leverage AI more formally, consider starting with free tooling and experimenting. Take one low risk demo and set yourself a goal to vibe something simple. Test it out and gauge the response. If it&#x2019;s positive, iterate and try again. Once you hone your skills, share what you did with your team and gauge their appetite. This can have many upsides, from mentoring, to presenting back and increasing your visibility in the company, to increased commission if you see an improvement in demo to close/won deals.</p><h2 id="recommended-reading">Recommended reading</h2><ul><li><a href="https://base44.com/?ref=theodin.co.uk">Base44</a></li><li><a href="https://n8n.io/?ref=theodin.co.uk">N8N</a></li></ul>]]></content:encoded></item><item><title><![CDATA[Engineering the interview process]]></title><description><![CDATA[A strong solutions engineering culture is cultivated through a thoughtful interview process. Implemented effectively, this approach mitigates the necessity for implementing bell curves and performance improvement plans.]]></description><link>https://theodin.co.uk/engineering-the-interview-process/</link><guid isPermaLink="false">65e787432f4c38043c500189</guid><category><![CDATA[engineering management]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Thu, 27 Jun 2024 16:03:04 GMT</pubDate><content:encoded><![CDATA[<p>A strong solutions engineering culture is cultivated through a thoughtful interview process. Implemented effectively, this approach mitigates the necessity for implementing bell curves and performance improvement plans.</p><p>Interviewing is fundamentally about answering three questions. Can I work with you? Can you work with me? and importantly, can you do the work? </p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/engineering-interviews/engineering-the-interview-process.webp" alt="Engineering the interview process" loading="lazy"></p>
<!--kg-card-end: markdown--><h2 id="jtbd">JTBD</h2><p>A strong interview process starts with a well-defined job description(JD). Hiring managers should take extra care when describing the company, role, and responsibilities, to avoid making a laundry list of wants. Instead, focus on the core competencies you desire in a candidate, and be explicit about what&apos;s mandatory and what is nice to have. </p><h2 id="apply-friction">Apply friction</h2><p>When reviewing candidate applications, bringing in an async stage provides several benefits:</p><ol><li>Assess a candidate&apos;s written communication ability. Can they articulate themselves in a clear, concise manner and provide examples of lived experiences?</li><li>Filter out window shoppers. If candidates are not serious, they typically won&apos;t put in the effort required to answer thoughtfully, this will manifest in either short terse answers or AI-generated boilerplate.</li></ol><p>Introducing this stage after the initial CV and phone screen will provide the hiring manager with a clearer understanding of the candidate&apos;s abilities, to make an informed decision about progressing them in the process. </p><h2 id="role-reversal">Role reversal</h2><p>Some of the most valuable data points are in the questions you don&apos;t ask. Leave time for candidate questions, and make it explicit in the interview loop. </p><p>If a candidate only asks about the tech stack, you may wish to probe deeper, but if the candidate instead asks about specific team challenges and company goals, this provides valuable insight into their motivations and drivers. </p><h2 id="demonstrate-principles">Demonstrate Principles</h2><p>When devising behavioral questions, consider the company principle/value and work back to formulate the question. </p><p>If the company emphasizes accountability and ownership, for example, consider asking a STAR-based question that allows you to identify if the candidate is aligned with this principle. Consider building a question bank for the company principles and sharing it with interviewers so questions can be calibrated and used when hiring for other functions.</p><h2 id="technical-assessments">Technical assessments</h2><p>Establishing if a candidate can do the work under artificial conditions is challenging. Regardless of whether you choose live whiteboarding, coding questions, or take-home assignments, the interviewer&apos;s role is to allow the candidate to demonstrate why they should be a strong yes &apos;inclined to hire&apos;.</p><p>Setting a clear playbook for running and evaluating technical assessments will ensure interviewers minimize their biases.</p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/engineering-interviews/engineering-the-interview-process-2.webp" alt="technical assessments" loading="lazy"></p>
<!--kg-card-end: markdown--><h2 id="interview-loop-in-practice">Interview loop in practice</h2><p>Combining each of the elements will leave you with the following stages, which can be applied to create a robust interviewing process:</p><ol><li>Phone screen</li><li>Async (2/3 written questions)</li><li> 1 hr interview on behaviors</li><li>Technical assessment</li><li>1 hr Interview with the hiring manager/founder</li><li>Debrief / Offer</li></ol><p>If you want to learn more, check out the recommended reading materials below.</p><h3 id="further-reading">Further reading</h3><ul><li><a href="https://www.evidenced.app/blog/how-to-onboard-new-interviewers?ref=theodin.co.uk">How to onboard new interviewers</a></li><li><a href="https://nationalcareers.service.gov.uk/careers-advice/interview-advice/the-star-method?ref=theodin.co.uk">The STAR method</a></li><li><a href="https://www.hatchways.io/blog/how-to-build-a-stellar-react-take-home-assessment?ref=theodin.co.uk">How to build a stellar take-home assessment</a> </li><li><a href="https://www.metaview.ai/resources/blog/how-to-run-an-effective-interview-debrief?ref=theodin.co.uk">How to run an effective interview debrief</a> </li></ul>]]></content:encoded></item><item><title><![CDATA[Structuring engineering teams at scale-ups]]></title><description><![CDATA[What product startups and scale-ups should consider before adopting cross-functional, platform, and functional teams to achieve success. ]]></description><link>https://theodin.co.uk/engineering-team-structures/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bdc</guid><category><![CDATA[scale-up]]></category><category><![CDATA[startup]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Fri, 28 Jul 2023 18:33:00 GMT</pubDate><content:encoded><![CDATA[<p>As a company prepares to scale-up from a nascent startup, the inevitable question comes to engineering leaders, how do we structure our teams for success? and how do we move faster? A scaling company on first name terms now needs to divide itself in order to conquer. But where do you draw the lines, and what are the tradeoffs in doing so?</p><p>Understanding what you need to optimise for will make the decision process easier. Let&apos;s consider the options available based on a product focused startup.</p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/scaleup-team-structures/scaleup-team-structure.png" alt="scale-up-team-structures" loading="lazy"></p>
<!--kg-card-end: markdown--><h2 id="cross-functional-teams-xf-squad-">Cross functional teams (XF/Squad)</h2><p>Popularised by the <a href="https://productschool.com/blog/product-fundamentals/spotify-model-scaling-agile?ref=theodin.co.uk">Spotify model</a> cross functional teams optimise for ownership and autonomy, making it possible to focus and go deep in a particular area. Teams will vary in size, usually adhering to the <a href="https://www.theguardian.com/technology/2018/apr/24/the-two-pizza-rule-and-the-secret-of-amazons-success?ref=theodin.co.uk">two pizza</a> maxim. Operating vertically a team might focus on a specific verb i.e. &quot;search&quot;, &quot;discover&quot;, &quot;support&quot; depending on the logical separation of the product domain. </p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/scaleup-team-structures/scaleup-team-vertical.png" alt="vertical-team-structures" loading="lazy"></p>
<!--kg-card-end: markdown--><p>Challenges typically arise in this structure as the product grows in complexity, a couple symptoms can often be identified:</p><ol><li>Team velocity starts to reduce. Technical debt may have accrued, or simply doing what intentionally would not scale is now hurting the team. </li><li>Different problems with very similar qualities begin to be solved in isolation by XF teams (i.e. multiple different implementations for webhooks), meaning more technical overhead and less focus towards product challenges.</li></ol><p>If you observe this, it might be the right time to consider introducing a platform team.</p><h2 id="platform-teams">Platform teams</h2><p>The <a href="https://subscription.packtpub.com/book/cloud-and-networking/9781786465702/1/ch01lvl1sec7/understanding-the-devops-movement?ref=theodin.co.uk">devops</a> movement has made <a href="https://www.youtube.com/watch?v=an8SrFtJBdM&amp;ref=theodin.co.uk">platform engineering</a> a compelling proposition to scale-ups. These teams operate <a href="https://www.wise.jobs/2020/09/16/scaling-transferwise-infrastructure/?ref=theodin.co.uk">horizontally</a>, and their goal is to accelerate the vertical teams productivity. These teams instil a build once mentality, reducing the complexity and duplication individual teams have to contend with. Standardising the way engineers tackle persistence, communication, storage, monitoring are all candidate areas where platform teams can bring value. &#xA0; </p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/scaleup-team-structures/scaleup-team-horizontal.png" alt="horizontal-team" loading="lazy"></p>
<!--kg-card-end: markdown--><p>Look for the symptoms described before spinning up a platform team, as timing is crucial. Starting with a reduced scope is recommended, executing on a couple of small wins will build momentum, giving teams time to adapt to a different model of engagement. An embedded model, where platform engineers work directly with vertical teams on particular problems will accelerate building trust and having a closer understanding of team workflows and pain points. </p><h2 id="functional-teams">Functional teams </h2><p>Structuring engineering teams by their functional discipline optimises for technical knowledge sharing, and technical cohesion. This arrangement may result in Frontend/Backend/Data engineers being co-located. PM&apos;s typically sit outside of these teams and request shaped product work be resourced/funded. In this structure code quality and technical architecture may improve, at the expense of product ownership. A team may also &quot;spin up&quot; out of the functional teams to deliver a clearly defined workstream, this requires strong stakeholder management. While this structure has fallen out of vogue, it is worth noting.</p><h2 id="adaptability">Adaptability</h2><p>Any scale-up will experience growing pains, as change is the only constant. Having a means of <a href="https://tech.deliveryhero.com/our-reliability-manifesto/?ref=theodin.co.uk">measuring teams performance</a> will allow engineering leaders to make informed decisions about when to make adjustments. &#xA0; </p><h2 id="further-reading">Further reading</h2><ul><li><a href="https://www.wise.jobs/2020/09/16/scaling-transferwise-infrastructure/?ref=theodin.co.uk">Scaling infrastructure at Wize</a></li><li><a href="https://leaddev.com/cross-functional-collaboration/structuring-engineering-teams-deliver-value-diverse-markets?ref=theodin.co.uk">Structuring engineering teams to deliver value to diverse markets</a></li><li><a href="https://tech.deliveryhero.com/our-reliability-manifesto/?ref=theodin.co.uk">The Delivery Hero Reliability Manifesto</a></li><li><a href="https://www.youtube.com/watch?v=an8SrFtJBdM&amp;ref=theodin.co.uk">DevOps vs SRE vs Platform Engineering | Clear Big Misconceptions</a></li></ul>]]></content:encoded></item><item><title><![CDATA[Tackling overemployment in remote first companies]]></title><description><![CDATA[Leaders in remote async environments must find ways to tackle overemployment, without sacrificing the high-trust environments we wish to foster.  ]]></description><link>https://theodin.co.uk/spotting-overemployment-in-remote-async-companies/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bdb</guid><category><![CDATA[overemployment]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Fri, 17 Feb 2023 16:01:46 GMT</pubDate><content:encoded><![CDATA[<p>Since the pandemic <a href="https://www.youtube.com/watch?v=oR-mzzIsHVE&amp;ref=theodin.co.uk">overemployment</a> has become a divisive topic in workplace culture, with employers citing this as a reason to <a href="https://www.forbes.com/sites/forbesbusinesscouncil/2022/11/03/tech-companies-forcing-a-return-to-the-office-are-ignoring-the-data/?sh=39641ecc59ee&amp;ref=theodin.co.uk">mandate a return to the office</a>. Creating high trust environments is hard, and this is made more challenging by a rising sub culture that encourages deception and short term gain through employees taking multiple full time positions.</p><p>Leaders in remote async environments must understand this new reality in order to find ways to tackle overemployment, without sacrificing the high trust environments we wish to foster. &#xA0; </p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/tackling-overemployment/tackling-overemployment.webp" alt="image" loading="lazy"></p>
<!--kg-card-end: markdown--><h3 id="why-is-overemployment-prevalent">Why is overemployment prevalent?</h3><p>After the pandemic forced many businesses to transition to a remote setup companies found incumbent office practices did not translate to the remote world, and nascent companies, adopted new <a href="https://remote.com/blog/why-you-should-be-doing-async-work?ref=theodin.co.uk">remote async approaches.</a> In product engineering companies this transition was accelerated by familiar agile practices, which lend themselves to reduced meetings and an emphasis on velocity. A system of good intentions created conditions for opportunists to exploit. A skills shortage leading to lucrative compensation packages in disciplines such as software engineering created all the ingredients for greed to manifest. </p><p>This resulted in predatorial behaviours. Employees can now entertain the possibility of doubling their income if they can hold their nerve and are above average in competence. These individuals believe the rewards outweigh the risks. </p><h3 id="how-can-leaders-tackle-overemployment">How can leaders tackle overemployment?</h3><p>As leaders it&apos;s important to understand the detrimental impact this behaviour can have on teams and organisations. While a talented polygot may double the output of their nearest peer, culture if fundamentally about what you punish and what you reward, so your decision should always be consistent and inline with your company values. </p><p>There are patterns to the behaviour of the overemployed, and knowing what to look for is key.</p><h5 id="peer-reviews">Peer reviews</h5><p>Soliciting feedback from peers has many positives, but in the case of the overemployed it&apos;s typically the primary means to get data points about a persons availability and collaboration. Introduce a <a href="https://about.gitlab.com/handbook/people-group/360-feedback/?ref=theodin.co.uk">360 review</a> process. If you spot a pattern of feedback that someone is distant, or disengaged dig into that, be authentically curious and avoid jumping to conclusions, there might be legitimate reasons, but if the discovery does not align with your own interactions with that person, start asking yourself why.</p><h5 id="avoid-vanity-metrics">Avoid vanity metrics</h5><p>There are many poor measures of contribution, from commits, to lines of code changed. Simply put, these are ripe for gamification and tell you nothing about someones impact, so avoid looking purely at someones technical competency. The fact someone can do the job should be no surprise, instead focus on answering the questions can you work with them? and can they work with you?</p><h5 id="availability-and-engagement">Availability and engagement</h5><p>Are individuals missing recurring team rituals? Is there a patten of last minute circumstances that lead to dropping off calls early or turning off the camera, or simply not turning up. The first step is to call out this behaviour, be explicit that this is an area for improvement. Excuses such as poor time management should be met with clear plan on how this is addressed, owned by the individual, not you. Put a timeframe by when you expect to see improvement. </p><h5 id="trust-and-verify">Trust and verify</h5><p>Finally, the management adage of &apos;trust and verify&apos; applies irrespective to whether a team is distributed or co-located. Do not confuse this with micro-management, it simply means you reserve the right to verify the completeness and correctness of work. Being explicit on this point will set a clear level of expectation, and those that choose to play with fire do so fully understanding the consequences. </p>]]></content:encoded></item><item><title><![CDATA[Numid number pyramid game]]></title><description><![CDATA[Mobile-first arithmetic web game. Improve numeracy skills through simple addition and subtraction of number bonds. ]]></description><link>https://theodin.co.uk/numid/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bda</guid><category><![CDATA[game]]></category><category><![CDATA[javascript]]></category><category><![CDATA[svelte]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Fri, 22 Jul 2022 20:26:08 GMT</pubDate><content:encoded><![CDATA[<p><a href="https://numid.io/?ref=theodin.co.uk">Numid</a> (Nu<em>mber</em> <em>Pyra</em>mid) is a mobile-first arithmetic game inspired by seminal Wordle created by <a href="https://www.powerlanguage.co.uk/?ref=theodin.co.uk">Josh Wardle</a>. The game aims to level up numeracy skills through &#xA0;simple addition and subtraction. The goal is to reach the top of the pyramid as quickly as possible.</p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/Numid/numid-game.png" alt="Numid number pyramid game" loading="lazy"></p>
<!--kg-card-end: markdown--><h3 id="technology-stack">Technology stack</h3><p>The game was written with <a href="https://svelte.dev/?ref=theodin.co.uk">Svelte</a> for logic, <a href="https://tailwindcss.com/?ref=theodin.co.uk">TailwindCSS</a> for styling, and developed using <a href="https://vitejs.dev/?ref=theodin.co.uk">Vite</a>. The game is built into a static artefact then hosted in S3 with <a href="https://www.cloudflare.com/?ref=theodin.co.uk">Cloudflare</a> providing caching and SSL. The minimal nature of the game leant itself to something lightweight, which is where Svelte and Vite really excel, starting with something small that can be developed and built with minimal configuration was a pleasure, and I would highly recommend Vite in future. I was also really impressed with <a href="https://svelte.dev/blog/svelte-and-typescript?ref=theodin.co.uk">Svelte(TS)</a> the docs made grasping the concepts easy and it felt familiar to author code this way. &#xA0; &#xA0;</p><h3 id="challenges-and-learnings">Challenges and learnings</h3><p>The games simplistic nature lends itself to improvements, ranging from difficulty selection to time based completion. Wordle captured peoples imagination by offering the same challenge to everyone, I think this idea could transcend to an arithmetic game also, but what&apos;s harder is to define an interesting dimension for success. Timing is one possibility, but it should not come at the expense of enjoyment. </p><p>You can check out the game at <a href="https://numid.io/?ref=theodin.co.uk">https://numid.io/</a> completely free. forever.</p>]]></content:encoded></item><item><title><![CDATA[LeadDev London 2022]]></title><description><![CDATA[Highlights from LeadDev 2022 Engineering Leadership Conference in London. A new approach to software architecture decisions and career planning]]></description><link>https://theodin.co.uk/leaddev-london-2022/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bd8</guid><category><![CDATA[Conference]]></category><category><![CDATA[management]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Fri, 17 Jun 2022 14:45:00 GMT</pubDate><content:encoded><![CDATA[<p>I was fortunate enough to attend LeadDev London this year, after a two year hiatus it was great to meet IRL and learn from leaders in technology. &#xA0;Despite all the quality content a couple of talks really resonated with me, and so I&apos;m sharing my key take aways and things I want to apply as an Engineering Manager.</p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/leadDev2022/IMG_2424+(2)-min.jpg" alt="LeadDev London 2022 conference" loading="lazy"></p>
<!--kg-card-end: markdown--><h3 id="-1-a-commune-in-the-ivory-tower-a-new-approach-to-architecture-decisions-andrew-harmel-law">#1 A Commune in the Ivory Tower? - A New Approach to Architecture Decisions - Andrew Harmel-Law</h3><p><a href="https://andrewharmellaw.github.io/?ref=theodin.co.uk">Andrew</a> described the inherent problems of becoming a bottleneck as an Architect, and surfaced the concept of &quot;distributed decision making&quot; through <a href="https://corporate-rebels.com/advice-process/?ref=theodin.co.uk">the advice process</a>. What really stood out to me is what good architecture process should be in practice:</p><blockquote><em>[In order for architecture to be successful] it is very much about ensuring that the conversations that needed to be happening, are happening - not always initiating them, nor always helping to focus or navigate them, but ensuring they do happen [...] and guiding when needed</em></blockquote><p>TL;DR: Get advice from all affected parties before making the decision, but you are empowered to drive the discussion.</p><p>A helpful tool for this is an <a href="https://adr.github.io/?ref=theodin.co.uk">Achitecture Decision Record</a> (ADR), which can be used to explore and propose, as well as document as an artifact for the future. A general format might be:</p><ul><li><strong>Status</strong> </li><li><strong>Decision</strong> - what was agreed?</li><li><strong>Context</strong> - what problem we are trying to solve?</li><li><strong>Consequences</strong> - The accepted tradeoffs of the decisions</li><li><strong>Advice</strong> - input from other domain expects, impacted parties</li></ul><p>My team had been playing with a similar approach to document historic decisions, but shifting left to have the ADR introduced in the discovery phase really clicked for me. One slight variation I&apos;d like to make on this concept is to use of a <a href="https://monday.com/blog/project-management/raci-model/?ref=theodin.co.uk">RACI</a> to tie in ownership, as this aligns with our company principle, also using source control (Github) to draft ADR&apos;s and co-locate them in the codebase, so they are preserved.</p><h3 id="-2-people-building-career-planning-for-your-direct-reports-daniel-burke">#2 People Building: Career Planning for your Direct Reports - Daniel Burke</h3><p><a href="https://twitter.com/d2burke?ref=theodin.co.uk">Daniels</a> charisma and enthusiasm is infectious, but what really struck me was the practical advice he imparted about his process for developing his reports. It was simple, digestible and repeatable:</p><ol><li><strong>Position</strong> - where are you?<br>1. <strong>Know your scope</strong> - whats the context and what opportunities do they present<br>2. <strong>Know your level</strong> - what are the expectations for your level at your company<br>3. <strong>Know your performance </strong>- align your performance delta first<strong> </strong></li><li><strong>Plan</strong> - where do you want to be?<br>1. <strong>Whats &#xA0;your motivation?</strong> - understand what&apos;s driving your people<br>2. <strong>Whats your current path</strong> - where is your trajectory taking you<br><strong>3. Creating goals</strong> - create <a href="https://www.atlassian.com/blog/productivity/how-to-write-smart-goals?ref=theodin.co.uk">SMART</a> goals that tie to company and personal growth metrics</li><li><strong>Progress</strong> - how are you doing?</li></ol><p>Daniel also made two really powerful observations that are invaluable for anyone on their management journey: </p><ol><li><strong>You are responsible for your career</strong> - getting reports aligned on this is the first step to accountability.</li><li><strong>Feedback is kindness</strong> -<strong> </strong>don&apos;t be afraid to give constructive criticism, it&apos;s the kindest thing you can do as a manager.</li></ol><p>Overall the conference was a great mix of &#xA0;story telling, educating, and fun. If you want to learn more, check out the further reading section below.</p><h3 id="further-reading">Further reading </h3><ul><li><a href="https://leaddev.com/events?ref=theodin.co.uk">LeadDev future events</a></li><li><a href="https://terrybrown.me/posts/2022/lead-dev-2022/?ref=theodin.co.uk">LeadDev 2022 London writeup</a> by Terry Brown</li></ul>]]></content:encoded></item><item><title><![CDATA[Better React app architectures]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/general/web_development_.svg" alt="react-application-architectures" loading="lazy"></p>
<!--kg-card-end: markdown--><p>Since its debut in 2013, <a href="https://reactjs.org/?ref=theodin.co.uk">React JS</a> has been widely adopted as a technology favourite for web application development. JSX and by extension the virtual DOM have fundamentally shifted the way developers reason about building responsive interfaces. A &apos;<a href="https://create-react-app.dev/?ref=theodin.co.uk">batteries not included</a>&apos; philosophy has empowered front-end engineering teams to</p>]]></description><link>https://theodin.co.uk/better-react-app-architectures/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bd7</guid><category><![CDATA[reactjs]]></category><category><![CDATA[javascript]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Fri, 07 Aug 2020 12:20:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/general/web_development_.svg" alt="react-application-architectures" loading="lazy"></p>
<!--kg-card-end: markdown--><p>Since its debut in 2013, <a href="https://reactjs.org/?ref=theodin.co.uk">React JS</a> has been widely adopted as a technology favourite for web application development. JSX and by extension the virtual DOM have fundamentally shifted the way developers reason about building responsive interfaces. A &apos;<a href="https://create-react-app.dev/?ref=theodin.co.uk">batteries not included</a>&apos; philosophy has empowered front-end engineering teams to make the decisions about how to compose apps, however, there are architectural anti-patterns to be avoided when laying out a codebase. Applying simple principles will help build foundations that will last as technologies evolve.</p><h2 id="decoupled-concerns">Decoupled concerns</h2><p>React JS is popular, so too is <a href="https://svelte.dev/?ref=theodin.co.uk">Svelte</a>, as is <a href="https://vuejs.org/?ref=theodin.co.uk">VueJS</a>. What would happen if your team decided to pivot from one solution to another? Do you have a suitable separation of concerns that means you can refactor a portion of your app, or are you likely to find a wholesale rewrite is necessary?</p><p>Defining boundaries around the various concerns of your application will help isolate what needs to import React. Take for example interacting with an API surface, does this need to be achieved with a React import statement? &#xA0;An <a href="https://blog.fullstacktraining.com/adapter-pattern-in-typescript/?ref=theodin.co.uk">adapter pattern</a> can return data to React modules. The benefits are two fold:</p><ol><li>Your API handler, and test files won&apos;t need to import React, or <a href="https://testing-library.com/docs/react-testing-library/intro?ref=theodin.co.uk">React Testing Library</a>.</li><li>If you pivot away from React you can write a new adapter to communicate with the new view layer.</li></ol><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/general/coding.svg" alt="mono-repos-architectures" loading="lazy"></p>
<!--kg-card-end: markdown--><h2 id="monorepos">Monorepos</h2><p>Despite numerous <a href="https://blog.nrwl.io/misconceptions-about-monorepos-monorepo-monolith-df1250d4b03c?ref=theodin.co.uk">misconceptions about Monorepos</a>, fundamentally they represent a means to co-locate logical packages inside the same repo, they allow teams to independently build constituent parts of a project without blocking colleagues. Stability challenges often occur in distributed teams where there is no robust process to ensure dependency management is understood by producers and consumers of those packages.</p><p>If a Monorepo is right for your problem space, identify the areas of concern up-front, use the <a href="https://sunscrapers.com/blog/single-responsibility-principle-in-react-applications-part-1/?ref=theodin.co.uk">single responsibility principle</a> to help define what these are:</p><p></p><pre><code class="language-shell">- package.json
- ...
|
---- /packages
    |
-------- /components
        |- package.json
        |- ...
-------- /routes
        |- package.json
        |- ...
-------- /api-handler
        |- package.json
        |- ...
-------- /api-react-adapter
        |- package.json
        |- .</code></pre><p>each package can run unit tests, perform linting, and create build artefacts etc, in isolation, which will speed up build times, and streamline developer workflows, this will also aid the first point &#x261D;&#xFE0F; that your api-handler should not need to import React, and so your <code>package.json</code> file can omit this.</p><h2 id="technical-scorecard">Technical scorecard</h2><p>As a codebase grows and evolves, it will inevitably accrue technical debt, this can manifest for a range of reasons, some being:</p><ul><li>Applying <a href="https://thevaluable.dev/dry-principle-cost-benefit-example/?ref=theodin.co.uk">DRY principles</a>, that introduce abstractions, without being able to refactor all previous implementations.</li><li>Discovering a preferred approach, such as using functional components over classes.</li><li>Identifying new methods of testing, for example using <a href="https://kentcdodds.com/blog/stop-mocking-fetch?ref=theodin.co.uk">MSW instead of mocking fetch</a>.</li></ul><p>Technical debt presents several challenges including:</p><ul><li>Onboarding new starters - where it requires context from mentors who must point to the preferred approach.</li><li>Changing business logic, where it requires touching and refactoring &apos;outdated&apos; patterns.</li></ul><p>A technical scorecard can help to track this, and be a useful input when understanding pain points. In the right hands it can highlight priority. A good technical scorecard can measure other dimensions too, such as developer satisfaction, time spent fixing vs building, as well as general codebase health. This is a worthwhile endeavour if your codebase is sufficiently growing and you are ramping up development resource.</p><h2 id="further-reading">Further reading</h2><ul><li>VIPER <a href="https://medium.com/@smalam119/viper-design-pattern-for-ios-application-development-7a9703902af6?ref=theodin.co.uk">design patterns for IOS</a></li><li>Presentation Model - <a href="https://martinfowler.com/eaaDev/PresentationModel.html?ref=theodin.co.uk">Martin Fowler</a></li><li>Adapter Pattern<a href="https://blog.fullstacktraining.com/adapter-pattern-in-typescript/?ref=theodin.co.uk"> for Javascript</a></li><li>Misconceptions <a href="https://blog.nrwl.io/misconceptions-about-monorepos-monorepo-monolith-df1250d4b03c?ref=theodin.co.uk">about Monorepos</a></li><li>Special thanks to <a href="https://www.manypixels.co/?ref=theodin.co.uk">ManyPixels</a> for imagery</li></ul>]]></content:encoded></item><item><title><![CDATA[Remote working: Creating conditions for success]]></title><description><![CDATA[Create a remote work environment where you will thrive. Tips on kit, ways of working, and avoiding burnout. ]]></description><link>https://theodin.co.uk/a-year-remote-working/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bd6</guid><category><![CDATA[remote]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Fri, 03 Apr 2020 10:53:12 GMT</pubDate><content:encoded><![CDATA[<p>In 2019 I took a remote engineering role, motivated by a young family and a long commute.</p><p>Stepping away from a Software Management role, where I&apos;d divided my time between technical leadership and people management, to a fully remote engineering role, was always going to require a change in mindset. Through this journey I&apos;ve learned a few strategies which may be useful for others on the same path.</p><h3 id="separate-your-work-space">Separate your work space</h3><p>I took a month off between jobs to build a home shed-office (pronounced &apos;shoffice&apos;). This was the single best investment I made in the transition, it won&apos;t be feasible for everyone, but whatever your environment, consider this a sacred space that needs to be treated with respect: </p><ul><li>Keeping the space tidy, and clutter free.</li><li>Educate others in the household to respect this space, this is where you will conduct yourself in a professional manner.</li><li>Have an &apos;off switch&apos;, it can be closing a door, or packing away of equipment, but make sure you know what that ritual is, and repeat it.</li></ul><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/remote-working/sacred-office-space-at-home.jpg" alt="sacred office space" loading="lazy"></p>
<!--kg-card-end: markdown--><h3 id="invest-in-audio-visual">Invest in audio visual</h3><p>Regardless of how your company is distributed, stand-ups, company all hands, and 1-2-1&apos;s will likely feature the medium of video calls. How you appear and sound becomes an extension of your professional demeanour: </p><ul><li>Consider face on cameras, with support for HD.</li><li>Simple lighting rigs will brighten dim spaces and improve streamed picture quality.</li><li>Headphones with built in microphones will offer superior audio fidelity. </li></ul><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/remote-working/office-lighting-rig.jpg" alt="lighting rig" loading="lazy"></p>
<!--kg-card-end: markdown--><h3 id="balance-over-burnout">Balance over burnout</h3><p> If you are fortunate enough to find a pursuit in life that you are passionate about, and create a set of favourable conditions to work in, it&apos;s very easy to get the balance wrong. I&apos;ve spent most of my professional career fighting to get a balance that was right for me and those I love. &#xA0;</p><ul><li>The brain processes information sequentially, which is why context switching is so expensive. Plan in half day increments. </li><li>The context switch must factor in breaks.</li><li>Exercise is paramount to a healthy physical and mental relationship with work. Set yourself up for success, prepare your workout/gear in advance, then you only need execute on it, a context change lends itself to this.</li></ul><h3 id="micro-interactions">Micro-interactions</h3><p>Continuing the topic of mental health, even the most introvert among us need to socialise. The opportunities for this are reduced when we are not co-located, so seeking and creating these opportunities is important.</p><ul><li>Asking for help is one of the easiest ways to do this. Pair programming using collaboration tools bridges the gap.</li><li>Daily standup in a remote environment will take longer, as it&apos;s not just about impediments and work in flight, it&apos;s an opportunity for people to share and connect.</li><li>Creating features of your work week, such as workshops and lightening talks will also create conditions for people to share and discuss areas of expertise. &#xA0; </li></ul><h3 id="further-reading">Further reading</h3><ul><li>Lighting: <a href="https://www.amazon.co.uk/gp/product/B07YZ8PQW6/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;psc=1&amp;ref=theodin.co.uk">Lighting ring</a>, <a href="https://www.amazon.co.uk/gp/product/B079FQBFJD/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;psc=1&amp;ref=theodin.co.uk">Light bar</a></li><li>Video: <a href="https://www.amazon.co.uk/gp/product/B07MM4V7NR/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;psc=1&amp;ref=theodin.co.uk">Front-facing HD camera</a></li><li>Headphones: <a href="https://www.theverge.com/2017/12/8/16709882/best-wireless-over-ear-headphones-to-buy?ref=theodin.co.uk">best wireless headphones</a></li><li>Pair programming: <a href="https://visualstudio.microsoft.com/services/live-share/?ref=theodin.co.uk">Liveshare for VSCode</a></li></ul>]]></content:encoded></item><item><title><![CDATA[Upgrade Ghost using Blue-Green deployments & Amazon Lightsail]]></title><description><![CDATA[Ghost is a powerful blogging platform with a promising roadmap of features, however updating to major releases can be problematic. An alternative approach to updating Ghost would be to use 'Blue-Green' deployments]]></description><link>https://theodin.co.uk/upgrading-ghost-blue-green-deployments-aws-lightsail/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bd5</guid><category><![CDATA[AWS]]></category><category><![CDATA[AmazonLightsail]]></category><category><![CDATA[Ghost]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Sun, 25 Nov 2018 12:53:47 GMT</pubDate><content:encoded><![CDATA[<p>Ghost is a <a href="https://ghost.org/?ref=theodin.co.uk">powerful blogging platform</a> with a promising roadmap of features, however updating to major releases can be <a href="https://forum.ghost.org/t/ghost-cli-update-issue/1418?ref=theodin.co.uk">problematic</a>. The <a href="https://github.com/TryGhost/Ghost-CLI?ref=theodin.co.uk">Ghost CLI </a>sets out to solve this problem, but is not yet mature enough to trust updating releases on production servers.</p><blockquote>The objective of the Ghost CLI project is to make setting up and maintaining a Ghost site as straight forward as possible</blockquote><h3 id="blue-green-deployments">Blue-Green Deployments</h3><p>An alternative approach to updating Ghost would be to use &apos;Blue-Green&apos; deployments, for a more in-depth description check out <a href="https://martinfowler.com/bliki/BlueGreenDeployment.html?ref=theodin.co.uk">Martin fowler&apos;s article on the subject</a>. In essence, you have a duplicate setup, Blue(e.g. Live) and Green(New Ghost version). Once updated Green is ready to deploy, you cut-over all traffic from Blue to Green. This has a number of advantages, most notably: </p><ul><li>Reduced/No downtime</li><li>Increased confidence and testing in production like environment</li><li>Ability to rollback easily </li></ul><h3 id="performing-blue-green-with-amazon-lightsail">Performing Blue-Green with Amazon Lightsail</h3><p><a href="https://www.techradar.com/uk/reviews/amazon-lightsail?ref=theodin.co.uk">Amazon Lightsail</a> offers a cheap and easy means to standup virtual servers with a simplified management interface. Although this article focuses on AWS, you could apply the same practice to <a href="https://www.digitalocean.com/?ref=theodin.co.uk">Digital Ocean</a> or other providers. &#xA0;</p><p>The prerequisites for setup are: AWS account, AWS static IP, and DNS configured (Cloudflare). all of which will be covered. </p><p>A core tenant of Dev-Ops is to treat servers as &apos;<a href="https://medium.com/@Joachim8675309/devops-concepts-pets-vs-cattle-2380b5aab313?ref=theodin.co.uk">Cattle, not Cats</a>&apos;, which is to say, it should be simple to standup and terminate servers with minimal system administration. In the case of Ghost you may want to speed up Green environment configuration by putting the setup into source control, but that will create it&apos;s own overhead as major releases will likely change this process. &#xA0; </p><h3 id="creating-your-green-instance">Creating your Green instance </h3><p>Let&apos;s imagine you have a live v1 ghost blog served from AWS. You now want to upgrade to v2. From the AWS management console select <strong><em>Instances &gt; Create instance </em></strong>and select the ubuntu configuration as defined by the <a href="https://docs.ghost.org/install/ubuntu/?ref=theodin.co.uk">Ghost stack guide</a>. This will take a few moments to startup. You should have instances as follows where blue is live and green is your new candidate:</p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/Blue-Green/blue-green-instances.png" alt="blue-green-instances" loading="lazy"></p>
<!--kg-card-end: markdown--><p>You can now setup your new instance following the <a href="https://docs.ghost.org/install/ubuntu/?ref=theodin.co.uk#create-a-new-user-">Ghost how to guide</a>. This should mean you are running the latest version of Ghost. Once done, you will want to use the <strong><em>Ghost admin console &gt; Labs </em></strong>export/import feature to move across your old posts and metadata to the new Green instance. Finally you may want to upload your new vX compliant theme into the Green Ghost instance. You can check that your theme meets the version requirements using the <a href="https://gscan.ghost.org/?ref=theodin.co.uk">gscan tool</a>. <strong>Please note:</strong> Once setup is complete, to have a true production environment you may need to re-run the <em>ghost-setup</em> command with your live blog domain name to ensure NGINX correctly maps HTTP requests on startup. </p><h3 id="setup-a-static-ip-address-with-lightsail">Setup a Static IP Address with Lightsail</h3><p>In the <a href="https://lightsail.aws.amazon.com/?ref=theodin.co.uk">Lightsail console</a> navigate to <strong><em>Networking &gt; Create Static IP</em></strong> here we you will be asked to specify your availability region and an identifiable name for the IP address. Please note static IP addresses are only retained as long as they are attached to a specific instance, essentially a &apos;use it or loose it&apos; policy. So be sure to attach to your Blue instance at this point. The IP address console should now display like so:</p><!--kg-card-begin: markdown--><p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/Blue-Green/blue-green-static-ip.png" alt="blue-static-ip" loading="lazy"></p>
<!--kg-card-end: markdown--><h3 id="routing-traffic-to-between-blue-green">Routing Traffic to between Blue-Green</h3><p>The domain name for your Ghost blog will point to your Blue(live) setup. <a href="https://www.cloudflare.com/ssl/?ref=theodin.co.uk">Cloudflare offer free SSL</a> that allows you to specify the static IP address to route all traffic to, meaning you can attach the static IP you created to either instance. If things go wrong and you need to rollback a straightforward re-attachment of the static IP to your Blue instance will reset you to your previous version. The console will show which instance has the static IP, in this example Green is now live:</p><figure class="kg-card kg-image-card"><img src="https://s3.amazonaws.com/theodin.co.uk/posts/Blue-Green/green-live-deployed.png" class="kg-image" alt="green deployed live" loading="lazy"></figure><p></p><h3 id="blue-green-considerations">Blue Green Considerations</h3><p>Blue Green deployments are not a silver bullet, they come with their own tradeoffs, depending on the size and complexity of a service the cost overheads may be harder to justify. In the case of this example you could think of this as a transient event, where ghost-v1-blue is decommissioned, or you could use more general naming and keep both running so you can quickly and confidently keep pace with new updates without risking any production downtime. </p><h3 id="further-reading-">Further reading:</h3><p>If you are interesting in learning more about Blue-Green deployments and Dev-Ops best practices here is some recommended reading:</p><ul><li><a href="https://www.amazon.co.uk/dp/B07B9F83WM/ref=dp-kindle-redirect?_encoding=UTF8&amp;btkr=1&amp;ref=theodin.co.uk">Accelerate: The Science of Lean Software and DevOps</a></li><li><a href="https://www.oreilly.com/library/view/the-devops-handbook/9781457191381/?ref=theodin.co.uk">The DevOps Handbook</a></li><li><a href="https://martinfowler.com/bliki/BlueGreenDeployment.html?ref=theodin.co.uk">BlueGreenDeployment - Martin Fowler</a></li></ul>]]></content:encoded></item><item><title><![CDATA[Setup a Clojure Webserver with Jetty, Compojure, & Hiccup]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><a href="https://clojure.org/?ref=theodin.co.uk">Clojure</a> is a versatile programming language founded on dynamic principles. Its speed and coherence have made it a desireable candidate for microservice achitectures, however the learning curve is steep.</p>
<h3 id="settingupaclojureproject">Setting up a Clojure project</h3>
<p>Clojures power also brings complexity. There are a number of ways to configure Clojure projects, but</p>]]></description><link>https://theodin.co.uk/setup-a-clojure-webserver-with-jetty-compojure/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bd4</guid><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Wed, 09 May 2018 15:59:51 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><a href="https://clojure.org/?ref=theodin.co.uk">Clojure</a> is a versatile programming language founded on dynamic principles. Its speed and coherence have made it a desireable candidate for microservice achitectures, however the learning curve is steep.</p>
<h3 id="settingupaclojureproject">Setting up a Clojure project</h3>
<p>Clojures power also brings complexity. There are a number of ways to configure Clojure projects, but one of the most popular is <a href="https://leiningen.org/?ref=theodin.co.uk">leiningen</a>. This simple configuration tool enables fast project setup, so you can focus on building.</p>
<h3 id="exampleclojurewebserver">Example Clojure webserver</h3>
<p>Clojure is an ideal language for web projects, suitable for API and application development. This <a href="https://github.com/philipbeel/example-clojure-webserver-jetty-compojure-hiccup?ref=theodin.co.uk">example project</a> provides a webserver boilerplate with support for app routing and HTML templating.</p>
<p>Once Leiningen is installed follow these steps to setup a webserver at <a href="http://localhost:3000/?ref=theodin.co.uk">http://localhost:3000</a></p>
<pre><code>git clone git@github.com:philipbeel/example-clojure-webserver-jetty-compojure-hiccup.git

cd example-clojure-webserver-jetty-compojure-hiccup

lein run
</code></pre>
<h4 id="webserversetupusingringjettyadapter">Webserver setup using Ring Jetty adapter</h4>
<p><a href="https://github.com/ring-clojure/ring/wiki/Getting-Started?ref=theodin.co.uk">Ring Jetty adapter</a> allows integration of a configurable webserver into any Clojure project, it provides options for threading, port configuration, and basic <a href="https://practicalli.github.io/clojure-webapps/create-a-webserver-with-ring/add-a-jetty-webserver.html?ref=theodin.co.uk">req/response structures</a>. It can be used as the basis for web based projects.</p>
<h4 id="routingrequestswithcompojure">Routing requests with Compojure</h4>
<p><a href="https://github.com/weavejester/compojure/wiki/Routes-In-Detail?ref=theodin.co.uk">Compojure</a> provides a comprehensive routing library. The example project implements a two routes, for an index page and a 404 page, demonstrating how these can be abstracted into a <code>/routing</code> directory.</p>
<h4 id="expressivehtmltemplatingviahiccup">Expressive HTML templating via Hiccup</h4>
<p><a href="https://github.com/weavejester/hiccup?ref=theodin.co.uk">Hiccup</a> offers an expressive way to write HTML markup. The API reference documents how the structure can be extended to create dynamic markup. The <a href="https://github.com/philipbeel/example-clojure-webserver-jetty-compojure-hiccup/blob/master/src/server_example/routing/index.clj?ref=theodin.co.uk">example project</a> demonstrates how this can be used in conjunction with script and stylesheets to render comprehensive HTML documents.</p>
<h3 id="furtherreading">Further reading</h3>
<p>Clojure is an extremly robust language, whilst setup can be challenging there are a great number of libraries that make it extremely enjoyable to work with. If you are interested in finding out more about Clojure, here are some recommended links:</p>
<ul>
<li><a href="https://github.com/functional-koans/clojure-koans?ref=theodin.co.uk">A set of exercises for learning Clojure</a></li>
<li><a href="https://www.braveclojure.com/?ref=theodin.co.uk">Brave Clojure</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Typescript coverage with Mocha & NYC]]></title><description><![CDATA[How implement code coverage in Typescript projects using Mocha, and Istanbul NYC. Tutorial with sample repo.]]></description><link>https://theodin.co.uk/typescript-coverage-mocha-nyc/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bd3</guid><category><![CDATA[typescript]]></category><category><![CDATA[Istanbul NYC]]></category><category><![CDATA[Mocha]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Fri, 09 Mar 2018 22:46:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><a href="https://www.typescriptlang.org/index.html?ref=theodin.co.uk">Typescript</a> provides strict typing, empowering teams to build enterprise applications that scale. Whilst precompilers offer benefits to Javascript, they present interoperability challenges when performing coverage checks on precompiled code.</p>
<h4 id="typescriptcoveragereports">Typescript coverage reports</h4>
<p>Coverage reports give insight into statements, functions, branches, and lines, but not necessarily <a href="https://theodin.co.uk/javascript-coverage-with-gulp-karma-istanbul/">quality</a>. It stands to reason that if your application code is written in Typescript, then your tests should be too. Further to this, having coverage represented in Typescript as opposed to compiled Javascript is invaluable in the development workflow.</p>
<h4 id="typescriptcoverageexample">Typescript coverage example</h4>
<p>This <a href="https://github.com/philipbeel/example-typescript-nyc-mocha-coverage?ref=theodin.co.uk">example project</a> demonstrates how to generate a Typescript coverage report for unit tests written in  <a href="https://mochajs.org/?ref=theodin.co.uk">Mocha</a> and executed with <a href="https://github.com/istanbuljs/nyc?ref=theodin.co.uk">NYC</a>.</p>
<pre><code>git clone git@github.com:philipbeel/example-typescript-nyc-mocha-coverage.git
</code></pre>
<p>The example project implements a boilerplate Typescript app for a crude calculator, with addition and subtraction files located in <code>calculator/ts/src</code>. The coverage report is executed from <code>package.json</code>:</p>
<pre><code>cd example-typescript-nyc-mocha-coverage
npm install
npm run coverage
</code></pre>
<h4 id="coverageinteroperabilityexplained">Coverage interoperability explained:</h4>
<p>The command executes the following behaviour in order to generate the report:</p>
<ol>
<li>The <code>package.json</code> specifies <a href="https://github.com/istanbuljs/nyc?ref=theodin.co.uk#configuring-nyc">configuration</a> options for NYC, the app <code>.ts</code> files are included and all test files, denoted by <code>*.test.ts</code> are excluded from the coverage report</li>
<li>The <code>/test</code> directory includes a <code>mocha.opts</code> file, this tell Mocha where to find the tests that need executing.</li>
<li>The unit tests are run, then the results are collected by NYC, which produces a coverage summary and a generated <code>/coverage</code> directory outlining the full detailed report.</li>
</ol>
<pre><code>==== Coverage summary =======
Statements   : 100% ( 10/10 )
Branches     : 100% ( 0/0 )
Functions    : 100% ( 6/6 )
Lines        : 100% ( 10/10 )
==============================
</code></pre>
<h4 id="furtherreading">Further reading:</h4>
<p>Typescript solves a very specific problem, however, it may not be right for every situation. If you are interested in learning more here are some resources:</p>
<ul>
<li><a href="https://www.carnaghan.com/typescript-demystified/?ref=theodin.co.uk">Demystifying Typescript</a></li>
<li><a href="https://www.typescriptlang.org/docs/handbook/declaration-files/by-example.html?ref=theodin.co.uk">Typescript by example</a></li>
<li><a href="https://hackernoon.com/typescript-vs-javascript-b568bc4a4e58?ref=theodin.co.uk">Typescript Vs Javascript</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Securing Ghost with SSL and Amazon Lightsail Bitnami Apps]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>The advent of <a href="https://amazonlightsail.com/?ref=theodin.co.uk">Amazon Lightsail</a> makes it even easier to spin up low cost EC2 instances, these can be pre-configured with a range of images such as NodeJS. <a href="http://codingagaintomorrow.com/creating-a-blog-site-in-aws/?ref=theodin.co.uk">CodeAgainTomorrow</a> provides a tutorial to get setup with <a href="https://ghost.org/?ref=theodin.co.uk">Ghost</a>, ideal for a blog. Securing your instance with SSL is essential for <a href="https://moz.com/blog/seo-tips-https-ssl?ref=theodin.co.uk">a</a></p>]]></description><link>https://theodin.co.uk/securing-ghost-with-ssl-on-amazon-lightsail-bitnami-apps/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bd2</guid><category><![CDATA[SSL]]></category><category><![CDATA[AmazonLightsail]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Ghost]]></category><category><![CDATA[Bitnami]]></category><category><![CDATA[Apache2]]></category><category><![CDATA[CSR]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Wed, 28 Jun 2017 22:36:45 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>The advent of <a href="https://amazonlightsail.com/?ref=theodin.co.uk">Amazon Lightsail</a> makes it even easier to spin up low cost EC2 instances, these can be pre-configured with a range of images such as NodeJS. <a href="http://codingagaintomorrow.com/creating-a-blog-site-in-aws/?ref=theodin.co.uk">CodeAgainTomorrow</a> provides a tutorial to get setup with <a href="https://ghost.org/?ref=theodin.co.uk">Ghost</a>, ideal for a blog. Securing your instance with SSL is essential for <a href="https://moz.com/blog/seo-tips-https-ssl?ref=theodin.co.uk">a number of security and SEO reasons</a>, configuring <a href="https://blog.yell.com/2016/03/https-is-hard/?ref=theodin.co.uk">SSL can be hard</a>, but it doesn&apos;t have to be.</p>
<h2 id="prerequisites">Prerequisites</h2>
<p>The following assumptions will be made:</p>
<ul>
<li>You have acquired an <a href="https://www.namecheap.com/security/ssl-certificates.aspx?ref=theodin.co.uk">SSL certificate</a> from a vendor</li>
<li>You selected the Bitnami NodeJS image for your Lightsail instance</li>
<li>You own a domain name and you have setup DNS to <a href="http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-to-ec2-instance.html?ref=theodin.co.uk">point to your instance</a></li>
<li>You have <a href="http://codingagaintomorrow.com/creating-a-blog-site-in-aws/?ref=theodin.co.uk">setup your ghost blog</a></li>
</ul>
<h2 id="generatingacsr">Generating a CSR</h2>
<p>Bitnami&apos;s Apache2 configuration comes with a self signed certificate pre-installed, which means the <code>bitnami.conf</code> only requires light modification. In order to swap the self signed cert for a trusted one, first you will need to generate a Certificate Signing Request (CSR)</p>
<h6 id="1navigatetotheapache2configuration">1. Navigate to the apache2 configuration</h6>
<p>SSH into your Lightsail instance and navigate to the conf directory:</p>
<pre><code>cd /opt/bitnami/apache2/conf
</code></pre>
<p>This directory will already be populated with the self signed <code>server.key</code>, <code>sever.crt</code>.</p>
<h6 id="2createrequest">2. Create request</h6>
<p>Next a CSR and key must be generated. To avoid confusion it&apos;s recommended to use the domain name for csr/key. Modify and run the following command:</p>
<pre><code>openssl req -new -newkey rsa:2048 -nodes -keyout domain-name.key -out domain-name.csr
</code></pre>
<p>When prompted enter information about the company and domain. <strong>Please note: United Kingdom region must use the &apos;GB&apos; country code.</strong></p>
<h6 id="3copythecsr">3. Copy the CSR</h6>
<p>A new CSR and key will be generated, open the CSR and copy the entire contents:</p>
<pre><code>cat domain-name.csr
</code></pre>
<h2 id="verification">Verification</h2>
<p>Paste the CSR into the SSL vendors control panel. The certificate issuer will need to verify the owner of the domain, there are generally 3 ways to do this:</p>
<ul>
<li>Provide an accessible domain email address.</li>
<li>Create a unique DNS CNAME.</li>
<li>Upload a unique public facing asset to the server.</li>
</ul>
<p>Choose the appropriate method and follow the vendors instructions, it can take up to one hour to be verified.</p>
<h2 id="uploadsigningmaterials">Upload signing materials</h2>
<p>Once the SSL vendor has verified that you own the domain a set of signing materials will be available to download. Depending on the vendor the format can vary:</p>
<ul>
<li><code>domain.crt</code></li>
<li><code>domain.ca-bundle</code> (dependent on vendor)</li>
</ul>
<p>Either SCP these files into <strong>/opt/bitnami/apache2/conf</strong> or touch the files and copy paste the contents of the signing materials, for consistency it&apos;s recommended to use the domain when naming these files.</p>
<pre><code>cd /opt/bitnami/apache2/conf
touch domain.crt
vim domain.crt
</code></pre>
<h2 id="makecertsavailable">Make certs available</h2>
<p>To start using the new signing materials the <code>bitnami.conf</code> needs updating, open the configuration for editing:</p>
<pre><code>vim /opt/bitnami/apache2/conf/bitnami/bitnami.conf
</code></pre>
<p>Search for the following lines:</p>
<pre><code>&lt;VirtualHost _default_:443&gt;
  DocumentRoot &quot;/opt/bitnami/apache2/htdocs&quot;
  SSLEngine on
  SSLCertificateFile &quot;/opt/bitnami/apache2/conf/domain.crt&quot;
  SSLCertificateKeyFile &quot;/opt/bitnami/apache2/conf/domain.key&quot;
</code></pre>
<ul>
<li><strong>SSLCertificateFile:</strong> replace with the newly added <code>domain.crt</code></li>
<li><strong>SSLCertificateKeyFile:</strong> replace with the <code>domain.key</code> that you generated in the initial CSR request</li>
</ul>
<p>Additionally if a <code>domain.ca-bundle</code> was provided in the signing materials include this line for Apache2:</p>
<pre><code>SSLCertificateChainFile &quot;/opt/bitnami/apache2/conf/domain.ca-bundle&quot;
</code></pre>
<h2 id="exclusiveuseofhttps">Exclusive use of https</h2>
<p>In order to make exclusive use of https:// on all incoming requests, include the <strong>RequestHeader</strong> directive into the above block:</p>
<pre><code>RequestHeader set X-Forwarded-Proto &quot;https&quot;
</code></pre>
<h2 id="restartapache">Restart Apache</h2>
<p>For the changes to take effect, Apache must be restarted:</p>
<pre><code>sudo /opt/bitnami/ctlscript.sh restart apache
</code></pre>
<p>The CLI will notify you if there were any issues restarting Apache2, assuming everything is successful, test out the domain name on <strong>https://</strong> and you should get the padlock confirming you are now serving your ghost blog over SSL.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Programming reactive interfaces with RxJS]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Building enterprise level web UI&apos;s is challenging. Functional Reactive Programming (FRP) may hold the solution with the advent of &apos;Reactive Extensions for JavaScript&apos; also known as <a href="https://github.com/Reactive-Extensions/RxJS?ref=theodin.co.uk">RxJS</a>.</p>
<h4 id="whatisreactiveprogramming">What is reactive programming!?</h4>
<p><a href="https://gist.github.com/staltz/868e7e9bc2a7b8c1f754?ref=theodin.co.uk">Andr&#xE9; Staltz introduction</a> to &apos;reactive programming&apos; gives a great overview to the</p>]]></description><link>https://theodin.co.uk/programming-reactive-interfaces-with-rxjs/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bd1</guid><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Sat, 08 Oct 2016 18:42:54 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Building enterprise level web UI&apos;s is challenging. Functional Reactive Programming (FRP) may hold the solution with the advent of &apos;Reactive Extensions for JavaScript&apos; also known as <a href="https://github.com/Reactive-Extensions/RxJS?ref=theodin.co.uk">RxJS</a>.</p>
<h4 id="whatisreactiveprogramming">What is reactive programming!?</h4>
<p><a href="https://gist.github.com/staltz/868e7e9bc2a7b8c1f754?ref=theodin.co.uk">Andr&#xE9; Staltz introduction</a> to &apos;reactive programming&apos; gives a great overview to the subject, I strongly recommend you read this first.</p>
<p>Functional Reactive programming is a paradigm that combines event driven programming with the benefits of functional programming. UI development is a perfect use case, as the majority of engagement comes from user interaction.</p>
<h4 id="streamsandmonads">Streams and monads</h4>
<p>Event streams are the cornerstone of RxJS, however in order to explain this we must first understand monads, which is <a href="http://stackoverflow.com/questions/2704652/monad-in-plain-english-for-the-oop-programmer-with-no-fp-background?ref=theodin.co.uk">no easy task</a>. If you&apos;ve ever used libraries like jQuery, the syntax may feel familiar:</p>
<pre><code>$(&apos;#id&apos;).fadeOut(&apos;slow&apos;).fadeIn(&apos;fast&apos;)
</code></pre>
<p>The conceptual idea of chaining functions onto monads means you can write succinct, readable code. RxJS builds on this theme by broadcasting and subscribing to event streams, functions can be chained to these event streams to perform a range of actions.</p>
<h4 id="rxjsinpractice">RxJS in practice</h4>
<p>Let&apos;s put these concepts into practice. Imagine you are given a requirement to build a PIN entry feature, that must apply the following business rules:</p>
<ul>
<li>Accept only numeric values from the keyboard.</li>
<li>Take a maximum of 4 numeric values.</li>
<li>Update the UI to display the user input values in order.</li>
<li>Display a notification when all criteria has been met.</li>
</ul>
<p>Lets look at how we might implement this in RxJS:</p>
<pre><code>    Rx.Observable.fromEvent(document, &apos;keyup&apos;)
        .debounce(100)
        .map((data) =&gt; data.key)
        .filter((key) =&gt; !isNaN(Number(key)))
        .take(4)
        .do(input =&gt; document.getElementsByTagName(&apos;input&apos;)[this.inputCount++].value = input)
        .count()
        .last(x =&gt; document.getElementById(&apos;notification&apos;).style.display=&apos;block&apos;)
        .subscribe(this.inputCount = 0);
</code></pre>
<p><a href="https://github.com/philipbeel/example-rxjs?ref=theodin.co.uk">Checkout the full example on Github</a></p>
<p><em>Please note this requires an ES6 compatible browser</em></p>
<p>In just 9 lines a stream has been created, which fulfils all these requirements. Lets step through the code to take a closer look at what&apos;s happening:</p>
<pre><code>    // Create observer on the keyup event
    Rx.Observable.fromEvent(document, &apos;keyup&apos;)
        // Wait 100ms between user keyup events 
        .debounce(100)
        // Strip the keyboard keys value from the data object
        .map((data) =&gt; data.key)
        // Filter out everything but number keys
        .filter((key) =&gt; !isNaN(Number(key)))
        // Only accept 4 numerical key values
        .take(4)
        // Push this value into the N input field on the DOM
        .do(input =&gt; document.getElementsByTagName(&apos;input&apos;)[this.inputCount++].value = input)
        // Count the number of numerical keypresses
        .count()
        // On the last numerical keypress display a notification to the user
        .last(x =&gt; document.getElementById(&apos;notification&apos;).style.display=&apos;block&apos;)
        // Finally subscribe to the key up event and start the input count at 0
        .subscribe(this.inputCount = 0);
</code></pre>
<h4 id="considerationsandimprovements">Considerations and improvements</h4>
<p>This example implementation is not perfect. The view interaction is tightly coupled, ideally this would be handled by a mediator or other actor. Taking this idea further we could include:</p>
<ul>
<li>An external API to validate the PIN value is correct</li>
<li>Error handling if the PIN does not match the expected value</li>
<li>Handling mouse and manual focus events.</li>
</ul>
<h4 id="summary">Summary</h4>
<p>RxJS has a steep learning curve, but With <a href="http://techblog.netflix.com/search/label/Rx?ref=theodin.co.uk">Netflix</a> driving the profile of this emerging set of libraries I expect resources and documentation to improve.</p>
<p>Having used RxJS in conjunction with Typescript and ES6 I have been really impressed by it&apos;s versatility, that said it may not suit every use case. If you are working on enterprise level applications with larger teams 20+ RxJS is worth some investigation.</p>
<h5 id="furtherreading">Further reading:</h5>
<ul>
<li><a href="http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html?ref=theodin.co.uk">RxJS documentation</a></li>
<li><a href="https://gist.github.com/staltz/868e7e9bc2a7b8c1f754?ref=theodin.co.uk">The introduction to Reactive Programming you&apos;ve been missing</a></li>
<li><a href="https://www.youtube.com/watch?v=AslncyG8whg&amp;ref=theodin.co.uk">Netflix JavaScript Talks - RxJS + Redux + React = Amazing</a></li>
</ul>
<p>The full exampe RxJS code can be found on Github:<br>
<a href="https://github.com/philipbeel/example-rxjs?ref=theodin.co.uk">https://github.com/philipbeel/example-rxjs</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Javascript coverage with Gulp, Karma & Istanbul]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Creating modular, testable code in your Javascript projects is imperative. Coverage enables developers to measure their unit tests. <a href="https://gotwarlost.github.io/istanbul/?ref=theodin.co.uk">Istanbul</a> is one such tool and plays nicely with <a href="http://gulpjs.com/?ref=theodin.co.uk">gulp</a>. It can be used to cover statements, branches and functions.</p>
<h6 id="whatcoveragetoolsare">What coverage tools are:</h6>
<p>Useful indicators for project health, when combined with</p>]]></description><link>https://theodin.co.uk/javascript-coverage-with-gulp-karma-istanbul/</link><guid isPermaLink="false">64e4e581bcbac20a926c5bd0</guid><category><![CDATA[javascript]]></category><category><![CDATA[karma]]></category><category><![CDATA[istanbul]]></category><category><![CDATA[gulp]]></category><dc:creator><![CDATA[Philip Beel]]></dc:creator><pubDate>Wed, 30 Dec 2015 01:56:58 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Creating modular, testable code in your Javascript projects is imperative. Coverage enables developers to measure their unit tests. <a href="https://gotwarlost.github.io/istanbul/?ref=theodin.co.uk">Istanbul</a> is one such tool and plays nicely with <a href="http://gulpjs.com/?ref=theodin.co.uk">gulp</a>. It can be used to cover statements, branches and functions.</p>
<h6 id="whatcoveragetoolsare">What coverage tools are:</h6>
<p>Useful indicators for project health, when combined with CI pipelines they ensure new and modified code is suitably covered and less likely to introduce bugs.</p>
<h6 id="whatcoveragetoolsarenot">What coverage tools are not:</h6>
<p>A guarantee that your tests are well written. You can have 100% code coverage, but if the tests are brittle, then it&apos;s for nothing.</p>
<hr>
<h5 id="istanbulcoverageexample">Istanbul Coverage example</h5>
<p>I&apos;ve put together an <a href="https://github.com/philipbeel/example-istanbul-gulp-coverage?ref=theodin.co.uk">example project</a> to demonstrate how to integrate coverage into a project.</p>
<pre><code>git clone https://github.com/philipbeel/example-istanbul-gulp-coverage
</code></pre>
<p>You&apos;ll need to globally install gulp on your machine in order to run <code>gulp</code> on the CLI:</p>
<pre><code>cd example-istanbul-gulp-coverage
npm install 
npm install gulp -g
</code></pre>
<p>The example project implements YACA (Yet Another Calculator App) a crude calculator, with addition and subtraction files located in <code>calculator/js</code>. The project also contains a <code>gulpfile.js</code> and <code>karma.conf.js</code>, we&apos;ll walk through this later. For now we just want to run the default gulp task:</p>
<pre><code>gulp
</code></pre>
<p>You should see <code>coverage/js/index.html</code> open in your browser with the score of both files, <code>add.js</code> at 100% and <code>subtract.js</code> at 71%.</p>
<p><img src="https://s3.amazonaws.com/theodin.co.uk/posts/istanbul-example/istanbul-output.png" alt="istanbul coverage" loading="lazy"></p>
<p>Clicking into a filename shows line by line details about what code is being covered. I&apos;ve deliberately left off some tests on <code>subtract.test.js</code> so you can compare the results.</p>
<h6 id="coveragecommandexplained">Coverage command explained:</h6>
<p>When we executed the gulp command the following events sequence is triggered:</p>
<ol>
<li>The <code>unit:coverage</code> gulp task is executed, which starts a karma test runner and sets up the <a href="https://github.com/karma-runner/gulp-karma?ref=theodin.co.uk">configuration options</a></li>
<li>The phantom browser runs and the tests are executed inside of it.</li>
<li>The output is reported back to the gulpfile, Istanbul then creates a new <code>/coverage</code> directory to store the results.</li>
<li>A new browser tab is automatically opened displaying the Istanbul report.</li>
</ol>
<p>You can extend this example project to implement AMD, or switch mocha for jasmine, as per your requirements.</p>
<h6 id="furtherreading">Further reading</h6>
<p>Coverage testing can be valuable component of a wider CI toolchain. If your interested check out some of these valuable resources.</p>
<ul>
<li><a href="http://jenkins-ci.org/content/official-jenkins-lts-docker-image?ref=theodin.co.uk">Jenkins Docker Image</a></li>
<li><a href="http://elijahmanor.com/unit-test-like-a-secret-agent-with-sinon-js/?ref=theodin.co.uk">Sinnon JS unit testing</a></li>
<li><a href="https://www.atlassian.com/git/tutorials/git-hooks/?ref=theodin.co.uk">Git hooks</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>