<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Tania Allard</title>
    <description>The latest articles on Forem by Tania Allard (@trallard).</description>
    <link>https://forem.com/trallard</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F142264%2F5c6935f8-ce77-4ee0-8cbe-e7cd512c5942.jpeg</url>
      <title>Forem: Tania Allard</title>
      <link>https://forem.com/trallard</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/trallard"/>
    <language>en</language>
    <item>
      <title>Contributing to open source projects: contributors etiquette</title>
      <dc:creator>Tania Allard</dc:creator>
      <pubDate>Thu, 08 Oct 2020 12:25:49 +0000</pubDate>
      <link>https://forem.com/azure/contributing-to-open-source-projects-contributors-etiquette-1bdm</link>
      <guid>https://forem.com/azure/contributing-to-open-source-projects-contributors-etiquette-1bdm</guid>
      <description>&lt;p&gt;Welcome to the second article in the "Contributing to Open Source" series. &lt;br&gt;
In the &lt;a href="https://dev.to/azure/contributing-to-open-source-projects-let-s-get-us-all-started-13ff"&gt;previous post&lt;/a&gt; I covered some of the benefits of contributing to open source as well as some guidance on how to find projects and items (or issues) to work on.&lt;/p&gt;

&lt;p&gt;Open-source brings together people from all over the world to collaborate and find solutions to complex problems. &lt;br&gt;
This post aims to help you improve your communication and collaboration skills. And at the same time, help make our community friendlier and safe for us all.&lt;/p&gt;




&lt;h2&gt;
  
  
  Communication and people skills
&lt;/h2&gt;

&lt;p&gt;I have been contributing to open source for some years now, mainly because I love writing code and the communities I belong to. Over these years, I have had a mix of experiences and challenges. And in both cases, maintainers and fellow contributors have played a massive role in this. &lt;/p&gt;

&lt;p&gt;These are my top recommendations when it comes to communicating and collaborating with other folks or projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First thing first -  before opening an issue, creating a Pull Request familiarise yourself with the project's Contribution Guidelines and their Code of Conduct. Make sure you know what the existing communication channels are and use them accordingly (e.g. Gitter, Slack, Github issues, Discourse).
Read the documentation first - sometimes the answer is in the documentation. Go through the documentation and see if you can find an answer to your question.&lt;/li&gt;
&lt;li&gt;Before opening a new issue, make sure to check the existing ones, so you do not open a duplicate. If there is an open issue tackling the same problem you are reporting comment on it providing additional context.  If there are issues that are related, make sure to reference them in your newly created issue. Pro tip: avoid the urge of asking: why has this not been fixed yet? Or similar.&lt;/li&gt;
&lt;li&gt;If you open an issue that you are not able to resolve yourself, please add a note about this. That way, maintainers can label this issue accordingly (e.g. "help wanted", "needs discussion"). If possible work on a &lt;a href="https://css-tricks.com/reduced-test-cases/"&gt;reduced test case&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;When reporting issues or requesting features, please use the project's issue tracker. This allows for discussions to be open and visible to the broader community. Do not request features or raise issues by emailing/sending Twitter DMs to the maintainers.&lt;/li&gt;
&lt;li&gt;Keep your communications smart:

&lt;ul&gt;
&lt;li&gt;Only comment if you have something to add to the discussion.&lt;/li&gt;
&lt;li&gt;Always provide context - I mentioned this before but minimise the cognitive burden on maintainers and contributors by absorbing the complexity on their behalf. Make it explicit what is being asked of them.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Respect people's time - everyone has other responsibilities and need time to unwind and recharge their batteries.  Do not ask maintainers for an ETA or ask them to prioritise your issue. Sometimes issues go silent for a while (as PRs do) so if needed make use of a gentle "bump". This is asking for concrete actions in a respectful manner. "Do you have a couple of minutes to look at this PR?", "I am having trouble with this test - do you have any pointers on what I might have missed?". &lt;/li&gt;
&lt;li&gt;Avoid shaming/guilting - sometimes your PR will not align with the project's roadmap, others your feature request might not be relevant, or the extra effort might not outweigh the benefits. You might not get an immediate response because sometimes maintainers are overworked and burned out. Remember: folks often work on open source voluntarily. Public shaming them for not having X feature, pointing out how this other project is much better than this one or "how bad their API decisions are" does not benefit anyone. Be gracious and thank folks for their work, avoid sending emails or start Twitter rages when you are frustrated and cannot solve your issues. Instead, consider contributing your solution (when you get there) and move on.&lt;/li&gt;
&lt;li&gt;Avoid entitlement - always be respectful when providing feedback or suggestions. If there is something that could be improved and you can help with this, offer your help. &lt;/li&gt;
&lt;li&gt;Don't be a bystander - have you noticed something that is in clear breach of the Code of Conduct? Report this immediately so that maintainers can take care of this situation. Disagreements can quickly escalate into very nasty problems, so the best you can do here is bring it to the attention of the core developers as soon as possible.&lt;/li&gt;
&lt;li&gt;Avoid unnecessary discussions - maybe folks have decided to adopt a specific style guide or use a code formatter. Though this might not align with your personal preferences, avoid the urge to convince folks on why they should change their style guide.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Workflow ettiquete
&lt;/h2&gt;

&lt;p&gt;The next thing we can improve is our etiquette around the contribution itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the project has issues or Pull Request templates, please USE THEM. If it does not provide as much information as possible to help the maintainers and contributors:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Issues&lt;/strong&gt;: steps to reproduce the problem, details about your environment and OS, any steps you tried to fix the issue, command line outputs and/or screenshots are great additions too. If you have suggestions on how to solve this problem, make sure to add them also.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull Request&lt;/strong&gt;: what issue the PR relates to (use fixes/closes: ), what you did and how you tested your changes. Also, note if this introduces braking changes or requires dependencies upgrades. Make sure to also update the docs and add a note about this. If adding a new feature, make sure to add the relevant tests or edit existing ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature request&lt;/strong&gt;: though this is usually raised as an issue make sure to provide enough context about WHY this feature might be useful for the community (rather than only yourself). If you have ideas on how this could be implemented or what skills would be needed, make sure to point it out.    Pro tip: avoid asking questions like "Why does this do not exist already?"&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Ask for feedback early - as soon as you start working on a fix or feature create a PR and mark it as Work in Progress (WIP) on the title. If you get feedback early, it will be easier to align your work with the project vision, and you can ensure your PR will be merged.&lt;/li&gt;
&lt;li&gt;Use descriptive commit messages - "Fixes issue" does not provide context nor describe what you did "Ensure the correct variable is referenced" is a much better message.&lt;/li&gt;
&lt;li&gt;One issue one PR - make sure that your Pull Request tackles one single issue. This makes it easier for others to review your work and provide feedback. It also makes it easier to keep changelogs consistent.&lt;/li&gt;
&lt;li&gt;As soon as you decide to work on an issue, make sure to explicitly say you will work on it. This helps others to know what issues are actively being worked on without stepping on each others' toes.&lt;/li&gt;
&lt;li&gt;Familiarise with &lt;a href="https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow"&gt;Gitflow&lt;/a&gt; and/or with the contribution guidelines for the project.&lt;/li&gt;
&lt;li&gt;Ask first - if you are planning to submit a huge PR to a project to which you do not contribute regularly, ask the maintainers first. Make sure that what you are planning to do aligns with their project roadmap or vision. If this can be split in smaller PR's, make sure to do this.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is all for now. Do you have any other suggestions I missed in here? Make sure to add them to the comments.&lt;/p&gt;

