<?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[Tech @ Zuto]]></title><description><![CDATA[Code, cloud and table tennis]]></description><link>https://tech.zuto.com/</link><image><url>https://tech.zuto.com/favicon.png</url><title>Tech @ Zuto</title><link>https://tech.zuto.com/</link></image><generator>Ghost 1.26</generator><lastBuildDate>Mon, 13 Apr 2026 00:38:32 GMT</lastBuildDate><atom:link href="https://tech.zuto.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Ping-Pong: Pairing isn't just an Olympic Sport]]></title><description><![CDATA[<div class="kg-card-markdown"><p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/08/pingpong.PNG" alt="pingpong"></p>
<p>Many of us have been enjoying the delayed Tokyo Olympic Games the last couple of weeks. And many people watching the table tennis (or ping pong) would not immediately associate it with software development. But &quot;ping-pong pairing&quot; is something many teams at Zuto incorporate into their day-to-day lives.</p></div>]]></description><link>https://tech.zuto.com/ping-pong-when-pairing-isnt-just-an-olympic-sport/</link><guid isPermaLink="false">610aa807b2e3d200333ac838</guid><dc:creator><![CDATA[Jade Kneen]]></dc:creator><pubDate>Wed, 04 Aug 2021 00:09:00 GMT</pubDate><media:content url="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/08/ping_pong_cartoon-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/08/ping_pong_cartoon-1.png" alt="Ping-Pong: Pairing isn't just an Olympic Sport"><p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/08/pingpong.PNG" alt="Ping-Pong: Pairing isn't just an Olympic Sport"></p>
<p>Many of us have been enjoying the delayed Tokyo Olympic Games the last couple of weeks. And many people watching the table tennis (or ping pong) would not immediately associate it with software development. But &quot;ping-pong pairing&quot; is something many teams at Zuto incorporate into their day-to-day lives.</p>
<h1 id="whatispingpongpairing">What is &quot;ping-pong&quot; pairing?</h1>
<p>Pairing is a common practice in software development. This is where two developers will work on the same ticket or piece of work, usually with one developer &quot;driving&quot; by writing the code and another one &quot;directing&quot; which means to instruct.</p>
<p>Ping-pong pairing is another structure. This is where one developer will write a unit test. This will fail, in line with the <strong>T</strong>est <strong>D</strong>riven <strong>D</strong>evelopment practices. The second developer will then write the code which will make this failing unit test pass. Once the test is passing, the developers will switch roles.</p>
<p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/08/ping_pong_cartoon.png" alt="Ping-Pong: Pairing isn't just an Olympic Sport"></p>
<h1 id="whatarethebenefits">What are the benefits?</h1>
<p>Ping pong pairing allows both developers the opportunity to work on the unit tests and the code. It ensures that both get to work on the code, as the structure prevents one developer from doing all of the work. This is especially beneficial when a developer might be new to TDD or unit testing.</p>
<p>Another benefit of ping pong pairing is that it improves understanding of the code. By focusing on small amounts of code, because each unit test is taking one at a time, and will by nature only focus on a small area of code; it will improve the understanding of the code.</p>
<p>This structure of pairing drives discussions between developers. The rapid code changes and role switching will encourage both developers to keep communication open, while traditional pair programming may find one developer driving and talking more.</p>
<h1 id="aretheredownsides">Are there downsides?</h1>
<p>During these covid times when people are working remotely, the main downside can be the need to pass the code back and forth so often. There are various ways to do this, whether developers use a live-sharing software, or the code is pushed to Github etc and pulled down by the other developer. This can feel tedious or may be time consuming when developers are on a short deadline or there are issues with any software that is being used.</p>
<p>Overall in my experience I would say that since being introduced to ping-pong pairing my learning has been far more effective. Although it can be intimidating at first, especially for someone who wasn't familiar with unit testing when I first started at Zuto, once I got into the flow and increased my confidence in asking questions it was quite enjoyable!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Zuto-Twilio Hackathon: First look at Twilio Studio]]></title><description><![CDATA[<div class="kg-card-markdown"><p>During the two-day hackathon Team DC Comics  used a Twilio product called Studio Flow. This is a drag and drop style designer that allows you to create complex processes for multiple channels (Voice and SMS).</p>
<p>As a team we were working on the project which used SMS to promote callback</p></div>]]></description><link>https://tech.zuto.com/first-look-at-twilio-studio/</link><guid isPermaLink="false">60d9818ab2e3d200333ac826</guid><category><![CDATA[Twilio]]></category><dc:creator><![CDATA[Cameron Hughes]]></dc:creator><pubDate>Mon, 28 Jun 2021 16:37:48 GMT</pubDate><media:content url="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/06/cover.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/06/cover.png" alt="Zuto-Twilio Hackathon: First look at Twilio Studio"><p>During the two-day hackathon Team DC Comics  used a Twilio product called Studio Flow. This is a drag and drop style designer that allows you to create complex processes for multiple channels (Voice and SMS).</p>
<p>As a team we were working on the project which used SMS to promote callback success. We needed to trigger an outbound SMS by posting to an endpoint that Twilio generates when you create a studio flow. Using what is called a “Split based on” widget we can branch behaviour depending on what the customer sends back to us via SMS.</p>
<p>For example:</p>
<p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/06/splitbasedon.width-500.png" alt="Zuto-Twilio Hackathon: First look at Twilio Studio"></p>
<p>In our case we either send them another SMS, send the conversation to Autopilot, which is another Twilio product, or send a task to Flex.</p>
<p>There were many more widgets we could have used to create custom behaviour. For example, the “Http request” widget allows you to communicate with a third-party API to retrieve or post data. There are more widgets dedicated to the voice channel that allows you to do a bunch of cool stuff like, gathering input on a call, make an outgoing call and recording a voicemail.</p>
<p>Overall, it was really fun and intuitive to work with studio flow and I recommend people who work with Twilio to try it out if you haven’t already.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Zuto - Twilio Hackathon]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Last week, Zuto hosted it's first <em>ever</em> internal hackathon in partnership with Twilio.</p>
<p>It was an opportunity for software engineers from different squads at Zuto to work together, with many of us having not been able to meet in person yet due to lockdown. Along with the added bonus of</p></div>]]></description><link>https://tech.zuto.com/zuto-twilio-hackathon/</link><guid isPermaLink="false">60d2e545b2e3d200333ac813</guid><category><![CDATA[Twilio]]></category><category><![CDATA[Hackathon]]></category><dc:creator><![CDATA[Jade Kneen]]></dc:creator><pubDate>Tue, 22 Jun 2021 15:45:00 GMT</pubDate><media:content url="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/06/hackathon-1.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/06/hackathon-1.jpg" alt="Zuto - Twilio Hackathon"><p>Last week, Zuto hosted it's first <em>ever</em> internal hackathon in partnership with Twilio.</p>
<p>It was an opportunity for software engineers from different squads at Zuto to work together, with many of us having not been able to meet in person yet due to lockdown. Along with the added bonus of Twilio staff, from across the globe, providing support over the two days.</p>
<p>For the majority of participants this was going to be their first experience of a hackathon. But this didn't cause many issues as the organisers made sure to keep everyone up to date in the run up to, and throughout, the event.</p>
<p>As the UK is still in lockdown, the event had to be held remotely. The organisers set up various Zoom meetings which enabled teams to work seperately, along with a virtual help desk room for when anyone needed assistance with their project, any Twilio products, or later on, their presentations and demos.</p>
<p>Then there were the challenges. As with any good hackathon the challenges provided an end goal, while allowing the teams the freedom to decide how to go about getting there by using Twilio products.</p>
<p>So these challenges were:</p>
<ul>
<li>Improve the pipeline view</li>
<li>Improve the UI for task based working</li>
<li>Enable customers to self serve using SMS</li>
</ul>
<p>Each team was assigned one of these challenges.</p>
<p>Dan Smith, a senior Software Engineer at Zuto, was working with Team DC Comics - the winning team! - and had this to say about his experience:</p>
<blockquote>
<p>I haven’t done a hackathon before, not that I didn’t think they were a good idea, more that they seem to involve working solidly for 24 hours, and that just doesn’t appeal.</p>
<p>This hackathon therefore was a bit easier since it allowed time to rest. This is quite important since I found the hackathon to be intense, but in a good way.</p>
<p>As the focus of this hackathon was on Twilio products I worked with AutoPilot, Studio Flow and Twilio’s Functions as well as building a simple API to serve as a backend for the Functions to call.</p>
<p>One of the really good things about AutoPilot are the templates; these provide very good examples on how to achieve common tasks.</p>
<p>I also got more familiar with the improvements that Twilio have made to their Functions. These include the ability to group them together and an easy way to register dependencies.</p>
<p>Overall, I would say it was a positive experience, a little draining due to the intensity but nevertheless well worth doing.</p>
</blockquote>
<p>Similarly, Julian Monono (Principal Software Engineer at Zuto) from Team Pixel enjoyed the opportunity to learn more about Twilio products:</p>
<blockquote>
<p>As most of my day to day is focused on the priorities for our Mission, the hackathon was a good opportunity to step back and try something a bit more ‘radical’ within Twilio.</p>
<p>The hackathon was a good opportunity to learn some more about Twilio products we don’t currently use (e.g. Sync) and to work ‘cross-squad’ on a focused problem!</p>
<p>The two days were a lot of fun and I learned that;</p>
<ul>
<li>You <em>can</em> make Flex look pretty with the right styling!</li>
<li>Frontend is always fun!</li>
<li>Understanding something new during a hackathon can be tricky when you have a cold</li>
</ul>
</blockquote>
<p>And also an insight from Melvin Iwuajoku, another Senior Software Engineer at Zuto who was working with the Team The (Best) Team:</p>
<blockquote>
<p>I had done a few hackathons before. Though this one did not involve waking up with a sore neck after sleeping on the floor or a desk, it was just as intense and exciting!</p>
<p>Besides my machine deciding to &quot;take some time off&quot; just before the demo, it was a great two days collaborating across teams and I'm happy with what we achieved. We invested quite some time to understand the problem but once we got going it was great! Looking forward to the next one now.</p>
<p><strong>What did I learn?</strong><br>
Applying custom branding on Twilio Flex UI is challenging but looks great when it comes together.</p>
<p>The Twilio platform including Flex offers us so many opportunities to help our sales partners.</p>
</blockquote>
<p>A great aspect of hackathons is the opportunity to involve other people from the company who aren't software engineers. For example, Adam Bell, a Junior Product Owner at Zuto, was one of the organisers of the event and he had this to say about the two days:</p>
<blockquote>
<p>The hackathon was really useful from a product perspective as it really helped showcase what might be possible in the future with Twilio and the findings from the day have already started to shape our immediate roadmap!</p>
<p>My role for the day was fairly fluid and I was floating across each of the squads, it was great to see ideas flowing and the different ways each team approached the business problem they’d been given to solve.</p>
<p>Hackathons like this help us test out a new ideas and quickly understand how we might be able to help our customers moving forward!</p>
</blockquote>
<p>The three teams then presented their projects to the rest of the company during &quot;Friday Demos&quot;. We were able to get great feedback from colleagues, along with ideas about how each idea could be implemented and expanded in the future.</p>
<p>And there are already talks about the next one!</p>
</div>]]></content:encoded></item><item><title><![CDATA[5 Reasons You Should Be Using Storybook]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Starting a project from complete scratch is quite a daunting task to consider as a Junior Developer. So, when the Partners squad, made up of myself and Ste Jackson, were assigned the task of developing a brand-new application form for the Zuto website, it was hard to choose where to</p></div>]]></description><link>https://tech.zuto.com/untitled/</link><guid isPermaLink="false">60a7d38fb2e3d200333ac7ff</guid><dc:creator><![CDATA[Alexandra Brown]]></dc:creator><pubDate>Mon, 24 May 2021 14:11:29 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Starting a project from complete scratch is quite a daunting task to consider as a Junior Developer. So, when the Partners squad, made up of myself and Ste Jackson, were assigned the task of developing a brand-new application form for the Zuto website, it was hard to choose where to begin!</p>
<p>As you can imagine, the only way you can tackle a mammoth project like this is with careful planning and strategic organisation of both your workload and the many different components your code base will be made up of.</p>
<p>Thankfully, we came across Storybook: a Sandbox environment and open-source tool for UI development.</p>
<p>With this handy software, no longer did we have to monotonously check through every component’s functionality or see how they affected the main application. Now we had the tools to create and test our components as they would appear in the application before any real development work began.</p>
<p>Storybook was so integral to our process that it made me question how you could create a front-end development project without it. For that reason, I want to share 5 pros of using Storybook.</p>
<h3 id="1itsaninteractiveplaygroundforuicomponents"><strong>1. It’s an interactive playground for UI components</strong></h3>
<p>One of the main benefits of Storybook is that it allows you to create components that are interactive rather than static. You can live-edit your creations, play around with the display and view how they would render in different ways.</p>
<p>For example, when we created our Button component for the application form, we had to consider the many different states it would include. Thankfully, Storybook offers Addons which expand the environment and allow a user to customise tools to fit in with their needs.</p>
<p>With the Controls addon, we were able to interact with the Button component without the need to code - we could determine appropriate modifications such as the Button variant, size, subtext, icon and whether it was disabled. Take a look…</p>
<p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/Picture4.png" alt="Picture4"></p>
<p>By selecting different options in the dropdown menus or by inputting our choice of text, we were able to render whatever style of Button we liked immediately onto the page, without affecting the larger application.</p>
<h3 id="2youcantestinisolation"><strong>2. You can test in isolation</strong></h3>
<p>This brings me nicely to another benefit of using Storybook — the ability to test and develop your components separately to the application, meaning project dependencies will not affect the behavior of components.</p>
<p>We found it extremely useful having a platform like Storybook isolated from the rest of our application as we could safely play around with component design and functionality without worrying about any pages being disrupted. That being said, as much as the platform was separate, it was also incredibly easy to integrate within our React application when needed.</p>
<p>Not only that, Storybook works with most of the other front-end frameworks too!</p>
<h3 id="3allowsforrapiduidevelopment"><strong>3. Allows for rapid UI development</strong></h3>
<p>Using Storybook hugely cut down our development time. This was due to the speed in which you can create components and how easy the software is to set up.</p>
<p>We used Storybook to create our components in real-time, which was aided by hot module reloading; whenever we made a modification, the module was replaced without the whole page reloading. This instant gratification helped us a lot and made sure we could design each component perfectly before integrating it within the rest of our app.</p>
<p>Additionally, the process of building a new story within our project was super simple and once we’d implemented one, we could easily tackle the rest without any (many…) hiccups. If you want to read more about implementing stories, you can do so here: <a href="https://storybook.js.org/docs/react/get-started/setup">https://storybook.js.org/docs/react/get-started/setup</a></p>
<h3 id="4addhandydocumentationforotherdevelopers">4. Add handy documentation for other developers</h3>
<p>With each story you make, you have the option to integrate the Docs addon, which allows you to add high quality documentation to your components.</p>
<p>We chose to incorporate this as we wanted to add in-depth documentation so that any other developer could access Storybook and immediately understand each of the component's capabilities and usages.</p>
<p>For example, we set up a design for our Grid layout within Storybook, which wasn’t quite as self-explanatory as some of our other components. For this reason, having the Docs addon right alongside the Grid canvas gave us the ability to describe exactly what was going on and how our app form layout was structured.</p>
<p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/Picture2.png" alt="Picture2"></p>
<p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/Picture3.png" alt="Picture3"></p>
<p>We believe this will be a handy tool for other engineers at Zuto and will save vital time in understanding components before you are able to work with them.</p>
<h3 id="5greatuiforgreatui">5. Great UI for great UI</h3>
<p>Finally, what more do you expect from a design tool created for building clean and pleasing user experiences, than an easy-to-use, aesthetically pleasing UI?</p>
<p>The organised and structured design of Storybook allows the user to focus on what matters most: building their components quickly and efficiently.</p>
<p>Storybook aids this process by separating your components accordingly, as well as organising the specified Addons you have implemented. It was due to this that we were able to showcase the atomic design principles that were vital to our approach of building the new app form.</p>
<p>With Storybook, we were able to easily demonstrate which components were classed as Atoms, Molecules and Organisms, and see clearly how they all interacted with one another. Not only did this help us during development, but it will make it easier for any future users to understand the thought processes behind our approach.</p>
<p>These many benefits that Storybook offer, including the rapid development process, the handy documentation for other developers and the clean UI, greatly improved our time and efficiency in building the new app form. As a developer, you’re always on the search for software and tools that will make your life easier, and Storybook offers exactly that! We hope to branch out this development tool into other areas at Zuto in the future. Follow this link if you would like to learn more about what Storybook has to offer: <a href="https://storybook.js.org/">https://storybook.js.org/</a></p>
</div>]]></content:encoded></item><item><title><![CDATA[My Zuto Journey: AWS Newbie to AWS Community Builder]]></title><description><![CDATA[Before starting at Zuto, I had used AWS once. But here I am, six months later, studying for my Associate Developer certification and selected for the AWS Community Builder program.]]></description><link>https://tech.zuto.com/beating-my-fear-of-aws/</link><guid isPermaLink="false">60539a82c163d500011bfe9a</guid><category><![CDATA[Amazon Web Services]]></category><dc:creator><![CDATA[Jade Kneen]]></dc:creator><pubDate>Tue, 18 May 2021 15:53:32 GMT</pubDate><media:content url="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/aws_logo-1.png" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/aws_logo-1.png" alt="My Zuto Journey: AWS Newbie to AWS Community Builder"><p>Before starting at Zuto in November 2020, I had used Amazon Web Services once. But here I am, six months later, studying for my Associate Developer certification and selected for the AWS Community Builder program.</p>
<p><strong>My first AWS experience</strong></p>
<p>My journey with AWS got off to a false start back in 2019. I had signed up for an Amazon sponsered hackathon which was being hosted by Code Nation in Manchester. I had no idea what to expect as I'd only been coding for a couple of months by this point.</p>
<p>We were told that one of the goals of the hackathon was to program an Alexa.</p>
<p>Now, I didn't even own an Alexa. Never mind not having any idea how to program one. But over the course of the weekend, the mentors introduced the team to AWS.<br>
<img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/aws_logo.png" alt="My Zuto Journey: AWS Newbie to AWS Community Builder"><br>
We did end up being awarded second place and although we didn't manage to get Alexa to respond to our commands, I did have one phrase stick in my head: <em>lambda functions</em>.</p>
<p>Fast forward a little over a year and I started my new role at Zuto. That's when I got my first experinece of working with AWS in a professional setting. Despite the niggling doubt in my mind from my first experience with AWS, I was fortunate that one of the Principle Developers at Zuto led an introduction to AWS course.</p>
<p>This course comprised of:</p>
<ul>
<li><strong>Session 1: Introduction to Cloud Computing</strong></li>
</ul>
<p>There were three junior developers in this first session, and it was focused on giving us an overall introduction. Covering topics like cloud computing (besides the memes pointing out that it is just someone else’s computer), Infrastructure As A Service and the standard resources available on the cloud. Due to lockdown, it was hosted virtually over Teams – though admittedly, I had to also cope with terrible wi-fi!</p>
<p>What did we do? We were shown how to install and check which version of the AWS Command Line Interface (CLI) we installed. We were shown how to configure an S3 bucket or object. And the most important part:  the monthly cost calculator, which enabled us to work out the costs of any requirements we might have when using AWS.</p>
<ul>
<li><strong>Session 2: Terraform and Deployment</strong></li>
</ul>
<p>The second session gathered more interest as it was an introduction to Terraform and deployment. This time around, there were several other developers and colleagues who joined wanting to understand this topic better.</p>
<p>As the experience levels were more varied than the previous session, we could benefit from hearing questions from other people and even solutions.</p>
<p>Due to the topic and amount of people taking part, I found the session moved a lot quicker than the previous one. However, a GitHub repository contained katas that we could work on and notes for each great section.</p>
<p>And if nothing else, I will also remember the most important command: terraform destroy.</p>
<p><strong>Continuing to work with AWS</strong></p>
<p>As more people have been recruited to work at Zuto, and the AWS training plan is sorted out going forward, I've been able to continue learning while working on tickets with my squad. As I knew it was one of my weakest areas, I set my quarterly PDP goals as &quot;continue learning AWS&quot;.</p>
<p>That's when the Tech Lead suggested that I should research the AWS certifications. I had seen these on LinkedIn but I had never considered it would be something I would do. But we agreed that it would be a good target for me to focus on that quarter so I have been studing towards the Associate Developer certification.</p>
<p><strong>Applying to become an AWS Community Builder</strong></p>
<p>The goal must have been what I needed as I found myself applying to the AWS Community Builder program after seeing it shared on Twitter. I knew it would be competitive as it took into account technical writing skills such as blog posts, social media presence and AWS knowledge.</p>
<p>But two months later I got the email confirming that I was one of the 26% who had been selected for the program!</p>
<p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/Community-Builder-logo-for-light-background.png" alt="My Zuto Journey: AWS Newbie to AWS Community Builder"></p>
<p><strong>My resources for learning about AWS</strong></p>
<ul>
<li><a href="https://docs.aws.amazon.com/index.html?nc2=h_ql_doc_do">AWS documentation</a> - this is where you will find the main resources. These have been split down into the individual areas of AWS which makes it easier to navigate.</li>
<li><a href="https://app.pluralsight.com/paths/certificate/aws-certified-developer-associate">PluralSight Certification Pathway</a> - if you have a subscription, I have found the tutorials and courses included in this pathway to be invaluable as it really breaks things down.</li>
<li><a href="https://aws.amazon.com/certification/certification-prep/?th=cta&amp;cta=header&amp;p=2">AWS Training and Certification</a> - like the documentation this will give you the training materials that Amazon has set up.</li>
<li><a href="https://www.youtube.com/user/amazonwebservices">AWS Youtube</a> - AWS also has a YouTube channel for anyone who prefers watching rather than reading!</li>
<li><a href="https://www.udemy.com/topic/aws-certification/?utm_source=adwords&amp;utm_medium=udemyads&amp;utm_campaign=Branded-Topic_la.EN_cc.UK&amp;utm_content=deal4584&amp;utm_term=_._ag_119656556043_._ad_510123282944_._kw_aws%20training%20udemy_._de_c_._dm__._pl__._ti_kwd-1203951217841_._li_1007043_._pd__._&amp;matchtype=e&amp;gclid=CjwKCAjwy42FBhB2EiwAJY0yQqSgrTlow0WcvXHcjceKTmtxtXNv8Qg-fRtWD7NKHP9BfycjOKTvvBoCf8sQAvD_BwE">Udemy AWS Courses</a> - while I haven't personally used Udemy for my learning, I have heard positive feedback from people who have used these courses.</li>
<li><a href="https://www.linkedin.com/learning/search?keywords=Amazon%20Web%20Services%20(AWS)">LinkedIn Learning AWS</a> - for anyone who has access to LinkedIn Premium there are also the LinkedIn Learning resources which are available.</li>
<li><a href="https://aws.amazon.com/">AWS Free Tier</a> - my main advice to anyone wanting to learn though is to sign up for their own account. I've found it really helpful to be able to put what I am learning into practice. Just remember to delete everything once you're done and to set up monthly cost budgets to avoid any charges.</li>
</ul>
</div>]]></content:encoded></item><item><title><![CDATA[Zuto on a Pi]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Hello!</p>
<p>I'm Michael Horsley and I'm one of the software engineers at Zuto.</p>
<p>This is hopefully the first post in a series of ramblings around seeing if I can run a copy of Zuto APIs off a cluster of Raspberry Pi.</p>
<p>The posts will generally be split between a wordy</p></div>]]></description><link>https://tech.zuto.com/zuto-on-a-pi/</link><guid isPermaLink="false">605b231fc163d500011bfeb0</guid><dc:creator><![CDATA[Michael Horsley]]></dc:creator><pubDate>Fri, 09 Apr 2021 17:32:04 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Hello!</p>
<p>I'm Michael Horsley and I'm one of the software engineers at Zuto.</p>
<p>This is hopefully the first post in a series of ramblings around seeing if I can run a copy of Zuto APIs off a cluster of Raspberry Pi.</p>
<p>The posts will generally be split between a wordy bit explaining what I intended to do/why and then a step-by-step walking through of how it was done.</p>
<p>This one will be a bit more wordy, as it'll include an introduction about why I'm doing this and then setting up a Pi Cluster.</p>
<p>If you're here for tech, as I'm sure some are, skip ahead to section &quot;Less talk more cluster&quot;</p>
<p><em>I wonder if Zuto would run on a Raspberry Pi?</em></p>
<h3 id="whyraspberrypi">Why Raspberry Pi?</h3>
<p>Well, mostly in an continuing effort to justify how much I spend on tech to myself and my partner <em>(mostly the partner)</em> I thought this would make great use of any Raspberry Pis I had already, as well as save some cost on hosting in AWS.</p>
<h4 id="couldyouhavenotjustusedthecloud">Could you have not just used the cloud?</h4>
<p>Oh absolutely, and for anything that's even remotely important or has any service-level agreement requirements, I'd go cloud based every time.</p>
<p>Kubernetes in the cloud has progressed really well in the last couple of years. From AWS EKS or Googles Cloud Platform managing your cluster to orchestrators such as Rancher <em>(<a href="https://rancher.com/">https://rancher.com/</a>)</em> it all makes getting your docker images and containers up and running on the cloud has been made much simpler, because providers have abstracted a lot of the complicity/maintenance away from the user.</p>
<p>However I feel this often skips a lot of the learnings and appreciations that engineers gain from having to deal with the original pain of getting it all working without these helpful services.</p>
<p>Also as costs of cloud RAM and Cores reduce over time, engineers and companies seem to have less enthusiasm around optimising either memory and CPU usage, as it returns less value then releasing new features or focusing on code.</p>
<p>Working with a Pi cluster brings a very fixed amount of usable resources, bringing with it a challenge to see if you can squeeze everything out of the running applications and forcing you to constantly monitor the running pods.</p>
<p>Another bonus of a Pi cluster would be if I could get it all completely self contained within my home network, the idea of having a fully contained bubble sounds like fun, for both development and testing. However this might be difficult with some existing services that exist purely within the AWS realm.</p>
<p>This might even open up the ability to spin up dev environments for each of the engineering teams allowing them to work independently of the other teams without the extra cost would be caused in the cloud.</p>
<h4 id="whatareyouhopingtogain">What are you hoping to gain?</h4>
<p>Mostly a better understanding of data flow through Zutos APIs, I've been with Zuto a little over 3 months at time of writing and while I've built somewhat of an understanding of the applications I work with day-to-day, I've got no doubt I'm missing a lot of infrastructural knowledge.</p>
<p>By converting each application into the Pi cluster and then it's connecting applications, I'll have to understand what is going on and each flow throughout the system.</p>
<p>I may be able to optimise the applications to get everything running on the cluster. This will hopefully improve Zutos cost margins, as we scale these will only increase, so any benefit here will hopefully compound later down the line.</p>
<h3 id="whyk3s">Why K3s</h3>
<p>K3s is a lightweight version of Kubernetes, perfect for a Raspberry Pi Cluster and supports ARM. It comes bundled with fairly little but does include Ingress <em>(that'll handle the API requests)</em> and a Control plane <em>(that'll control where our running applications sit in our cluster)</em>.</p>
<p>The other main option for Raspberry Pi is MicroK8s which boasts, among other things, high-availability.</p>
<p>I chose K3s over MicroK8s mostly because I struggled to get a basic .Net Core application running within the cluster, almost certainly something daft I've done but it was difficult to try and find any tutorial or guide that showed me how to piece together an Ingress or any other routing option into an usable setup.</p>
<p>If someone has a good tutorial or walk through I'd be happy to try it out, one joy of the Pi cluster is I can rebuild it fairly quickly now.</p>
<h3 id="thecluster">The Cluster</h3>
<p>So I'm going to using a 3 node Cluster consisting of 1 Raspberry Pi 4 A (4GB model) and 2 Pi 4 B (8GB models) making it one primary and 2 secondary nodes. The primary node by default will act as the control plane while the 2 secondaries will run my applications, however you should be able to follow along with even a single Raspberry Pi <em>(Ideally RPi 4B models, however 4A should work as well)</em>.</p>
<h1 id="lesstalkmorecluster">Less talk more cluster</h1>
<p>For the following you'll need this;</p>
<ul>
<li>Raspberry Pi 4 with power supply</li>
<li>SD Card and SD card USB Reader</li>
<li>Desktop or Laptop to image the SD cards</li>
<li>Raspberry Pi Imager <em>(I've grabbed it from here <a href="https://www.raspberrypi.org/software/">https://www.raspberrypi.org/software/</a>)</em></li>
<li>SSH Keys generated on your machine <em>(you will most likely already have these if you use GitHub, to check, go to your user directory and see if there's an .ssh folder, it might be hidden. If not, run <code>ssh-keygen</code> within command prompt and follow the instructions)</em></li>
<li>[Optional] Lens for Kubernetes <em>(<a href="https://k8slens.dev/">https://k8slens.dev/</a>)</em> This is optional but will give you a nice GUI that'll display information about your cluster</li>
</ul>
<p>In my commands to run, I'll either denote them as Desktop or Pi or Pi Primary, if you are following along, copy everything after the <code>$</code></p>
<p>So if my command was <code>Desktop $ ssh ubuntu@ubuntu</code> this means, from my desktop machine I would run the command <code>ssh ubuntu@ubuntu</code>, hopefully that makes sense. This will hopefully make things easier later in the step-by-step when I switch between the primary/secondary nodes and my desktop for Helm.</p>
<p>The <code>Pi</code> and <code>Pi Primary</code> are for dealing with multiple Pi, if you're using only 1 Pi then skip the &quot;Setting up our secondary Pi Node(s)&quot; section.</p>
<h3 id="settingupabaseubuntupi">Setting up a base Ubuntu Pi</h3>
<ol>
<li>
<p>Take the SD card and place it into your card reader and place that into your computer</p>
</li>
<li>
<p>Open up the Raspberry Pi Imager</p>
</li>
<li>
<p>Go to <code>Ubuntu</code> and then select <code>Ubuntu Server 21.04 (RPi 3/4/400) 64-bit server OS for arm64 architectures</code></p>
</li>
<li>
<p>Then select your SD card</p>
</li>
<li>
<p>Click Write</p>
<ul>
<li>This can take up to 10 minutes or so to write and then verify, depending on your USB port and Cards write speed</li>
<li>Once that is done it should have already safely ejected the mount, however if not, do this yourself before taking the reader out of your computer</li>
</ul>
</li>
</ol>
<h4 id="optionalstepsforwifi">[Optional Steps For Wifi]</h4>
<p>If you would like your Pi to use Wifi on boot like I did, use the following, otherwise skip steps 6 - 10 if you have an Ethernet Cable connected to the Pi</p>
<ol start="6">
<li>
<p>Place the reader back into your PC to get the folder prompt back, we have some files we need to alter</p>
</li>
<li>
<p>Open up the drive disk view and select <code>system-boot</code></p>
</li>
<li>
<p>Open the <code>network-config</code> file in a text editor</p>
</li>
<li>
<p>Remove the commented out lines under the ethernet section and replace it with something like my example</p>
</li>
</ol>
<ul>
<li>just remember to be careful, this is yaml and it uses spaces, tabs will not work here and it's 2 spaces for indentation</li>
<li>put your wifi name with &quot; &quot; surrounding it, just like your password</li>
<li>An example is below;</li>
</ul>
<pre><code>version: 2
ethernets:
  eth0:
    dhcp4: true
    optional: true
wifis:
  wlan0:
    dhcp4: true
    optional: true
    access-points:
      &quot;my-wireless-network-name&quot;:
        password: &quot;my-network-password&quot;
</code></pre>
<ol start="10">
<li>Safely eject the SD Card from your machine</li>
</ol>
<h4 id="endofoptionalstepsforwifi">[End of Optional Steps For Wifi]</h4>
<ol start="11">
<li>Plug the SD card into your Pi and power it up</li>
</ol>
<ul>
<li>Wait a couple of minutes and then open up a terminal, I personally use Git Bash (<a href="https://gitforwindows.org/">https://gitforwindows.org/</a>), we are going to ssh into our PI now</li>
</ul>
<ol start="12">
<li>You can ssh into your Pi either via its hostname like so or by it's IP</li>
</ol>
<ul>
<li><code>Desktop $ ssh ubuntu@ubuntu</code></li>
</ul>
<p>since the default host should be ubuntu or you should be able to get it via it's IP address, there's a few ways to find out the Pi IP address, I usually open up my wifi router's home page and look for it there. Hopefully ubuntu should work as a host name but that might depend on your routers settings</p>
<ol start="13">
<li>When prompted to add the key fingerprint type <code>yes</code></li>
</ol>
<ul>
<li>the default password is <code>ubuntu</code> unless you changed it within the user-data file previously</li>
</ul>
<ol start="14">
<li>It should now ask us to reset the ubuntu user's password, follow the prompts to create a new password for this user, type what you want but remember it</li>
</ol>
<ul>
<li>completing this step will kick us out of the ssh session</li>
</ul>
<ol start="15">
<li>[Optional] If you have already set up ssh keys and would like to log into the Pi via them rather than a username/password, do the following from your machine</li>
</ol>
<ul>
<li><code>Desktop $ ssh-copy-id ubuntu@ubuntu</code></li>
<li>enter in the password you set in the previous step</li>
<li>now when we ssh into the PI, we won't get asked for a password</li>
</ul>
<ol start="16">
<li>ssh back into the PI</li>
</ol>
<ul>
<li><code>Desktop $ ssh ubuntu@ubuntu</code></li>
</ul>
<ol start="17">
<li>Run the following</li>
</ol>
<ul>
<li><code>Pi $ sudo sed -i '1s/^/cgroup_enable=memory cgroup_memory=1 /' /boot/firmware/cmdline.txt</code>
<ul>
<li>? what does this command do? this allows resource management to restriction memory usage, when installing K3s, the service will not start if this part isn't configured correctly</li>
</ul>
</li>
</ul>
<ol start="18">
<li>Set the hostname of the pi, don't have this collide with any hostnames already defined on your network <em>(so I use node1, node2, node3 etc)</em>.</li>
</ol>
<ul>
<li><code>Pi $ sudo hostnamectl set-hostname node1</code></li>
</ul>
<ol start="19">
<li>Then reboot</li>
</ol>
<ul>
<li><code>Pi $ sudo reboot</code></li>
</ul>
<ol start="20">
<li>
<p>Ssh back into the Pi once it's booted <code>Desktop $ ssh ubuntu@node1</code> //or whatever you changed the host to</p>
</li>
<li>
<p>Run package updates, it's always good to keep it up to date for security updates</p>
</li>
</ol>
<ul>
<li><code>Pi-Primary $ sudo apt -y update &amp;&amp; sudo apt dist-upgrade</code>
<ul>
<li>this takes a while</li>
<li>on the version that I am running, it will warn you that there's a new version of the kernel and it will need to restart some services, just hit Enter, you'll see two different screens that look something like this;<br>
<img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/warning_1.jpg" alt="warning_1"></li>
</ul>
</li>
</ul>
<ol start="22">
<li>Finally reboot after that's done</li>
</ol>
<ul>
<li><code>Pi $ sudo reboot</code></li>
</ul>
<p>You now have base set up of the Raspberry Pi, however we don't yet have K3s on it. The previous steps are the same for all nodes within our cluster</p>
<p>Now it diverges slightly, on your Primary Pi node do the following</p>
<h2 id="settingupourprimarypinode">Setting up our primary Pi Node</h2>
<ol>
<li>Let's get K3s</li>
</ol>
<ul>
<li><code>Pi-Primary $ curl -sfL https://get.k3s.io | sh -</code></li>
</ul>
<ol start="2">
<li>Once that's done, run</li>
</ol>
<ul>
<li><code>Pi-Primary $ sudo kubectl get nodes</code>
<ul>
<li>this should return them as ready, if not, wait a few minutes and try again, failing that, double check the cgroup_enable and cgroup_memory to make sure they are correct</li>
</ul>
</li>
</ul>
<h2 id="settingupoursecondarypinodes">Setting up our secondary Pi Node(s)</h2>
<p>Assuming you've repeated steps 1-22 for all the generic setting up of Ubuntu, we don't run the same curl command as our primary for all our secondaries, instead we install and connect our Pi(s) to the primary node by doing the following;</p>
<ol>
<li>On the primary node run the following</li>
</ol>
<ul>
<li><code>Pi-Primary $ sudo cat /var/lib/rancher/k3s/server/node-token</code>
<ul>
<li>this will spit out a token, copy that for the next command</li>
</ul>
</li>
</ul>
<ol start="2">
<li>ssh into your secondary nodes and run the following, using the token generated from step 1</li>
</ol>
<ul>
<li><code>Pi-Secondary $ export K3S_URL=&quot;https://node1:6443&quot; &amp;&amp; export K3S_TOKEN=&quot;&lt;TokenCopied&gt;&quot; &amp;&amp; curl -sfL https://get.k3s.io | sh -</code>
<ul>
<li>Replacing the hostname <code>node1</code> if you used something different</li>
<li>Replace '<tokencopied>' with the token from step 1</tokencopied></li>
<li>Don't forget to copy the little <code>-</code> at the end, it's part of the command</li>
</ul>
</li>
</ul>
<ol start="3">
<li>After a few minutes you should be able to run <code>Pi $ sudo kubectl get nodes</code> on any of the Raspberry Pi to see the nodes as ready.</li>
</ol>
<p>And there we go, we have a running cluster!</p>
<p>But we don't want to have to SSH into the Raspberry Pi everytime we want to deploy something or run any kubectl commands.</p>
<h2 id="runningkubectlcommandswithoutsshingintotheclustereverytime">Running Kubectl commands without SSH'ing into the cluster everytime</h2>
<p>For this we'll want to grab the Kube Config from the Primary Node, and then copy it to our main machine, this will allow us to run the kubectl commands outside of our cluster.</p>
<ol>
<li>Create a new folder within your user directory on your main machine called <code>.kube</code></li>
</ol>
<ul>
<li>For example mine could then become <code>C:\Users\michael.horsley\.kube</code></li>
</ul>
<ol start="2">
<li>
<p>Within this directory create a new extentionless file called <code>config</code></p>
</li>
<li>
<p>Open a terminal and SSH into the Primary Pi node</p>
</li>
</ol>
<ul>
<li><code>Desktop $ ssh ubuntu@node1</code>
<ul>
<li>my Primary Pi host is node1</li>
</ul>
</li>
</ul>
<ol start="4">
<li>Print the K3s kube config to the terminal</li>
</ol>
<ul>
<li><code>Primary $ sudo cat /etc/rancher/k3s/k3s.yaml</code></li>
</ul>
<ol start="5">
<li>
<p>Copy that from your terminal and then paste that into the config file we created in step 2</p>
</li>
<li>
<p>Open the <code>config</code> file and around line 5 there is a bit of text <code>server: https://127.0.0.1:6443</code> change the 127.0.0.1 to your nodes hostname or IP address</p>
</li>
</ol>
<ul>
<li>Mine would become <code>https://node1:6443</code></li>
</ul>
<ol start="7">
<li>Save that file and then re-open the terminal and try getting the cluster nodes</li>
</ol>
<ul>
<li><code>Desktop $ kubectl get nodes</code></li>
</ul>
<ol start="8">
<li>Now hopefully you'll be able to see all your nodes and we've done this outside of our cluster! No more needless SSH'ing back in to run commands. This'll become important for when we want to deploy applications into our cluster.</li>
</ol>
<ul>
<li>If this step fails, try using the IP address instead of the hostname when updating the kube config file</li>
</ul>
<ol start="9">
<li>[Optional step for Lens] Getting Lens set up with our cluster is now as easy as clicking to add a new Cluster and then selecting our <code>config</code> file. Lens should then connect and you'll be able to browse around the namespaces and contexts, we aren't running anything yet so it'll be a little empty.</li>
</ol>
<p>Here's a link to a kubectl cheat sheet I will often refer back to since it's hard to remember all the commands <em>(<a href="https://kubernetes.io/docs/reference/kubectl/cheatsheet/">https://kubernetes.io/docs/reference/kubectl/cheatsheet/</a>)</em></p>
<h1 id="nextsteps">Next steps</h1>
<p>My next steps are to start moving over the Api applications and their dependencies, I'll be doing this one at a time but first I'll need to figure out which ones to move.</p>
<h1 id="wrappingup">Wrapping up</h1>
<p>If you've made it this far then thank you, hopefully this post will at least have been interesting and do let me know how your cluster went or if you have any general feedback or advice for my posts or my Pi cluster! My twitter handle is @Mike_Horsley</p>
</div>]]></content:encoded></item><item><title><![CDATA[Landing My First Job as a Software Engineer]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Looking back, I still find it hard to believe how far I have come in such a short amount of time. From taking the leap into software development just five months ago and embarking on a 14-week intensive coding bootcamp at Northcoders, I kicked off 2021 with a bang and</p></div>]]></description><link>https://tech.zuto.com/landing-my-first-job-as-a-software-engineer/</link><guid isPermaLink="false">60539b92c163d500011bfe9c</guid><dc:creator><![CDATA[Alexandra Brown]]></dc:creator><pubDate>Fri, 09 Apr 2021 13:31:46 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Looking back, I still find it hard to believe how far I have come in such a short amount of time. From taking the leap into software development just five months ago and embarking on a 14-week intensive coding bootcamp at Northcoders, I kicked off 2021 with a bang and started my first job as a Junior Software Engineer. It still seems crazy that I managed to achieve something like this, especially during a global pandemic, and I am excited to see where this journey will take me going forward. For now, though, I wanted to share my experience and what I have learnt from starting my role as a Software Engineer at Zuto.</p>
<p>As I approached the end of my time at Northcoders, I was all set to embark on the gruelling journey into finding my first job. I put time and effort into my LinkedIn profile and mentally prepared myself for the endless amount of tech tests and inevitable rejections that were coming my way. However, just before I officially graduated, I was approached by Zuto, who had read about my coding experience on my tech blog and wanted to invite me to interview. It seemed too good to be true — an interview without all the stress and hassle of an application? But nevertheless, a couple of days later I was interviewing for the role whilst simultaneously finishing off my final Northcoders’ project. By the end of the week I was offered the job and I couldn’t believe it. I was so grateful that Zuto saw the potential in me and wanted to offer a soon-to-be coding bootcamp graduate a chance.</p>
<p>As much as I was excited to get my teeth into my first professional role, I was also trying to overcome the fear and anxiety that came with starting a new job in an industry that I had never worked in before. I couldn’t shake the fact that my only experience of coding had been at Northcoders, where I had been cooped up in my room doing the whole thing online. To think I would be removed from this bubble, working on something that would impact a real-life company, was very daunting and something that took me a while to digest. That familiar feeling of imposter syndrome was creeping up on me and I was already telling myself that I would be the most inexperienced person there — I didn’t have a computer science degree and was still relatively new to software development. What if I was out of my depth?</p>
<p>Thankfully, my first week at Zuto managed to alleviate these concerns and calm my nerves. The whole week was dedicated to introducing me to the company, allowing me to get to grips with what they did and how they did it. This was extremely useful as I was able to get a sense of the bigger picture of the environment I would be working in and understand the day-to-day rather than being chucked in at the deep end straight away. Furthermore, it gave me the opportunity to get to know some of the other new starters who I would be working with. This really helped us to establish some grounding before immediately starting to work as a team — I can imagine this being extremely useful in the long run as we progress in our careers at Zuto.</p>
<p>After the induction week, we were set our first team project. This was a really nice way to get the new starters introduced to the way in which the tech teams at Zuto work and how they approach a task. Myself and Phoebe, two Junior Engineers, were able to work with Michael, a Senior Engineer. We were both guided through the project and received a lot of handy pointers on best practices as well as the general ‘do’s and don’ts’ when working with a company’s code. Zuto use C# for their backend development, a language I had not worked with before, so it was quite a challenge to approach a project in a coding language I was not familiar with. It can still be a lot to keep up with, but I am lucky enough to be supported by a team that is willing to put time and energy into my development and learning. I was able to get started on some online courses whilst simultaneously learning on the job via paired and mob programming; it was really reassuring to hear that the company would mould my training to what methods of learning suit me best.</p>
<p>What most impressed me when starting at Zuto was the sense of community that exists within the company. From day one, I was made to feel welcomed and accepted into the workplace, and even whilst the majority of us are working from home, I still feel as though I am connected to my team and everyone is supporting one another.</p>
<p>When I had initially been searching for a job, what mattered most to me was finding a company that would recognise my potential as a coding bootcamp graduate and give me the support to grow within my first role. With Zuto, I have found exactly that.</p>
<p>So what have I learned from my experience?</p>
<ol>
<li><em><strong>Don’t be hard on yourself</strong></em> - It is perfectly valid to be nervous when starting a new job, regardless of the industry. The only person you must overcome when feeling like this is yourself!</li>
</ol>
<p>2.<strong>Nobody expects you to know everything</strong> - It is your dedication and willingness to learn that matters most.</p>
<ol start="3">
<li><strong>Ask questions</strong> - This is the only way you can learn!</li>
</ol>
<p>I am excited to see what lies ahead in my career at Zuto and I can’t wait to learn more about the industry!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Welcome to Zuto's Tech blog]]></title><description><![CDATA[<div class="kg-card-markdown"><p>Hi there, and welcome to the blog.</p>
<p>As you can see, the blog focuses on technology at Zuto.</p>
<p>I thought that having the blog would give everyone the opportunity share their knowledge - without the pressure of talking in front of people. It also gives us something to look back</p></div>]]></description><link>https://tech.zuto.com/welcome-to-zutos-tech-blog/</link><guid isPermaLink="false">6058a57bc163d500011bfeac</guid><dc:creator><![CDATA[Jade Kneen]]></dc:creator><pubDate>Fri, 09 Apr 2021 08:24:13 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><p>Hi there, and welcome to the blog.</p>
<p>As you can see, the blog focuses on technology at Zuto.</p>
<p>I thought that having the blog would give everyone the opportunity share their knowledge - without the pressure of talking in front of people. It also gives us something to look back on in the future to see how things have changed and developed.</p>
<p>I want to invite everyone to write a post on areas in technology which might interest them. You might have an opinion on tech stacks, or new developments within Zuto or the general technological world.</p>
<p>Squads can share their successes.</p>
<p>Zutonites can share their stories.</p>
<p>Maybe you are learning something new in your 10% time and want to share your progress; who knows, you may also start a conversation or inspire others' to also try learning something new.</p>
<p>Get in touch if you would like to contribute or want to discuss any ideas.</p>
</div>]]></content:encoded></item><item><title><![CDATA[Building an IVR using Twilio]]></title><description><![CDATA[Blog post looking at how to use the Twilio REST API in .NET Core to provision a phone number as the starting point for an IVR]]></description><link>https://tech.zuto.com/building-an-ivr-using-twilio/</link><guid isPermaLink="false">5e679445dbe3240001ef639a</guid><category><![CDATA[Twilio]]></category><dc:creator><![CDATA[Zuto Tech Admin]]></dc:creator><pubDate>Fri, 13 Mar 2020 08:37:47 GMT</pubDate><media:content url="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/twilio-blog1-cover.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card-markdown"><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/twilio-blog1-cover.jpg" alt="Building an IVR using Twilio"><p>Firstly let me introduce myself - my name is Julian and I work on the Customer Engagement squad here at Zuto.</p>
<p>I started around three months ago and have really enjoyed getting to learn a new industry and business domain, and helping to deliver improvements to some of our underlying systems and processes.</p>
<p>Our squad is currently working on a really exciting project using the <a href="https://twilio.com">Twilio platform</a>. Twilio offer a range of solutions and APIs to help communicate with customers, such as APIs for;</p>
<ul>
<li>Sending and receiving emails and SMS</li>
<li>Making and receiving voice calls</li>
<li>Building realtime video applications</li>
</ul>
<p>And even services to allow you to build AI chatbots!</p>
<p><img src="https://media.giphy.com/media/mIZ9rPeMKefm0/giphy.gif" alt="Building an IVR using Twilio"></p>
<p>Twilio offer APIs that can make it easy to build your own contact centre - and in this set of blog posts I'm going to look at how you might build an Interactive Voice Response (IVR) using a number of Twilio APIs. So let's get started!</p>
<h2 id="sohowdowebuildanivr">So, how do we build an IVR?</h2>
<p>The first thing we need to do is create a Twilio account! Twilio offer a free trial account that offers a good amount of available credit - allowing you to try out lots of features. You can sign up for a Twilio trial account <a href="https://www.twilio.com/try-twilio">here</a>.</p>
<p>Once you have your Twilio account in place, you can sign in and visit the <a href="https://www.twilio.com/console">Twilio Console</a>. You should see something that looks similar to the screenshot below:</p>
<p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/twilio-dashboard.png" alt="Building an IVR using Twilio"></p>
<p>The Twilio Console is the hub that you will likely return to often, to view details of your services - and in our case details of your IVR.</p>
<h2 id="gettingstartedwithtwilio">Getting started with Twilio</h2>
<p>Now we have our Twilio account, we can start writing some code! First, we'll provision a phone number (you can't have an IVR without calling a number!) using Twilio's APIs. Whilst you could create all the resources we'll talk about in this blog using the Twilio Console, using their APIs is a nice way to get familiar with the APIs that underpin the platform. To that end we'll create a simple .NET Core (3.1) Console application that will allow us to look up an available phone number, and provision it on our account.</p>
<h3 id="creatingourtwilioconsoleapp">Creating our Twilio Console App</h3>
<p>Nothing too strenuous here - we'll just use the out of the box template for a C# Console app:</p>
<ol>
<li>Open Visual Studio 2019 and choose &quot;Create a new project&quot;</li>
<li>Select the &quot;C# Console App (.NET Core)&quot; template and select a location to store the solution</li>
<li>Call the project something snappy (SuperTwilioApp if you like!) and when prompted select .NET Core 3.1</li>
</ol>
<h2 id="provisioningaphonenumber">Provisioning a phone number</h2>
<p>Twilio provide a handy SDK that is a wrapper around the REST API used to manage Twilio resources. Our console app will make use of this to lookup available phone numbers and to actually buy a new phone number. In summary the steps we'll carry out are;</p>
<ol>
<li>Search for an available (local not international!) phone number that matches our requirements</li>
<li>Specify the address that will be associated with the phone number (this is for regulatory reasons, details of which can be found <a href="https://www.twilio.com/docs/phone-numbers/regulatory/faq">here</a>)</li>
<li>Buy the number!</li>
</ol>
<h3 id="keepitsecretkeepitsafe">Keep it secret, keep it safe!</h3>
<p>All interactions using the Twilio REST API first require us to initialise a <code>TwilioClient</code> instance, using some information specific to each Twilio account; namely our &quot;Account Sid&quot; and an &quot;Auth Token&quot;.</p>
<p>Add an <code>appsettings.json</code> file to the Console App project, with the following structure to represent our Twilio values (remembering to ensure it's copied to our output directory):</p>
<pre><code class="language-js">{
  &quot;Twilio&quot;: {
    &quot;AccountSid&quot;: &quot;This will be retrieved using User Secrets&quot;,
    &quot;AuthToken&quot;:  &quot;This will be retrieved using User Secrets&quot;
  } 
}
</code></pre>
<p>You'll notice that values for the <code>AccountSid</code> and <code>AuthToken</code> are not specified here. As these values give anyone with access to them the ability to create resources in your Twilio account (potentially costing you money!) we want to be careful with them. Therefore it makes sense to not store them directly in our code (or accidentally commit them to source control!), but to instead make use of the .NET <a href="https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-3.1&amp;tabs=windows">Secret Manager</a> tool that allows us to store secrets in a file called <code>secrets.json</code>. This file is stored in a system-protected, user specific location that is from the project tree (and is therefore not subject to source control).</p>
<p>The linked article details the various ways the Secret Manager can be initialised in a project, but Visual Studio 2019 offers a really handy shortcut - simply right-click the Console App project and select <strong>Manage User Secrets</strong> from the context menu. This will open up the <code>secrets.json</code> file in our IDE and adds the necessary <code>UserSecrets</code> configuration element to our <em>.csproj</em> file.</p>
<p>In the <code>secrets.json</code> file that opens up, add the following:</p>
<pre><code class="language-js">{
  &quot;Twilio:AccountSid&quot;: &quot;Your account sid here&quot;,
  &quot;Twilio:AuthToken&quot;:  &quot;Your auth token here&quot;
}
</code></pre>
<blockquote>
<p>NOTE: You'll notice that in this file the JSON structure we specified earlier is flattened.</p>
</blockquote>
<p>And finally edit the project and add the following environment variable for running the project in development:</p>
<p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/twilio-launchsettings.png" alt="Building an IVR using Twilio"></p>
<p>With this in place we can now write the code necessary to load up our configuration, and see how our secrets get nicely injected in.</p>
<h3 id="setupapplicationconfiguration">Setup application configuration</h3>
<p>To read the config from our <code>appsettings.json</code> file, we'll use a trimmed down version of the configuration builder code you've likely seen in an ASP.NET Core application;</p>
<pre><code class="language-csharp">private static IConfiguration BuildApplicationConfiguration()
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile(&quot;appsettings.json&quot;);

    if (IsDevelopmentEnvironment())
    {
        builder.AddUserSecrets&lt;Program&gt;();
    }

    return builder.Build();
}

