<?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>DEV Community: Harvey Church</title>
    <description>The latest articles on DEV Community by Harvey Church (@harveychurch).</description>
    <link>https://dev.to/harveychurch</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%2F246033%2F16822cfc-a154-4368-9905-66565de87a9e.jpeg</url>
      <title>DEV Community: Harvey Church</title>
      <link>https://dev.to/harveychurch</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harveychurch"/>
    <language>en</language>
    <item>
      <title>Multiple Developers; One Discord Bot?</title>
      <dc:creator>Harvey Church</dc:creator>
      <pubDate>Tue, 08 Mar 2022 16:56:00 +0000</pubDate>
      <link>https://dev.to/harveychurch/multiple-developers-one-discord-bot-n57</link>
      <guid>https://dev.to/harveychurch/multiple-developers-one-discord-bot-n57</guid>
      <description>&lt;p&gt;I had a problem: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do I keep a Python Discord bot online, allow multiple people to contribute to it and then deploy it when new features are added?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Several Google searches had come up short, partial solutions; no clear answer.&lt;/p&gt;

&lt;p&gt;Here is my attempt at a solution (&lt;em&gt;though no promise that it is the smartest, or best.. it has just worked for me&lt;/em&gt; ¯\_(ツ)_/¯)&lt;/p&gt;

&lt;h2&gt;
  
  
  Hosting and Deployment
&lt;/h2&gt;

&lt;p&gt;This project uses discord.py and &lt;a href="https://pypi.org/project/discord-py-slash-command/"&gt;discord-py-slash-command&lt;/a&gt; to patch the missing slash command functionality and is hosted &lt;a href="https://github.com/harveychurch/beeb-bot"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The aim of the project was to allow for any member of a private Discord to contribute custom functionality, test locally and then deploy for all to use.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uJO6QY50--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m3ovqs4085ivb2i5oge5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uJO6QY50--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m3ovqs4085ivb2i5oge5.png" alt="From Local Development to Deployment" width="880" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Code can be developed locally, and continually pushed to a GitHub repo.&lt;/li&gt;
&lt;li&gt; No code is pushed to the "Live Server" until a git tag is created for a specific release&lt;/li&gt;
&lt;li&gt; This tag triggers a GitHub Action that SSH's into the "live server" and deploys the code&lt;/li&gt;
&lt;li&gt; For a user on a Discord server the bot is part of, can now run commands.&lt;/li&gt;
&lt;li&gt; Developers can continue to test/create features on a locally hosted bot, and push them &lt;em&gt;without&lt;/em&gt; the live bot being effected&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For hosting, I am using &lt;a href="https://www.digitalocean.com/"&gt;DigitalOcean&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am sure any other cloud hosting provider will work, just a few changes in the GitHub action script would be required.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions &amp;amp; Server Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Script
&lt;/h3&gt;

&lt;p&gt;To actually upload the code and implement the triggering of the workflow when a tag is created, I have used the following GitHub workflow script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Deploy Code to Digital Ocean

on:
  push: 
    branches:
    - main
    tags:
     - 'v0.*'

jobs:
  create_release:
    if: github.ref_type == 'tag' &amp;amp;&amp;amp; contains(github.ref_name,'v')
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2.4.0
      - name: Create Release on GitHub
        uses: softprops/action-gh-release@v1
        with:
           tag_name: ${{ github.ref_name }}
           token: ${{ secrets.GITHUB_TOKEN }}
  push_to_digital_ocean:
    needs: create_release
    runs-on: ubuntu-latest
    steps:
     - name: SSH into Droplet and push
       uses: garygrossgarten/github-action-ssh@release
       with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        passphrase: ${{ secrets.PASSWORD }}
        privateKey: ${{secrets.SSHKEY}}
        command: |
         cd beeb-bot/
         echo "Running Startup Script"
         pm2 stop main_bot
         git pull
         # For if there have been any changes to the pipefile/dependancies
         pipenv install
         pm2 start main_bot

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

&lt;/div&gt;