&lt;p&gt;And keep your eyes peeled for the third post on this series "What makes a good and meaningful contribution to open source projects?".&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>opensource</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Contributing to open source projects: let's get us all started</title>
      <dc:creator>Tania Allard</dc:creator>
      <pubDate>Mon, 28 Sep 2020 17:50:35 +0000</pubDate>
      <link>https://forem.com/azure/contributing-to-open-source-projects-let-s-get-us-all-started-13ff</link>
      <guid>https://forem.com/azure/contributing-to-open-source-projects-let-s-get-us-all-started-13ff</guid>
      <description>&lt;p&gt;Have you always wanted to contribute to Open Source but do not know how to get started? Are you preparing to participate in Hacktoberfest? Well, look no more, because in these series you will learn how to do your first contribution to open source. &lt;/p&gt;

&lt;p&gt;In this first part of the series, we will cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Motivations to contribute to Open Source&lt;/li&gt;
&lt;li&gt;How to get started with your contributions &lt;/li&gt;
&lt;li&gt;What to look for in an Open Source project &lt;/li&gt;
&lt;li&gt;Getting ready to contribute&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why contributing to open source?
&lt;/h2&gt;

&lt;p&gt;I am a long-time open source user and contributor. So much of my work relies on open-source software. Also, belonging to open source communities has definitely opened many doors and opportunities for me in the past. Some reasons you might want to contribute to open source are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It can be a rewarding experience:&lt;/strong&gt; knowing that you helped fix a pesky issue or improve the documentation for the libraries that you use can be quite satisfying and benefit a bunch of folks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is an excellent way to learn new skills:&lt;/strong&gt; from improving your version control skills to working collaboratively with other developers, technical writers and designers, you always acquire new skills (or sharpen your existing ones).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Being part of the community:&lt;/strong&gt; contributing to open source helps you build relationships within the open-source community&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find mentors and mentor others:&lt;/strong&gt; as you work on open source projects you often need to explain how you do things and discuss the best solution to a problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Going beyond the technical skills:&lt;/strong&gt; not only it allows you to improve your coding or technical skills, but it also allows you to work on essential people skills such as effective communication, conflict resolution, leadership and organisational skills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Working in the open:&lt;/strong&gt; in many cases, we do not get the chance to share what we work on in our day job due to NDIs or other circumstances. Or maybe you are looking for a career change and want to build an online developer presence. Contributing to open-source gives you a chance to showcase all of the skills mentioned above in an open and public manner. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to get started with open-source contributions
&lt;/h2&gt;

&lt;p&gt;Right, so far, I only focused on the "why you might want to contribute to open source". Contributing to open-source can be pretty daunting, mostly if you have never done it before.&lt;br&gt;
And to be accurate, there are many steps involved, from choosing the best project to contribute to, selecting an item to work on to submitting your contribution. &lt;/p&gt;

&lt;p&gt;So let's break this into smaller pieces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding the right project
&lt;/h3&gt;

&lt;p&gt;The most straightforward way to find a project is thinking about the libraries you use regularly. And head over to the project's repository.&lt;/p&gt;

&lt;p&gt;Some items are a good indicator that the project is welcoming and accepting contributions. Head over to the project's repository and look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;:  make sure the project has an &lt;a href="https://choosealicense.com/" rel="noopener noreferrer"&gt;open source license&lt;/a&gt;, if you cannot find this, then the project is not open source. This should be as a &lt;code&gt;LICENSE&lt;/code&gt; file in the repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contribution guidelines&lt;/strong&gt;:  if the project repository is in GitHub, look for a &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; file. This should either contain the detailed process to set your development environment, how to run the tests and build the documentation. As well as any conventions for submitting contributions. 
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fnezahualcoyotl%2Fimage%2Fupload%2Fv1601312170%2Fnumpy_CONTRIBUTING_md_at_master___numpy_numpy_c9boje.png" alt="numpy-contributing"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code of conduct&lt;/strong&gt;: having a Code of Conduct is critical to keep the community interactions safe and friendly for us all. It helps set ground rules for contributor's behaviours and also outlines mechanisms to report violations to these rules. Having a CoC is a good signal towards a project being inclusive and welcoming. But make sure there are also channels to report CoC violations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication channels&lt;/strong&gt;:  some projects will have mailing lists for folks to ask questions and receive guidance. Others have Discourse servers, Gitter or Slack channels. Keep track of these resources as you might need them to ask questions.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fnezahualcoyotl%2Fimage%2Fupload%2Fv1601312499%2Fjupyterhub_jupyterhub__Multi-user_server_for_Jupyter_notebooks_elnuf1.png" alt="jupyterhub-communication"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contribution workflow&lt;/strong&gt;: check the number of issues open, Pull Requests and check the flow of discussions on issues. Spending some time doing this can be super valuable to get an idea about maintainers-contributors interactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Finding something to work on
&lt;/h3&gt;