private static bool IsDevelopmentEnvironment()
{
    var environment = Environment.GetEnvironmentVariable(&quot;NETCORE_ENVIRONMENT&quot;);
    return environment == &quot;Development&quot;;
}
</code></pre>
<p>The <code>IsDevelopmentEnvironment</code> method uses the environment variable we set up earlier to determine if we are running in dev, and if so add in the UserSecrets configuration source. This will ensure that our Twilio values get automagically replaced with their secret equivalents at runtime.</p>
<h3 id="phonenumbercompliancestuff">Phone number compliance stuff!</h3>
<p>Before we can buy a phone number, for regulatory purposes Twilio needs us to create an address that will be associated with that number. The code below shows how we can create a new address, if one doesn't already exist.</p>
<pre><code class="language-csharp">private static async Task&lt;string&gt; GetOrCreateAddress()
{
    var existingAddresses = await AddressResource.ReadAsync(limit: 20);

    if (existingAddresses.Any())
    {
        Console.WriteLine($&quot;No address created, existing address found with Sid: {existingAddresses.First().Sid}&quot;);

        return existingAddresses.First().Sid;
    }

    var createdAddress = await AddressResource.CreateAsync(
        friendlyName: &quot;My IVR Address&quot;,
        customerName: &quot;Mr E Guest&quot;,
        street: &quot;1 Guest Road&quot;,
        city: &quot;Guesttown&quot;,
        region: &quot;Guestshire&quot;,
        postalCode: &quot;GS1 1GS&quot;,
        isoCountry: &quot;GB&quot;);

    Console.WriteLine($&quot;Address created, with Sid: {createdAddress.Sid}&quot;);

    return createdAddress.Sid;
}
</code></pre>
<p>We can see that the Twilio API has the concept of an <a href="https://www.twilio.com/docs/usage/api/address"><code>AddressResource</code></a> which they use to represent an address. We use the <code>ReadAsync</code> method to fetch up to a number (twenty in this case) of addresses that may exist in our Twilio account. If we haven't yet created an address on our account, we use the <code>CreateAsync</code> method to create a new address.</p>
<blockquote>
<p>NOTE: I have used dummy address values here so substitute these as you see fit :-)</p>
</blockquote>
<p>Now we can use the address details to buy our phone number.</p>
<h3 id="buyingalocalphonenumber">Buying a local phone number</h3>
<p>Twilio provide the ability to search for locally available phone numbers using their REST API (via <a href="https://www.twilio.com/docs/phone-numbers/api/availablephonenumberlocal-resource"><code>LocalResource</code></a> requests). You can search for numbers that match several criteria, including area code, country code and the features the number supports (e.g. SMS). Once you have identified the number you want, you can use the <a href="https://www.twilio.com/docs/phone-numbers/api/incomingphonenumber-resource"><code>IncomingPhoneNumberResource</code></a> API to buy a specific number - supplying an appropriate address (which we created earlier).</p>
<p>The method below finds a local phone number and provisions the first in the list:</p>
<pre><code class="language-csharp">private static async Task&lt;string&gt; BuyLocalPhoneNumber(string addressSid)
{
    // Find local phone numbers for the Macclesfield area
    var availableLocalPhoneNumbers = await LocalResource.ReadAsync(
        contains: &quot;+441625&quot;,
        pathCountryCode: &quot;GB&quot;,
        voiceEnabled: true,
        smsEnabled: true,
        limit: 50);

    var numberToBuy = availableLocalPhoneNumbers.First();

    var boughtNumber = await IncomingPhoneNumberResource.CreateAsync(phoneNumber: numberToBuy.FriendlyName,
        addressSid: addressSid);

    return boughtNumber.Sid;
}
</code></pre>
<p>If we were to run this method as-is it would buy a new phone number every time. As we're on a limited budget it probably makes sense to only create a number if one doesn't already exist - so we wrap the <code>BuyLocalPhoneNumber</code> method in a method that first checks for an existing number on the account, using the <code>IncomingPhoneNumberResource</code> API:</p>
<pre><code class="language-csharp">private static async Task&lt;string&gt; GetOrProvisionIncomingPhoneNumber(string addressSid)
{
    var incomingPhoneNumbers = await IncomingPhoneNumberResource.ReadAsync(limit: 20);
    if (incomingPhoneNumbers.Any())
    {
        var existingIncomingPhoneNumber = incomingPhoneNumbers.First();

        Console.WriteLine($&quot;No phone number bought, existing incoming phone number found with friendly name: {existingIncomingPhoneNumber.FriendlyName} &quot; +
                            $&quot;and Sid: {existingIncomingPhoneNumber.Sid}&quot;);

        return existingIncomingPhoneNumber.Sid;
    }

    var incomingPhoneNumberSid = await BuyLocalPhoneNumber(addressSid);
    Console.WriteLine($&quot;phone number bought with Sid: {incomingPhoneNumberSid}&quot;);
    
    return incomingPhoneNumberSid;
}
</code></pre>
<h2 id="putitalltogether">Put it all together!</h2>
<p>We now have all the building blocks needed to buy a phone number - so we can update our console app to call the building blocks and actually get a phone number!</p>
<pre><code class="language-csharp">static async Task Main(string[] args)
{
    var config = BuildApplicationConfiguration();

    TwilioClient.Init(config[&quot;Twilio:AccountSid&quot;], config[&quot;Twilio:AuthToken&quot;]);

    string addressSid = await GetOrCreateAddress();
    string phoneNumberSid = await GetOrProvisionIncomingPhoneNumber(addressSid);
}
</code></pre>
<p>Once we run this we should see something similar to the following:</p>
<p><img src="https://s3-eu-west-2.amazonaws.com/tech-blog-ghost-images-prod/2021/05/twilio-buy-phone-number1.png" alt="Building an IVR using Twilio"></p>
<p>Now we can actually call the phone number to hear a pleasant voice telling us we have a trial account and that we should press any key to execute our code! If we do press a key we then get a standard Twilio demo voice message which shows us everything is working fine!</p>
<p><img src="https://media.giphy.com/media/x6WhgtmAIbgMU/giphy.gif" alt="Building an IVR using Twilio"></p>
<h2 id="summary">Summary</h2>
<p>In this post we setup our Twilio trial account and bought a phone number that will be the entry point to our IVR.</p>
<p>In the next post we'll look at how to create the API that will power our IVR, instead of just playing a slightly robotic message!</p>
</div>]]></content:encoded></item><item><title><![CDATA[Linux Password-less Authentication]]></title><description><![CDATA[<div class="kg-card-markdown"><h2 id="whatispasswordlessauthentication">What is Password-less Authentication?</h2>
<p>SSH Password-less Authentication is basically having the ability to log-on to another remote server without having to enter a password. This is particularly useful when you want to automate tasks/jobs such as zipping-up a directory by using a script, or even for remote command execution.</p></div>]]></description><link>https://tech.zuto.com/linux-password-less-authentication/</link><guid isPermaLink="false">5e667850dbe3240001ef6391</guid><category><![CDATA[Linux]]></category><category><![CDATA[Authentication]]></category><category><![CDATA[SSH]]></category><dc:creator><![CDATA[Zuto Tech Admin]]></dc:creator><pubDate>Fri, 02 Jun 2017 00:00:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card-markdown"><h2 id="whatispasswordlessauthentication">What is Password-less Authentication?</h2>
<p>SSH Password-less Authentication is basically having the ability to log-on to another remote server without having to enter a password. This is particularly useful when you want to automate tasks/jobs such as zipping-up a directory by using a script, or even for remote command execution.</p>
<p>You should consider using SSH password-less authentication when you are dealing with a number of remote servers. By adding public keys to a file, you can eliminate the whole process of exposing a password elsewhere.</p>
<p>Using Password-less authentication now means we don’t have to put our passwords in continuous integration. Therefore meaning that we don’t need to share passwords between team members, thus making the password less accessible.</p>
<h2 id="whystartusingpasswordlessauthentication">Why start using Password-less Authentication</h2>
<p>In some cases, you may need to use Password-less Authentication for running commands on a remote server. Before having Password-less Authentication setup on the server, you probably would have used a password that was being stored / remembered somewhere. This is not very secure as the password could easily be found. However, once you have setup the Password-less Authentication, the key is less accessible, therefore making it a lot more secure.</p>
<h2 id="passwordsvskeys">Passwords Vs Keys</h2>
<p>Passwords are strong right? Doing some research suggested that they can take seconds to crack if they do not contain any special characters, capital letters or numbers.</p>
<p>RSA Keys - It would take approximately 1.5 million years with a standard desktop machine to crack a 2048 bit key.</p>
<p>Passwords - It would take roughly 6 months with a standard desktop machine to crack a 10 character password containing special characters.</p>
<h2 id="howtosetitup">How to set it up</h2>
<p>First of all, you will need the SSH keys for the server that you’re using.</p>
<ul>
<li>Log onto the box you want to connect to</li>
<li>Navigate to <code>~/.ssh/</code></li>
<li>Copy the public key into the authorized_keys file by running this command <code>ssh-copy-id -i ~/.ssh/mykey user@host</code></li>
</ul>
<p>If the SSH keys need to be regenerated, then you will need to follow these steps:</p>
<ul>
<li>Logon to the box that you want to connect from</li>
<li>If it’s a different user, impersonate using<br>
<code>sudo su - username</code></li>
<li>In the home directory, run<br>
<code>ssh-keygen -r rsa</code></li>
<li>Don’t set a password</li>
<li>It will generate the file at <code>HomeDirectory/.ssh/id_rsa.pub</code></li>
<li>You will need the public key to be added to the box you want to connect to</li>
<li>You should now be able to ssh onto the box from the client machine, without the password.<br>
<code>e.g. ssh username@hostname dir</code></li>
</ul>
</div>]]></content:encoded></item></channel></rss>