&lt;p&gt;The core of the script is the SSH portion. GitHub actions are designed for the repeating of others code. This action makes use of Gary Großgarten's &lt;a href="https://github.com/garygrossgarten/github-action-ssh"&gt;"Github Action SSH"&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;A private key is stored &lt;em&gt;within&lt;/em&gt; the repository, with the matching Public Key on the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Juicy Part
&lt;/h3&gt;

&lt;p&gt;The important part of the script is the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  cd beeb-bot/
         echo "Running Startup Script"
         pm2 stop main_bot
         git pull
         # For if there have been any changes to the pipefile/dependancies
         pipenv install
         pm2 start main_bot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pm2&lt;/code&gt; in the script refers to a &lt;a href="https://pm2.keymetrics.io/"&gt;process manager&lt;/a&gt;, mainly used for Node.js projects -- however it can run Python scripts. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;pm2&lt;/code&gt; is used used because just running something like &lt;code&gt;python3 main.py&lt;/code&gt; locks up the action, and it can never exit. Using this means the script no longer locks up, and the action succeeds/fails.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main_bot&lt;/code&gt; is a short hand for &lt;code&gt;pm2 start "pipenv run python3 main.py" --name main_bot --watch&lt;/code&gt;. This project makes use of pipenv to manage dependencies, and to make sure the virtual environment is used, &lt;code&gt;pipenv run&lt;/code&gt; is called.&lt;/p&gt;

&lt;p&gt;A git instance of repo is stored on the server. &lt;code&gt;git pull&lt;/code&gt; gets a copy from GitHub (which should be the latest release).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pipenv install&lt;/code&gt; is run to ensure the virtual environment on the server matches the needed packages for the project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pm2 start main_bot&lt;/code&gt; is called to start the process again and run the freshly pulled &lt;code&gt;main.py&lt;/code&gt; script.&lt;/p&gt;

&lt;h3&gt;
  
  
  On the Server (&lt;em&gt;specifically for this project&lt;/em&gt;)
&lt;/h3&gt;

&lt;p&gt;The initial set-up on the server has a few requirements. &lt;code&gt;pipenv&lt;/code&gt; and &lt;code&gt;pm2&lt;/code&gt; must then be installed.&lt;/p&gt;

&lt;p&gt;Following this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user must clone the repo on the server&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pipenv install&lt;/code&gt; to establish the same Python packages that the project is expecting (mainly discord.py and discord-py-slash-command)&lt;/li&gt;
&lt;li&gt;Have a token stored in the &lt;code&gt;.env&lt;/code&gt; file so that when the bot is run, it can talk to Discord and authenticate.&lt;/li&gt;
&lt;li&gt;Create a pm2 proccess -- &lt;code&gt;pm2 start "pipenv run python3 main.py" --name main_bot&lt;/code&gt; -- &lt;em&gt;Note: This project expects the proccess to be called "main_bot", but in reality, any name can be used.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Final Remarks
&lt;/h2&gt;

&lt;p&gt;This is not &lt;em&gt;entirely&lt;/em&gt; comprehensive, but hopefully is a good jumping off point for others. &lt;/p&gt;

&lt;p&gt;I am certain that it is not perfect, I have missed something obvious or that there is something simpler. &lt;/p&gt;

&lt;p&gt;One big gap, the release process relying on tags is very manual. The usage of Semantic Version could improve this.&lt;/p&gt;

</description>
      <category>python</category>
      <category>github</category>
      <category>discord</category>
    </item>
    <item>
      <title>A Dumb Sorting Algorithm</title>
      <dc:creator>Harvey Church</dc:creator>
      <pubDate>Fri, 05 Jun 2020 18:53:15 +0000</pubDate>
      <link>https://dev.to/harveychurch/a-dumb-sorting-algorithm-42kd</link>
      <guid>https://dev.to/harveychurch/a-dumb-sorting-algorithm-42kd</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is originally from my &lt;a href="//blog.hchurch.net"&gt;blog&lt;/a&gt;. I try and write semi-often, but only when I feel I have something interesting to say.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Mistake, but the question.
&lt;/h1&gt;