&lt;p&gt;This is perhaps one of the most challenging parts of submitting your first (or hundredth) contribution. But here are my top tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Think beyond code&lt;/strong&gt;: there are so many ways in which you can contribute to open source, apart from code. I often get folks asking me "I am not a developer but a technical writer/designer/else, can I still contribute?" and the answer is &lt;strong&gt;yes&lt;/strong&gt;. The truth is open-source can significantly benefit from a diverse set of contributions, so make sure to think outside the coding box and think about how you can use other skills. Do you like organising events? Are you a great graphic designer? Are you an accessibility expert? Do you speak multiple languages? Think about how you can add value to the project while building on your skills and interests. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build from experience&lt;/strong&gt;: if you are contributing to a project, you have used before you might have encountered something that could be better. Maybe the instructions for setting up your development environment are outdated. Perhaps some of their tutorials are not clear enough. Use this to your advantage - having a fresh set of eyes can be massively helpful to improve the contributor's experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No contribution is too small&lt;/strong&gt;: maybe you encountered a broken link in the documentation or the project &lt;code&gt;Readme&lt;/code&gt;, consider submitting this as a contribution. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finding issues to work on&lt;/strong&gt;: There are multiple ways in which you can find issues to work on. For projects on GitHub, you can head over to their &lt;code&gt;Issues&lt;/code&gt; page and find issues marked as &lt;code&gt;help-wanted&lt;/code&gt;, &lt;code&gt;beginner-friendly&lt;/code&gt; or &lt;code&gt;good first issue.&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fnezahualcoyotl%2Fimage%2Fupload%2Fv1601313626%2FIssues___numpy_numpy_v6h5wy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fnezahualcoyotl%2Fimage%2Fupload%2Fv1601313626%2FIssues___numpy_numpy_v6h5wy.png" alt="numpy issues"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Something quite nifty I found about recently is that you can directly head over to the issues marked with these labels directly by going to the projects contributing page. For example, for JupyterHub, you would head over to &lt;a href="https://github.com/jupyterhub/jupyterhub/contribute" rel="noopener noreferrer"&gt;https://github.com/jupyterhub/jupyterhub/contribute&lt;/a&gt;. Plus the Contribution guidelines are also made visible so you can access them directly!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fnezahualcoyotl%2Fimage%2Fupload%2Fv1601313692%2FContribute_to_jupyterhub_jupyterhub_t2wse0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fres.cloudinary.com%2Fnezahualcoyotl%2Fimage%2Fupload%2Fv1601313692%2FContribute_to_jupyterhub_jupyterhub_t2wse0.png" alt="JupyterHub issues"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Beginners issues aggregators&lt;/strong&gt;: there are some sites that you can use to find beginner-friendly issues across many repositories, programming languages and organisations. 

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/explore/" rel="noopener noreferrer"&gt;GitHub explore&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.firsttimersonly.com/" rel="noopener noreferrer"&gt;First Timers Only&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://up-for-grabs.net/" rel="noopener noreferrer"&gt;Up for grabs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://goodfirstissues.com/" rel="noopener noreferrer"&gt;Good first issues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firstcontributions.github.io/" rel="noopener noreferrer"&gt;First contributions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.codetriage.com/" rel="noopener noreferrer"&gt;Code Triage&lt;/a&gt; this allows you to subscribe to your favourite project and get a new issue in your inbox for triaging&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  You are almost ready!
&lt;/h2&gt;