&lt;p&gt;As part of the preparation for interviews, I have been re-touching some of the foundational concepts in Computer Science. Some of the more interesting challenges have been relearning and implementing sorting algorithms in Python.&lt;/p&gt;

&lt;p&gt;Success has been... wrought with interesting mishaps where my understanding did not quite match the implementation I had written. One of these more interesting mistakes arose from creating a bubble sort.&lt;/p&gt;

&lt;p&gt;I will say now- I did successfully implement a bubble sort, but the first "mistake" did lead to an interesting question:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"What is the efficiency of this janky creation?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The concepts around efficiency are not new to me, but testing and saying what it is for a new algorithm where it is not obvious is a new area.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Algorithm
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/harveychurch/558a43e8e7054598dec1ad751cae8ac6"&gt;On a gist here - in case you ever feel (but I do not know why) inclined to copy it and try it out&lt;/a&gt;.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;somethingSort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;number_of_comparisons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;pointer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&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;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pointer&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;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;pointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    
            &lt;span class="n"&gt;pointer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;number_of_comparisons&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;  
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;number_of_comparisons&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Summarized: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Compare the current value and the next&lt;/li&gt;
&lt;li&gt;If Current is bigger then the next, swap them&lt;/li&gt;
&lt;li&gt;Reset the pointer back to 0 (go back to the beginning)&lt;/li&gt;
&lt;li&gt;ELSE increase the pointer by one (move onto the next pair of numbers and compare)&lt;/li&gt;
&lt;li&gt;If the pointer is at the current length of the input array, then we have finished sort&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I can see the problems very clearly when I summarize it like this. If you happen to be sorting at the end of the array, after you find a pair to swap, you will be sent right back to the beginning. This can cause the algorithm to re-check all the values.. at least twice.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Analysis
&lt;/h1&gt;

&lt;p&gt;Now, this is the bit I was mostly interested in, but unsure when it came to generating a conclusion. This is an area - scalability- where I believe there will always be lots of questions are left to be answered in some form, as to how things scale informs major design decisions.&lt;/p&gt;

&lt;p&gt;All calculations were run at least 10 times for each randomly generated list of up to 500 values long. The randomly generated numbers were between 1 and 100 inclusively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparisons
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wKKASoby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r2jhyk92c3gi16pjsfav.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wKKASoby--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r2jhyk92c3gi16pjsfav.JPG" alt="Comparisons" width="753" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The algorithm quite nicely (but unfortunately) scaled cubically. This being that for every input, it will do the cube of it in terms of the number of comparisons. For reference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick Sort has an average nlogn for comparisons - in the worst cases (but rarely) n²&lt;/li&gt;
&lt;li&gt;Bubble Sort has an average and worst of n² &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is an R² value attached to the graph, however this is not a good metric to use, as R² is primarily for comparing linear data to a line of best fit. This is not linear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Time
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gH0ZIkn1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/szhd33x26k599ocvlg37.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gH0ZIkn1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/szhd33x26k599ocvlg37.JPG" alt="Graph of Time" width="777" height="578"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the point of data is the area I am least certain on. The time was calculated by recording the time before the calculation and after then taking the difference. All calculations were left on the same computer with the same applications in the background.&lt;/p&gt;

&lt;p&gt;The point of the analysis I am not sure of is around what the equation of the correlation line is. As stated before, using R² is a bad choice for non-linear data. My indecision arises around how that value improves when increasing the power of the correlation line. So I am being hypocritical by using it to decide on the equation. It is somewhere between  n² and  n⁵.&lt;/p&gt;

&lt;h1&gt;
  
  
  Learning is slow but worth the climb
&lt;/h1&gt;

&lt;p&gt;This is still a new area for me. I really did enjoy re-visiting and programming sorting algorithms. The analysis itself might be a bit off, but I can only improve from there.&lt;/p&gt;

&lt;p&gt;I already have in mind improvements for this algorithm, and doing so might mean it is just a copy of one that already exists.&lt;/p&gt;

&lt;p&gt;Onwards to more learning about how to presenting data! (Any comments on what I did/could do better.. please provide away)&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>python</category>
      <category>efficiency</category>
    </item>
  </channel>
</rss>