&lt;p&gt;Before getting working on an issue, make sure to have a quick check to make sure that nobody is working on this item already. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the issue and express your intention to work on it so that there is no duplication of effort&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes folks commit to working on an issue, but it turns out they did not follow through (maybe their circumstances changed, I have been there, and it's ok). &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Head to the issue and say you would like to follow on it.
Ask questions if you need to clarify any points or discuss implementations. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there are no issues opened for the item, you plan to work on open an issue straight away and discuss the idea. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide enough context, links and screenshots if this help support your issue. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Next steps
&lt;/h3&gt;

&lt;p&gt;Hopefully, this will get you all started. If you want to get some practice on creating Pull Requests &lt;a href="https://firstcontributions.github.io/" rel="noopener noreferrer"&gt;this resource by @kentcdodds&lt;/a&gt; is great. You can also make a PR to the &lt;a href="https://github.com/Roshanjossey/first-contributions" rel="noopener noreferrer"&gt;First Contribution&lt;/a&gt; repository to get some hands-on experience.&lt;/p&gt;

&lt;p&gt;Do you have any tops tips to get started? Add them as comments to this article, share your favourite projects to contribute to or examples to outstanding Readmes.&lt;/p&gt;

&lt;p&gt;And do not miss the following articles in the series where we will discuss PR etiquette and efficient communication and contribution workflows. &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>opensource</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>10 top tips for reproducible Machine Learning</title>
      <dc:creator>Tania Allard</dc:creator>
      <pubDate>Fri, 24 Apr 2020 13:59:34 +0000</pubDate>
      <link>https://forem.com/azure/10-top-tips-for-reproducible-machine-learning-36g0</link>
      <guid>https://forem.com/azure/10-top-tips-for-reproducible-machine-learning-36g0</guid>
      <description>&lt;h1&gt;
  
  
  10 practical tips for reproducible Machine Learning
&lt;/h1&gt;

&lt;h3&gt;
  
  
  The one where you get some advice to make your workflows more reproducible
&lt;/h3&gt;

&lt;p&gt;The boom of Machine Learning and AI solutions is undeniable. We have "AI" enabled everything: from medical diagnosis optimisation to HR and beer brewing processes.&lt;br&gt;
But thanks to this boom, we have also realised that developing and productising such products is hard, really hard. And it was not long before we started seeing these kinds of articles popping, well, everywhere:&lt;/p&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2Frepro_crisis.png%3Fraw%3Dtrue" alt="AI faces a reproducibility crisis - Wired mag"&gt;&lt;a&gt;https://www.wired.com/story/artificial-intelligence-confronts-reproducibility-crisis/&lt;/a&gt;
  



  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2Frepro_crisis_science.png%3Fraw%3Dtrue" alt="AI faces a reproducibility crisis - Science mag"&gt;Hutson M., Science Magazine Feb 2018, Vol. 359 pp. 725
  

&lt;h2&gt;
  
  
  What is reproducibility, and why do we care?
&lt;/h2&gt;

&lt;p&gt;A result is reproducible when the same analysis steps performed on the same dataset consistently produces the same answer.&lt;br&gt;
Reproducible Machine Learning can avoid significant errors and costs in the future. As well as making it easier to track and explain the insights/predictions generated.&lt;/p&gt;

&lt;p&gt;But beyond that, working reproducibly facilitates collaboration and review processes, ensures continuity of your work and retains institutional knowledge and future proofs your work. This is extremely important because most of the time, we do not work alone but with a group of data scientists, software engineers and many other stakeholders. &lt;/p&gt;

&lt;p&gt;The truth is that reproducibility in Machine Learning is a problem that every practitioner faces daily.&lt;/p&gt;

&lt;p&gt;Have you ever found yourself wondering any of the following?:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; What version of the dataset was used to train this algorithm?&lt;/li&gt;
&lt;li&gt; What version of the algorithm/model do we have in R&amp;amp;D/staging/production/was published in the paper?&lt;/li&gt;
&lt;li&gt;Did we keep track of all the parameters and features we explored and the baseline models?&lt;/li&gt;
&lt;/ul&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2Fmonkey.jpg%3Fraw%3Dtrue" alt="Gray monkey picture"&gt;Photo by Paolo Nicolello on Unsplash
  


&lt;p&gt;We have all been there, trust me. &lt;/p&gt;

&lt;p&gt;So without further ado, let's dive into how to make your workflows more reproducible.&lt;/p&gt;
&lt;h2&gt;
  
  
  0. Identifying the key players
&lt;/h2&gt;

&lt;p&gt;The base for reproducible workflows lies in being able to track and reproduce your data, computational environment and code.&lt;br&gt;
So you will notice that most of the recommendations here centre around these three critical assets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2F00_asset.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2F00_asset.png%3Fraw%3Dtrue" alt="Pillars reproducibility"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I am not going to dive too much into this (as this deserves a whole post for itself).  But, you ideally want to make all your work reproducibility across three levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Methodology&lt;/strong&gt;: for example, how your formulate your experiments and prove or disprove your hypothesis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model/algorithm&lt;/strong&gt; (though Machine Learning goes way beyond models that get deployed). For example, explain the complexity of your algorithm and the space you are covering how were your hyperparameters chosen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt;: here you want to ensure that there are a robust infrastructure folk others to access your data and run your code. Make sure also to describe the hardware you used (i.e. GPU).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2F01_asset.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2F01_asset.png%3Fraw%3Dtrue" alt="Levels reproducibility"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Always know what you are expecting from your data.
&lt;/h2&gt;

&lt;p&gt;We all know how vital good quality data is for good quality and reliable Machine Learning. So we always should know what we are expecting from our data at all times - what types, distributions, ranges and schemas. &lt;/p&gt;

&lt;p&gt;One of my favourite tools to do this is &lt;a href="https://docs.greatexpectations.io/" rel="noopener noreferrer"&gt;Great expectations&lt;/a&gt; as it integrates with other tools I use like Spark, Airflow, Jupyter Notebooks and pandas (among others). It is an excellent tool for data validation, testing and documentation. &lt;/p&gt;

&lt;p&gt;For example, if you have a raw data source on which you do some manipulation before storing it in a database, you can add multiple validation steps for your input and output data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2F02_asset.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2F02_asset.png%3Fraw%3Dtrue" alt="Validation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are collecting data from third-party APIs, you can use &lt;a href="https://github.com/Julian/jsonschema" rel="noopener noreferrer"&gt;JSON schema&lt;/a&gt; to validate against the meta schema.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Develop pipelines.
&lt;/h2&gt;

&lt;p&gt;The best way to keep track of all your outputs, inputs, metrics, models and data even before using specialised tools is being able to keep track of each task you are performing. &lt;/p&gt;

&lt;p&gt;Many tools allow you to build robust pipelines. Many of which revolve around the concept of &lt;a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph" rel="noopener noreferrer"&gt;Directed acyclic graphs&lt;/a&gt;. Some of my favourites are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/dagster-io/dagster" rel="noopener noreferrer"&gt;Dagster&lt;/a&gt;: I have found that it is super easy to use and has native Jupyter integration (win!).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/apache/airflow" rel="noopener noreferrer"&gt;Airflow&lt;/a&gt;: this Apache incubator project has gained loads of popularity. The UI makes it very easy to have an overview of your DAGs and their statuses. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These add a lot more complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.pachyderm.com/" rel="noopener noreferrer"&gt;Pachyderm&lt;/a&gt;: A Kubernetes native platform for repeatable data science. &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kubeflow.org/" rel="noopener noreferrer"&gt;Kubeflow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, you decide to implement your pipelines keep this rule of thumb in mind:&lt;/p&gt;

&lt;p&gt;✨ &lt;strong&gt;Top tip:&lt;/strong&gt;  Split your tasks into atomic units of work. Where each node of your DAG or each step in your pipeline does one single task.&lt;/p&gt;

&lt;p&gt;This helps avoid the "Change anything Change everything" (&lt;a href="https://papers.nips.cc/paper/5656-hidden-technical-debt-in-machine-learning-systems.pdf" rel="noopener noreferrer"&gt;Scully et all&lt;/a&gt;) problem.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. ML loves randomness - deal with it.
&lt;/h2&gt;

&lt;p&gt;There is randomness everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Random initialisations&lt;/li&gt;
&lt;li&gt;Random augmentations&lt;/li&gt;
&lt;li&gt;Random noise introductions&lt;/li&gt;
&lt;li&gt;Data shuffles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The sound advice that you will find everywhere is &lt;strong&gt;always set and save your seed&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;If working with Python, you should often find yourself performing a version of this ritual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt; 
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tensorflow&lt;/span&gt; 
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; 

&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PYTHONHASHSEED&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;tensorflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;numpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tensorflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dropout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SEED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tensorflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random_flip_left_right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tensorflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random_normal_initializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another source of randomness is - data! When we split the data for training and validation, we often use different splits. &lt;/p&gt;

&lt;p&gt;The solution: fix train and validation splits before training - if using methods like &lt;code&gt;test_split_train&lt;/code&gt; from scikit-learn make sure also to specify the &lt;code&gt;seed&lt;/code&gt; argument. &lt;/p&gt;

&lt;h2&gt;
  
  
  4. Hyperparameters everywhere
&lt;/h2&gt;

&lt;p&gt;Finding the right hyperparameters for your models can be quite an involved process. These can be particularly problematic when you are running multiple experiments with different network architectures.&lt;/p&gt;

&lt;p&gt;✨ &lt;strong&gt;Top tip:&lt;/strong&gt;  As a rule of thumb: not only keep track of the parameters but also of the output metrics of each model associated and your selection process/baseline.&lt;/p&gt;

&lt;p&gt;An excellent example of how to keep track of your hyperparameters in a sane manner can be found in the &lt;a href="https://github.com/pachyderm/pachyderm/tree/master/examples/ml/hyperparameter#distributed-hyperparameter-tuning" rel="noopener noreferrer"&gt;Pachyderm distributed hyperparameter tuning sample&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fpachyderm%2Fpachyderm%2Fblob%2Fmaster%2Fexamples%2Fml%2Fhyperparameter%2Fpipeline1.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fpachyderm%2Fpachyderm%2Fblob%2Fmaster%2Fexamples%2Fml%2Fhyperparameter%2Fpipeline1.png%3Fraw%3Dtrue" alt="Pachyderm"&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The use of pipelines to split, train, test, and select the models and hyperparameter makes it so much easier to keep track of the outputs at all stages as well as reporting on the rationale behind why you chose specific hyperparameters.  &lt;/p&gt;

&lt;h2&gt;
  
  
  5. &amp;amp; 6. Version control &amp;amp; data decoupling.
&lt;/h2&gt;

&lt;p&gt;How often have you worked on pieces of code that had lines like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;../../../data.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this scenario, both data and code are tightly coupled. To ensure reproducibility, you want to keep track of both your code and your data versions. Not only for the final outputs but also the intermediate results. &lt;/p&gt;

&lt;p&gt;Imagine you have a workflow like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2F03_asset.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftrallard%2F10-tips-reproducible-ml%2Fblob%2Fmaster%2Fassets%2F03_asset.png%3Fraw%3Dtrue" alt="Simple pipeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although this is a somewhat simplified pipeline, there are still multiple outputs which you want to track (data, code and serialised files).&lt;/p&gt;

&lt;p&gt;A great tool for this is &lt;a href="https://dvc.org/" rel="noopener noreferrer"&gt;dvc&lt;/a&gt; - which allows you to keep track of all your assets with Git without * storing your data in Git*. &lt;br&gt;
This allows you to decouple data and code and their respective versions to ensure reproducibility:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdvc.org%2Fimg%2Fmodel-versioning-diagram.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdvc.org%2Fimg%2Fmodel-versioning-diagram.png" alt="dvc tutorial"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Testing
&lt;/h2&gt;

&lt;p&gt;Testing in Machine Learning can be quite complex. Again, I am not going to dive too much into this as testing strategies deserve a post for itself. So here is a checklist of testing strategies and items you need to consider testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API calls and contract tests against your data schemas&lt;/li&gt;
&lt;li&gt;Integration tests for your pipelines&lt;/li&gt;
&lt;li&gt;Regression tests&lt;/li&gt;
&lt;li&gt;Unit tests - test your methods, transformations&lt;/li&gt;
&lt;li&gt;Test that model weights and outputs are numerically stable&lt;/li&gt;
&lt;li&gt;Reproducibility across environments: development, staging and production. The predictions across these should be the same.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✨ &lt;strong&gt;Top tip:&lt;/strong&gt;  A package I find using over and over again is &lt;a href="https://github.com/HypothesisWorks/hypothesis" rel="noopener noreferrer"&gt;Hypothesis&lt;/a&gt; for property-based testing. It not only has simplified my testing strategies but also has increased my confidence in the tests.&lt;/p&gt;

&lt;p&gt;There are extensions to Hypothesis which are worth checking: &lt;a href="https://hypothesis.readthedocs.io/en/latest/strategies.html" rel="noopener noreferrer"&gt;https://hypothesis.readthedocs.io/en/latest/strategies.html&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Reproducible environments
&lt;/h2&gt;

&lt;p&gt;For a piece of work to be reproducible, the computational environment that it was conducted in must be captured so that others can replicate it. &lt;/p&gt;

&lt;p&gt;Many tools allow you to create reproducible environments or at least to get close to. &lt;/p&gt;

&lt;p&gt;Depending on the projects I am working on, I tend to mix some of these tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.conda.io/en/latest/" rel="noopener noreferrer"&gt;Conda&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jazzband/pip-tools" rel="noopener noreferrer"&gt;Pip-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://python-poetry.org/" rel="noopener noreferrer"&gt;Poetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pypa/pipenv" rel="noopener noreferrer"&gt;Pipenv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mybinder.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Binder&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And I am still a fan of Make because it is fantastic.&lt;/p&gt;

&lt;p&gt;✨ &lt;strong&gt;Top tips:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no &lt;strong&gt;one size fits all&lt;/strong&gt;. Choose the most appropriate method for your project for capturing your computational environment&lt;/li&gt;
&lt;li&gt;Capture your computational environment - I recommend not only pinning the main dependencies but also the sub dependencies and use a tool with dependency resolutions (pip-tools, pipenv and Poetry are proper tools to do this)&lt;/li&gt;
&lt;li&gt;Share your captured computational environment along with your code and data if possible&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  9. Automate
&lt;/h2&gt;

&lt;p&gt;A lot of errors can be introduced when we depend too much on the &lt;em&gt;human-in-the loop&lt;/em&gt; for our workflows. &lt;br&gt;
So whenever possible automate stuff not only, it will save you time but will optimise your workflows and increase your confidence.&lt;/p&gt;

&lt;p&gt;Some great tools I use for automation are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://tox.readthedocs.io/en/latest/index.html" rel="noopener noreferrer"&gt;Tox&lt;/a&gt; - for automated testing&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nox.thea.codes/en/stable/" rel="noopener noreferrer"&gt;Nox&lt;/a&gt; - flexible test automation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.pyinvoke.org/" rel="noopener noreferrer"&gt;Invoke&lt;/a&gt; - general-purpose task execution (quite similar to Make but Python-specific)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jupyter/repo2docker" rel="noopener noreferrer"&gt;Repo2docker&lt;/a&gt; - create Docker containers from GitHub repositories&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mybinder.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Binder&lt;/a&gt; - create reproducible interactive environments from GitHub repositories&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub actions&lt;/a&gt; - Continuous integration and devliery as well as workflow automation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✨ &lt;strong&gt;Top tip:&lt;/strong&gt; Start automating the most critical parts - deployment, container creation, testing and move from there.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Consistency and standards
&lt;/h2&gt;

&lt;p&gt;With the myriad of tools and workflows out there &lt;strong&gt;there is not a single solution&lt;/strong&gt; for the reproducibility problem. &lt;/p&gt;

&lt;p&gt;But what I have found is that consistency is critical. Here are my last ✨ &lt;strong&gt;Top tips:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have a consistent project structure. You can use tools like &lt;a href="https://drivendata.github.io/cookiecutter-data-science/" rel="noopener noreferrer"&gt;data science cookiecutter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Adhere to coding standards:

&lt;ul&gt;
&lt;li&gt;Use a fomatter and linter. I normally use &lt;a href="https://github.com/psf/black" rel="noopener noreferrer"&gt;black&lt;/a&gt;, &lt;a href="https://www.pylint.org/" rel="noopener noreferrer"&gt;pylint&lt;/a&gt;, and &lt;a href="http://flake8.pycqa.org/en/latest/" rel="noopener noreferrer"&gt;flake8&lt;/a&gt; as well as &lt;a href="https://github.com/timothycrosley/isort" rel="noopener noreferrer"&gt;isort&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Using these tools helps me with code quality.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Document and documentation as code. 

&lt;ul&gt;
&lt;li&gt;Many folks do not enjoy writing documentation. But something I started doing a while ago is treating docs as code (well almost). I build all my docs through my continuous integration pipelines, and I also run tests on them. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Choosing tools:

&lt;ul&gt;
&lt;li&gt;I have mentioned many tools here. But each of them come with a learning curve and tricks you have to learn. Chose what works for you and learn it well, rather than trying to learn how to use all the tools.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;That is it! These are some practical tips to get you started with Reproducible Machine Learning. &lt;/p&gt;

&lt;p&gt;Do you have any other tips I missed? Let me know in the comments.&lt;/p&gt;

&lt;p&gt;You can also find me at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Twitter: &lt;a href="https://twitter.com/ixek" rel="noopener noreferrer"&gt;https://twitter.com/ixek&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/trallard" rel="noopener noreferrer"&gt;https://github.com/trallard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;My personal site: &lt;a href="https://trallard.dev" rel="noopener noreferrer"&gt;https://trallard.dev&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>machinelearning</category>
      <category>opensource</category>
      <category>reproducibility</category>
      <category>aiapril</category>
    </item>
    <item>
      <title>💻🚀 Tech bites: What is the cloud?</title>
      <dc:creator>Tania Allard</dc:creator>
      <pubDate>Wed, 08 Apr 2020 09:17:23 +0000</pubDate>
      <link>https://forem.com/azure/tech-bites-what-is-serverless-1a9a</link>
      <guid>https://forem.com/azure/tech-bites-what-is-serverless-1a9a</guid>
      <description>&lt;p&gt;These days everything is &lt;em&gt;on the cloud&lt;/em&gt; - but what is this so called "cloud"? This infographic aims to help you all learn more about how the cloud works and what it is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hafaqjPg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/nezahualcoyotl/image/upload/v1586337294/cloud_101_i1o1qs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hafaqjPg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/nezahualcoyotl/image/upload/v1586337294/cloud_101_i1o1qs.png" alt="cloud 101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the pdf version &lt;a href="https://github.com/trallard/tech-bites/blob/master/EN/cloud-computing/what_is_the_cloud.pdf"&gt;here&lt;/a&gt; which is released under CC-BY.&lt;/p&gt;

&lt;p&gt;✨ This post is part of a series of visuals I will be working on over the next few months so I will be adding al the visuals to this GitHub repository &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/trallard"&gt;
        trallard
      &lt;/a&gt; / &lt;a href="https://github.com/trallard/tech-bites"&gt;
        tech-bites
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      💻🎨 Infographics, digital assets and others to explain tech concepts, tools and techniques!
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://raw.githubusercontent.com/trallard/tech-bites/master/assets/banner.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ofbFxB7w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/trallard/tech-bites/master/assets/banner.png" alt="banner"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://creativecommons.org/licenses/by/4.0/" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/aaaf93831400a8c345a60a447db475849116046f884609a199d49e692f6cbb46/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d43432532304259253230342e302d6c69676874677265792e7376673f636f6c6f72413d32443241353626636f6c6f72423d374137364332267374796c653d666c61742e737667" alt="License: CC BY 4.0"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
What is in here?&lt;/h2&gt;
&lt;p&gt;The digital assets for the series of infographics I produce. The goal of these is to provide insight on tech, tools, and techniques in easy to digest formats.&lt;/p&gt;
&lt;h2&gt;
Infographics table of content&lt;/h2&gt;
&lt;p&gt;All of the content will be released both in English and Spanish and you can find it here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
🇬🇧 English version
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./EN/serverless"&gt;Serverless 101&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./EN/cloud-computing"&gt;Cloud 101&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
🇲🇽 Spanish version
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./ES/serverless"&gt;Informática sin servidor 101&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./ES/cloud-computing"&gt;La nube 101&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✨🙋🏻‍♀️ Want to translate into other languages? Let me know!&lt;/p&gt;
&lt;h2&gt;
🙌🏼 Contributing&lt;/h2&gt;
&lt;p&gt;If you want to suggets a topic to make an infographic on please use the &lt;code&gt;new topic&lt;/code&gt; template in this repo &lt;a href="https://github.com/trallard/tech-bites/issues"&gt;issues&lt;/a&gt; ✨.&lt;/p&gt;
&lt;p&gt;You can find the contributing guidelines &lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./CONTRIBUTING.md"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are now accepting translations. Please check the contributing guidelines first and then use the &lt;code&gt;translation&lt;/code&gt; template in this repo &lt;a href="https://github.com/trallard/tech-bites/issues"&gt;issues&lt;/a&gt;. 🌎🌍🌏&lt;/p&gt;
&lt;h2&gt;
📝 Further resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
☁️ &lt;a href="https://docs.microsoft.com/learn/paths/azure-fundamentals/?WT.mc_id=academic-0000-taallard" rel="nofollow"&gt;Azure fundamentals interactive tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
⚡️…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/trallard/tech-bites"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>cloud</category>
      <category>beginners</category>
      <category>codenewbie</category>
      <category>technology</category>
    </item>
    <item>
      <title>💻🚀 Tech bites: What is serverless?</title>
      <dc:creator>Tania Allard</dc:creator>
      <pubDate>Tue, 07 Apr 2020 15:16:34 +0000</pubDate>
      <link>https://forem.com/azure/tech-bites-serverless-computing-101s-4d8c</link>
      <guid>https://forem.com/azure/tech-bites-serverless-computing-101s-4d8c</guid>
      <description>&lt;p&gt;&lt;strong&gt;Serverless computing&lt;/strong&gt; has gained a lot of traction recently. But, are you still trying to wrap your head around how this works?&lt;br&gt;
Wonder no more, I created this infographic as a gentle 101 (introductory) resource to serverless computing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2o_uHkcV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/nezahualcoyotl/image/upload/v1586274415/101_serverless_v3fcb0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2o_uHkcV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/nezahualcoyotl/image/upload/v1586274415/101_serverless_v3fcb0.png" alt="serverless 101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the pdf version &lt;a href="https://github.com/trallard/tech-bites/blob/master/EN/serverless/101_serverless.pdf"&gt;here&lt;/a&gt; which is released under CC-BY.&lt;/p&gt;

&lt;p&gt;✨ This post is part of a series of visuals I will be working on over the next few months so I will be adding al the visuals to this GitHub repository &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/trallard"&gt;
        trallard
      &lt;/a&gt; / &lt;a href="https://github.com/trallard/tech-bites"&gt;
        tech-bites
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      💻🎨 Infographics, digital assets and others to explain tech concepts, tools and techniques!
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://raw.githubusercontent.com/trallard/tech-bites/master/assets/banner.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ofbFxB7w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/trallard/tech-bites/master/assets/banner.png" alt="banner"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://creativecommons.org/licenses/by/4.0/" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/aaaf93831400a8c345a60a447db475849116046f884609a199d49e692f6cbb46/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d43432532304259253230342e302d6c69676874677265792e7376673f636f6c6f72413d32443241353626636f6c6f72423d374137364332267374796c653d666c61742e737667" alt="License: CC BY 4.0"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
What is in here?&lt;/h2&gt;
&lt;p&gt;The digital assets for the series of infographics I produce. The goal of these is to provide insight on tech, tools, and techniques in easy to digest formats.&lt;/p&gt;
&lt;h2&gt;
Infographics table of content&lt;/h2&gt;
&lt;p&gt;All of the content will be released both in English and Spanish and you can find it here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
🇬🇧 English version
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./EN/serverless"&gt;Serverless 101&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./EN/cloud-computing"&gt;Cloud 101&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
🇲🇽 Spanish version
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./ES/serverless"&gt;Informática sin servidor 101&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./ES/cloud-computing"&gt;La nube 101&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✨🙋🏻‍♀️ Want to translate into other languages? Let me know!&lt;/p&gt;
&lt;h2&gt;
🙌🏼 Contributing&lt;/h2&gt;
&lt;p&gt;If you want to suggets a topic to make an infographic on please use the &lt;code&gt;new topic&lt;/code&gt; template in this repo &lt;a href="https://github.com/trallard/tech-bites/issues"&gt;issues&lt;/a&gt; ✨.&lt;/p&gt;
&lt;p&gt;You can find the contributing guidelines &lt;a href="https://raw.githubusercontent.com/trallard/tech-bites/master/./CONTRIBUTING.md"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are now accepting translations. Please check the contributing guidelines first and then use the &lt;code&gt;translation&lt;/code&gt; template in this repo &lt;a href="https://github.com/trallard/tech-bites/issues"&gt;issues&lt;/a&gt;. 🌎🌍🌏&lt;/p&gt;
&lt;h2&gt;
📝 Further resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
☁️ &lt;a href="https://docs.microsoft.com/learn/paths/azure-fundamentals/?WT.mc_id=academic-0000-taallard" rel="nofollow"&gt;Azure fundamentals interactive tutorial&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
⚡️…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/trallard/tech-bites"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>serverless</category>
      <category>beginners</category>
      <category>learning</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>Let the posadas begin - Day 16 of the #25DaysOfServerles challenge</title>
      <dc:creator>Tania Allard</dc:creator>
      <pubDate>Tue, 17 Dec 2019 12:00:17 +0000</pubDate>
      <link>https://forem.com/azure/let-the-posadas-begin-day-16-of-the-25daysofserverles-challenge-57hm</link>
      <guid>https://forem.com/azure/let-the-posadas-begin-day-16-of-the-25daysofserverles-challenge-57hm</guid>
      <description>&lt;p&gt;This article is part of &lt;a href="https://25daysofserverless.com"&gt;#25DaysOfServerless&lt;/a&gt;. New challenges will be published every day from Microsoft Cloud Advocates throughout the month of December. Find out more about how Microsoft Azure enables your &lt;a href="https://docs.microsoft.com/azure/azure-functions/?WT.mc_id=25days_devto-blog-cxa"&gt;Serverless functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have an idea or a solution? &lt;a class="twitter-share-button" href="https://twitter.com/intent/tweet?text=I'm%20joining%20the%20@azureadvocates%20%2325DaysOfServerless%20challenge!!%20Learn%20more%20at%20https://aka.ms/25daysofserverless%20or%20see%20solutions%20at%20https://dev.to/search?q=25DaysOfServerless!%20Join%20me!"&gt; Share your thoughts on Twitter! &lt;br&gt;
&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;It's the 16th of December, which can only mean one thing: Posadas are finally starting in Mexico! Everyone is already preparing for the following nine days of posadas and deciding on venues all across Mexico City for this festive tradition. &lt;/p&gt;

&lt;p&gt;A couple of months back, Xanath offered to put together a list of hosts and locations so that all her friends and family had the details for each posada. With all the servers missing and so little time to collect the sites and inform everyone Xanath has asked some friends for help.&lt;br&gt;
They will all be working together to make a solution to help folks to find the location of the next posada.&lt;/p&gt;
&lt;h2&gt;
  
  
  The challenge
&lt;/h2&gt;

&lt;p&gt;Your challenge is to create a simple solution for Xanath's friends and family to find the locations of the upcoming posadas as well as the name of the person hosting.&lt;br&gt;
Since there will be several people working on the project and adding locations at the same time, you need to make sure that the solution is accordingly updated and deploy to reflect these changes. &lt;/p&gt;
&lt;h2&gt;
  
  
  Tips:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;To allow for the solution and data to be updated as fast as possible, the deployment should be made automatically after a Pull Request has been merged. You can achieve this using services like GitHub Actions or Azure Pipelines.&lt;/li&gt;
&lt;li&gt;You can specify the locations in any way you prefer (i.e. addresses, latitude and longitude pairs). Still, you need to make sure that every place added adheres to the same format.&lt;/li&gt;
&lt;li&gt;There are many ways in which you can implement this solution; we recommend you start with a simple one, implement your CI/CD pipeline and refine later.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  A solution
&lt;/h2&gt;

&lt;p&gt;In this particular challenge, the main focus is setting up a CI/CD pipeline for an Azure Function, so I decided to use Python for this challenge.&lt;br&gt;
Since the main focus is not the function itself, I am going to summarise the process quite a bit. Still, you can follow &lt;a href="https://docs.microsoft.com/en-us/azure/python/tutorial-vs-code-serverless-python-01/?WT.mc_id=25days_devto-blog-cxa"&gt;this tutorial&lt;/a&gt; in case you want a step-by-step guide on how to create an Http Triggered Azure Function in Python.&lt;/p&gt;

&lt;p&gt;I used VS Code and the Azure functions extension to create a Python Http triggered function with the predefined templates as the starting point.&lt;/p&gt;

&lt;p&gt;The next step is to decide on the format for the locations for the challenge. In my case, I created a &lt;code&gt;locations.json&lt;/code&gt; file which looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"locations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bellas Artes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"December 16, 2019"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tania Allard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"geopoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"lon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;19.4352&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;99.1412&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Museo de Antropologia"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"December 17, 2019"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tania Allard"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"geopoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"lon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;19.4260&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;99.1863&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I modified the &lt;code&gt;__init__.py&lt;/code&gt; script accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;azure.functions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Someone is looking for a posada! ✨"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"day"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;locations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json_locations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;locations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json_locations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="n"&gt;posada&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_loc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;posada&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please pass a day"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;json_locations&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
 &lt;span class="s"&gt;"""Function to parse the json file with the locations,
 we use Pathlib to resolve the full path of the file
 """&lt;/span&gt;
 &lt;span class="n"&gt;loc_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./posadas/data/locations.json"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;json_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;locations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"locations"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_loc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="s"&gt;"""This function searches for the location corresponding to the 
 query day. 
 We need to make sure the dates are actually converted into DateTime objects.
 """&lt;/span&gt;
 &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;posada&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

 &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strptime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;posada&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"%B %d, %Y"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;posada&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above allows the user to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Provide a day as a query string to the function API in which case it only returns the details for the corresponding day (e.g. &lt;code&gt;https://posadastrallard.azurewebsites.net/api/posadas/?day=16&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Submit a GET request to the primary endpoint so that it returns all of the dates and locations in the locations file. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After testing locally running &lt;code&gt;func host start&lt;/code&gt; and making sure everything was working, I deployed my function app to Azure. I like using the Azure CLI for this kind of things (again a step-by-step can be found &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-python/?WT.mc_id=25days_devto-blog-cxa"&gt;here&lt;/a&gt;).&lt;br&gt;
If you have the Azure Functions extension for VS Code Installed, you can publish your app directly from there too, and it will save you some time.&lt;/p&gt;

&lt;p&gt;After deploying, I made sure that my function was working correctly by performing a GET request:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3Ol2Jg8j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/trallard/25daysofserverless-challenges/blob/master/assets/api.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3Ol2Jg8j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/trallard/25daysofserverless-challenges/blob/master/assets/api.png%3Fraw%3Dtrue" alt="api call"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the function is deployed, we can go ahead and create the CI/CD pipeline. For this challenge, I decided to use &lt;a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions"&gt;GitHub actions&lt;/a&gt;. To do so, we need to follow the next steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals#service-principal-object/?WT.mc_id=25days_devto-blog-cxa"&gt;service principal&lt;/a&gt;. This will allow us to deploy our function using GitHub actions. 
If you are using your command line with the Azure CLI or the Azure Cloud shell, you can use the following command:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; az ad sp create-for-rbac &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"myApp"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--role&lt;/span&gt; contributor &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--scopes&lt;/span&gt; /subscriptions/&amp;lt;SUBSCRIPTION_ID&amp;gt;/resourceGroups/&amp;lt;RESOURCE_GROUP&amp;gt;/providers/Microsoft.Web/sites/&amp;lt;APP_NAME&amp;gt; &lt;span class="nt"&gt;--sdk-auth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Note that we are giving it only &lt;code&gt;contributor&lt;/code&gt; access to restrict the scope of this access.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now make sure to copy the output of the above command as you will need it. Head over to your GitHub repository where you have your function code go to &lt;strong&gt;Settings &amp;gt; Secrets&lt;/strong&gt; 
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ShoDksSC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/trallard/25daysofserverless-challenges/master/assets/secrets.png" alt="api call"&gt;
Paste the output from when you created your service principal (note that you will need to add your subscription id too).&lt;/li&gt;
&lt;li&gt;Now back in your local repository, we are going to create a &lt;code&gt;.github/workflows&lt;/code&gt; directory. That is the location where all of our CI/CD pipeline definitions will be located for GitHub to be able to find them. Now let's create a &lt;code&gt;python_function.yaml&lt;/code&gt; file (you can change the name).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I am going to explain the content, so you know what this is doing. &lt;/p&gt;

&lt;p&gt;We want the pipeline to trigger at a push on the master branch. Also, we first need to check out our repository, so we use &lt;code&gt;actions/checkout@master&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python function&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;build-and-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
 &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Checkout&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;GitHub&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;
 &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we login to Azure and set our Python environment. Here is where you also install dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Login&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;via&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Azure&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CLI"&lt;/span&gt;
 &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure/login@v1&lt;/span&gt;
 &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;creds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AZURE_CREDENTIALS }}&lt;/span&gt;

 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Python &lt;/span&gt;&lt;span class="m"&gt;3.7&lt;/span&gt;
 &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v1&lt;/span&gt;
 &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3.7&lt;/span&gt;

 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pip"&lt;/span&gt;
 &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;
 &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
 &lt;span class="s"&gt;pushd .&lt;/span&gt;
 &lt;span class="s"&gt;python -m pip install --upgrade pip&lt;/span&gt;
 &lt;span class="s"&gt;pip install -r requirements.txt --target=".python_packages/lib/python3.7/site-packages"&lt;/span&gt;
 &lt;span class="s"&gt;popd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally we publish our function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Azure&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Functions&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Action"&lt;/span&gt;
 &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Azure/functions-action@v1&lt;/span&gt;
 &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fa&lt;/span&gt;
 &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;app-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;posadastrallard&lt;/span&gt;
 &lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we do &lt;code&gt;git add .github/workflows/python_function.yaml&lt;/code&gt; and push we should see the workflow running straightaway under &lt;strong&gt;Actions&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ME0sNl_G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/trallard/25daysofserverless-challenges/master/assets/actions2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ME0sNl_G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/trallard/25daysofserverless-challenges/master/assets/actions2.png" alt="pipelines actions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, you can make an update to the locations file, wait for the deployment to complete and see your app updated!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J9uWKdhO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/trallard/25daysofserverless-challenges/master/assets/api2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J9uWKdhO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/trallard/25daysofserverless-challenges/master/assets/api2.png" alt="api updated"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Success!&lt;/p&gt;

&lt;p&gt;You can see the final Python Http Triggered function as well as the GitHub actions workflows in the &lt;a href="https://github.com/trallard/25daysofserverless-challenges"&gt;GitHub repository&lt;/a&gt; shall you need more inspiration.&lt;/p&gt;




&lt;p&gt;Want to submit your solution to this challenge? Build a solution locally and then &lt;a href="https://github.com/microsoft/25-days-of-serverless/issues/new?assignees=&amp;amp;labels=challenge-submission&amp;amp;template=challenge-solution-submission.md&amp;amp;title=%5BCHALLENGE+SUBMISSION%5D+"&gt;submit an issue&lt;/a&gt;. If your solution doesn't involve code you can record a short video and submit it as a link in the issue desccription. Make sure to tell us which challenge the solution is for. We're excited to see what you build! Do you have comments or questions? Add them to the comments area below.&lt;/p&gt;




&lt;p&gt;Watch for surprises all during December as we celebrate 25 Days of Serverless. Stay tuned here on dev.to as we feature challenges and solutions! Sign up for a &lt;a href="https://azure.microsoft.com/free/?WT.mc_id=25days_devto-blog-cxa"&gt;free account on Azure&lt;/a&gt; to get ready for the challenges!&lt;/p&gt;

</description>
      <category>25daysofserverless</category>
      <category>serverless</category>
      <category>azure</category>
      <category>python</category>
    </item>
  </channel>
</rss>
