<?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: Wilson</title>
    <description>The latest articles on DEV Community by Wilson (@wilsonj806).</description>
    <link>https://dev.to/wilsonj806</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%2F206896%2Fe7d526aa-6890-47b1-b7e7-bb1628dfa883.jpeg</url>
      <title>DEV Community: Wilson</title>
      <link>https://dev.to/wilsonj806</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wilsonj806"/>
    <language>en</language>
    <item>
      <title>Five Things I Learned From Making NYC Arbor Logger</title>
      <dc:creator>Wilson</dc:creator>
      <pubDate>Mon, 04 May 2020 19:03:43 +0000</pubDate>
      <link>https://dev.to/wilsonj806/five-things-i-learned-from-making-nyc-arbor-logger-28c2</link>
      <guid>https://dev.to/wilsonj806/five-things-i-learned-from-making-nyc-arbor-logger-28c2</guid>
      <description>&lt;h1&gt;
  
  
  Five Things I Learned From Making NYC Arbor Logger
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Estimated Reading Time: 4.5 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I recently finished a simple full stack project and learned a good amount from it! I decided to share a couple of things that I think might help you on your developer journey.&lt;/p&gt;

&lt;p&gt;For some background on this project, I wanted to build a full stack project with a Flask backend, all while using open source data to make data visualizations on a React frontend. The scope of this project wasn't super large and since I didn't have to do any data analysis, processing the data is straight forwards.&lt;/p&gt;

&lt;p&gt;That said, here are five things I learned in the process of making this project!&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Automating basic tasks is not overkill
&lt;/h2&gt;

&lt;p&gt;This seems kind of obvious, but while writing Cypress tests and using TravisCI to validate my small app's code is overkill, using TravisCI to automate my deploys to Github Pages was definitely not. It saved a lot of repetitive work merging pull requests, then pulling those changes locally so that I can run my deploy script manually. Troubleshooting config issues might not be nearly as fun, but being able to "set it once and forget it" gives me time to work on other things and I'm definitely doing this for my future projects.&lt;/p&gt;

&lt;p&gt;And just as a quick illustration, I've added a small graphic overviewing both workflows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open Pull Request =&amp;gt; Validate/ merge changes =&amp;gt; Manually pull changes locally =&amp;gt; Manually run deploy script =&amp;gt; Repeat

Configure CI/ Troubleshoot CI config =&amp;gt; Open Pull Request =&amp;gt; Validate/ merge Changes =&amp;gt; CI handles deploy =&amp;gt; Repeat
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  2) Cypress and Jest would go great together if I made tests for both
&lt;/h2&gt;

&lt;p&gt;I learned about Cypress as an end To end testing framework(see this &lt;a href="https://kentcdodds.com/blog/unit-vs-integration-vs-e2e-tests"&gt;Kent C Dodds post&lt;/a&gt; if you're not sure what that is) a while ago and wanted to check it out for this project. Previously I used a combination of Jest and React Testing Library in my last project in order to weirdly handle unit tests, integration tests, and even end to end tests.&lt;/p&gt;

&lt;p&gt;That wasn't my most favorite thing in the world and as you can probably tell. Some of the tests for full app layouts probably belong in a series of end to end tests rather than leaving them in Jest.&lt;/p&gt;

&lt;p&gt;In the context of this app, the end to end tests were simple, but were very easy to implement in Cypress. There's not a lot of complicated functionality in the app, but being able to validate about 85% of the app with Cypress is very powerful. If I were to increasescale the complexity of the app, then I'm confident that I'd end up making tests with both Jest and Cypress, where Jest tests can focus on functionality of components, and Cypress tests can focus on functionality of the whole app.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) React.useEffect is about synchronizing state, not lifecycle
&lt;/h2&gt;

&lt;p&gt;Every once and a while you need to relearn or rethink something you thought you were familiar with. The &lt;code&gt;useEffect()&lt;/code&gt; hook was that for me during this project. I learned React before React Hooks was released, so I learned about class components and the component lifecycle. So, when I learned React Hooks, and the &lt;code&gt;useEffect()&lt;/code&gt; hook, I think I ended up thinking that &lt;code&gt;useEffect()&lt;/code&gt; was like &lt;code&gt;componentDidMount()&lt;/code&gt; and such.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;useEffect()&lt;/code&gt; hook is not that, and through Dan Abramov's &lt;a href="https://overreacted.io/a-complete-guide-to-useeffect/"&gt;article&lt;/a&gt; on &lt;code&gt;React.useEffect&lt;/code&gt; and Hooks, I had to relearn how that hook worked.&lt;/p&gt;

&lt;p&gt;The short version is that &lt;code&gt;useEffect()&lt;/code&gt; is more about data synchronization rather than lifecycle. So it's not that the hook goes through &lt;code&gt;componentWillMount&lt;/code&gt;, &lt;code&gt;componentShouldUpdate&lt;/code&gt;, but it's more that it's checking for changes, and then performing that effect if state and props in the dependency array chance.&lt;/p&gt;

&lt;p&gt;This gave me the chance to rework some wonky data flow and synchronization as a result of relearning previous mental models. In the end, I ended up dumping some unnecessary local state and made the component update values at very set times.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) Caching data is great
&lt;/h2&gt;

&lt;p&gt;I also took the time to learn to use Redis in this app. Granted there isn't a lot of caching going on, but being able to cache a dataset of 3000+ entries is pretty nice. If I wanted to go further, I could have converted the React app into an isomorphic app and take advantage of caching the entire generated markup. Scaling it up, if there was user authentication like for my last project, I could have cached the markup for authenticated users and send that to their browsers when requested for even faster interactivity times.&lt;/p&gt;

&lt;h2&gt;
  
  
  5) D3 is not a data visualization library
&lt;/h2&gt;

&lt;p&gt;D3 is not a data visualization library. This is kind of straight-forwards, but D3 doesn't not directly manipulate HTML elements. It does however, bind data to nodes in a tree and then decides what to render to the user based on the data. This is based on a Mike Bostock &lt;a href="https://bost.ocks.org/mike/selection/"&gt;article&lt;/a&gt; on how D3 selections work and it's super important because this single principle is what D3 is built around.&lt;/p&gt;

&lt;p&gt;It lets D3 be super flexible since you can programmatically adjust your markup as your data changes, but it comes at the cost of complexity. Understanding how D3 selects and binds data is super important and makes D3 much more powerful as a library as you can pretty much build any HTML you want with your data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fin
&lt;/h2&gt;

&lt;p&gt;And that's all! This list isn't meant to be super comprehensive, but is just a highlight of some of the things that I thought might be useful to share.&lt;/p&gt;

&lt;p&gt;You can check out the &lt;a href="https://wilsonj806.github.io/nyc-arbor-logger/"&gt;finished project&lt;/a&gt; there. The app is very very simple, but I enjoyed working on it and learned a ton of stuff from it!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Dockerizing a Python app</title>
      <dc:creator>Wilson</dc:creator>
      <pubDate>Wed, 15 Apr 2020 20:48:48 +0000</pubDate>
      <link>https://dev.to/wilsonj806/dockerizing-a-python-app-2ee</link>
      <guid>https://dev.to/wilsonj806/dockerizing-a-python-app-2ee</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&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%2Fimgs.xkcd.com%2Fcomics%2Fpython_environment_2x.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%2Fimgs.xkcd.com%2Fcomics%2Fpython_environment_2x.png" alt="relevant xkcd"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python's one of the more popular programming languages with a wide variety of applications, from building backends to creating a neural network. However, keeping your Python environment consistent between projects can be a pain as seen from the above.&lt;/p&gt;

&lt;p&gt;This is where Docker comes in. Docker allows for containerization of applications, which means you can run isolated instances of your services and applications. In addition, Docker gives you the ability to connect your apps and services together with Docker Compose, which makes Python apps very convenient to build.&lt;/p&gt;

&lt;p&gt;Note that all the code referenced in this article comes from this &lt;a href="https://github.com/wilsonj806/nyc-tree-data-fetcher/tree/0-special.release" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;. This is a live app, and while the code in that particular release is &lt;strong&gt;not&lt;/strong&gt; production ready, it still can run everything through Docker.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Docker?
&lt;/h2&gt;

&lt;p&gt;What is Docker anyways? I went over it briefly above, and as mentioned, it's software that lets you containerize apps and services. The benefit of it is that instead of installing and using multiple versions of Python and managing multiple virtual environments, you can have Docker build each app separately with their own isolated environments.&lt;/p&gt;

&lt;p&gt;This means we don't need to run &lt;code&gt;python -m venv venv&lt;/code&gt; every time we build a new project, so as long as we setup a &lt;code&gt;DockerFile&lt;/code&gt; and a &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Images, Containers and Composing
&lt;/h3&gt;

&lt;p&gt;Cool so with that out of the way, we need to overview some quick vocab.&lt;/p&gt;

&lt;p&gt;First is Docker images. An image in Docker, is basically an immutable "snapshot" of an app. It includes instructions to start the app in a new container, and can be built using other images. The immutability is important as it allows us to have multiple versions of the same app, without having the version of the image collide.&lt;/p&gt;

&lt;p&gt;Second is Docker containers. A Docker container is the instance of the app that we run based off of our image. It's analogous to a reproduction of the aforementioned "snapshot" and cannot be shared. We can however, spin up as many Docker containers of a particular image as we want, which is super handy for databases and similar services!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Docker
&lt;/h2&gt;

&lt;p&gt;If you don't have it already, you'll need to install &lt;a href="https://www.docker.com/products/docker-desktop" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt;. If you already have it and know how to go through it, then you can skip to the &lt;a href=""&gt;next section&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'll also briefly go over some of the commands you can run with the Docker CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  docker image ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;docker image ls&lt;/code&gt; lists all of the images currently available on your computer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  docker container ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;docker container ls&lt;/code&gt; lists all currently started/ active containers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  docker container ls -a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;docker container ls -a&lt;/code&gt; lists all containers whether they've been started or if they're active. The &lt;code&gt;-a&lt;/code&gt; flag is short for &lt;code&gt;--all&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  docker container rm &amp;lt;first 3 symbols of the container ID or container name&amp;gt; [...other containers you want to remove]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;docker container rm&lt;/code&gt; removes the listed containers. Note that you need either the first 3 symbols of the contaienr ID/ the container name AND the container can't be running before you remove a container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  docker [COMMAND] --help
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The help flag is super helpful and can be used with any command. It'll give you a list of options and also general instructions on how to use the commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Docker Env
&lt;/h2&gt;

&lt;p&gt;With that said, to set up a Docker env, we need a couple of things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;we need to make an image of our app for Docker to use&lt;/li&gt;
&lt;li&gt;we need to somehow coordinate all of the databases that our app uses&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the first point, that's what a &lt;code&gt;Dockerfile&lt;/code&gt; is for. A &lt;code&gt;Dockerfile&lt;/code&gt; is a file that defines the command line arguments required to set up and run the app. In English, it's a file that specifies the bare minimum required to set up and run the app.&lt;/p&gt;

&lt;p&gt;Below is an example of a &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.8&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /src&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./requirements.txt .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 5000&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["flask", "run", "--host", "0.0.0.0"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What's in the Dockerfile
&lt;/h3&gt;

&lt;p&gt;So a quick overview of what everything is:&lt;/p&gt;

&lt;p&gt;The first line specifies that we're basing our app's image from the Python 3.8 image&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;since we can build our image off of other images, we're taking full advantage of that&lt;/li&gt;
&lt;li&gt;additional images can be found in &lt;a href="https://cloud.docker.com/repository/list" rel="noopener noreferrer"&gt;DockerHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;we specify what tag/ version we want with a colon followed with the tag, so here &lt;code&gt;python:3.8&lt;/code&gt; specifies &lt;strong&gt;Python&lt;/strong&gt; at the &lt;strong&gt;3.8&lt;/strong&gt; tag&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second line sets up the working directory for the container. This is important as that'll be where our app's files will live.&lt;/p&gt;

&lt;p&gt;The third line copies the &lt;code&gt;requirements.txt&lt;/code&gt; file into our working directory. We could copy everything all at once but there's actually an important reason we don't that'll be explained next.&lt;/p&gt;

&lt;p&gt;The fourth line runs whatever command we listed. So here it's installing our Python packages from the &lt;code&gt;requirements.txt&lt;/code&gt; file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;we do this separately as Docker caches any external packages that we might need, depending on changes in &lt;code&gt;requirements.txt&lt;/code&gt;(or &lt;code&gt;package.json&lt;/code&gt; for NPM)&lt;/li&gt;
&lt;li&gt;if we didn't do that, then Docker would just end up dumping the cached packages everytime, wasting a lot of time that could have been saved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fifth line copies the rest of the files from our app's directory into the working directory. If we wanted to, we could also add it to a different sub-directory and it'd look like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . ./my-subdirectory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sixth line exposes a port for us to access the container. So it'd be port 5000 here.&lt;/p&gt;

&lt;p&gt;The last line states the default command to execute on container start. Note that every part of the command is in an array.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Note that this array of strings is the preferred way to do it, and that we &lt;strong&gt;must&lt;/strong&gt; wrap each command fragment needs to be wrapped in double quotes(") as it's parsed as a JSON array&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Docker Compose
&lt;/h3&gt;

&lt;p&gt;Cool, so what about databases. Sure we can run the database locally, but since Docker also has database images, we can actually run as many containers with our database on it as we want.&lt;/p&gt;

&lt;p&gt;There's a big problem though, we don't want to manually create and start every single service that our app depends on. Sure it's fine if we have one database, but what we have two different databases and another app/ service that needs it's own database?&lt;/p&gt;

&lt;p&gt;This is where &lt;code&gt;docker-compose&lt;/code&gt; comes in(and Kubernetes as you scale up, but this is a different topic). Rather than having to manually start and create containers of the services your app depends on, you can use a &lt;code&gt;docker-compose.yml&lt;/code&gt; file to automate large portions of that.&lt;/p&gt;

&lt;p&gt;Check out the following link to an example &lt;a href="https://github.com/wilsonj806/nyc-tree-data-fetcher/blob/1b545fac7bde26135a3cc61681c46aaa3f912087/docker-compose.yml" rel="noopener noreferrer"&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt; file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sadly this won't be a full guide on making a Docker Compose file, but I'll overview the parts.&lt;/p&gt;

&lt;p&gt;So in the file we have the below(plus or minus some comments):&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.5'&lt;/span&gt; &lt;span class="c1"&gt;# Docker compose version&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="c1"&gt;# Binding the current working directory to the new container&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/&lt;/span&gt;
    &lt;span class="c1"&gt;# The working directory in the app Dockerfile&lt;/span&gt;
    &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
    &lt;span class="na"&gt;links&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app-redis&lt;/span&gt;
    &lt;span class="c1"&gt;# ENV configuration&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
    &lt;span class="c1"&gt;# Additional app secrets&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;APP_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/run/secrets/app_token&lt;/span&gt;
    &lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app_token&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;5000:5000'&lt;/span&gt;
  &lt;span class="na"&gt;app-redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:5&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;6379:6379'&lt;/span&gt;
&lt;span class="c1"&gt;# App secret registration&lt;/span&gt;
&lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app_token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app_token.txt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Broadly speaking there are three major parts to the compose file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the version of Docker Compose we want

&lt;ul&gt;
&lt;li&gt;specifying the version of Docker Compose is important as certain properties aren't available in other versions, check the &lt;a href="https://docs.docker.com/compose/compose-file/" rel="noopener noreferrer"&gt;Docker Compose v3 docs&lt;/a&gt; for more&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;registering services&lt;/li&gt;

&lt;li&gt;registering container secrets&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Within the section for registering our services, we have the below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;configuring our Python app container

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;linking&lt;/strong&gt; our container to another service(Redis)&lt;/li&gt;
&lt;li&gt;binding our working directory so that we can live update the container&lt;/li&gt;
&lt;li&gt;adding an .env file&lt;/li&gt;
&lt;li&gt;adding our app secret&lt;/li&gt;
&lt;li&gt;exposing ports and start command&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;configuring out Redis container

&lt;ul&gt;
&lt;li&gt;adding the image to build the container from&lt;/li&gt;
&lt;li&gt;exposing ports&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Note that the &lt;code&gt;links&lt;/code&gt; property is there to explicitly say that the &lt;code&gt;app-redis&lt;/code&gt; service is a dependency for our Python app. It means that we access our database differently in our Flask app than normal but we'll get to that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Required Updates to Our Python App
&lt;/h2&gt;

&lt;p&gt;Now that we have out &lt;code&gt;docker-compose.yml&lt;/code&gt; file up, we can't access our Redis instance the same way we might think. So rather than using &lt;code&gt;localhost&lt;/code&gt; to have our Python app access our Redis instance, we need to update it so that it uses the service name instead like so:&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="c1"&gt;# Fetch.py
# Std lib imports
&lt;/span&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;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&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="c1"&gt;## Lib Imports
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="c1"&gt;# Global Module Var
&lt;/span&gt;&lt;span class="n"&gt;isDocker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;IS_DOCKER&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;cacheHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app-redis&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;# ...Extra code
&lt;/span&gt;&lt;span class="n"&gt;red_cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cacheHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6379&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# ...Rest of the module's implementation
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty quick and easy, and with that we can run &lt;code&gt;docker-compose up&lt;/code&gt; inside our app directory and start the Flask app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So we summarized how to quickly Dockerize a Python app. This involved the below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;creating a Dockerfile with:

&lt;ul&gt;
&lt;li&gt;the image we're basing the app off of&lt;/li&gt;
&lt;li&gt;the contents we're copying&lt;/li&gt;
&lt;li&gt;any terminal commands we want to run&lt;/li&gt;
&lt;li&gt;a startup command&lt;/li&gt;
&lt;li&gt;a port to expose&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;creating a &lt;code&gt;docker-compose.yml&lt;/code&gt; file which had:

&lt;ul&gt;
&lt;li&gt;the version of Docker Compose&lt;/li&gt;
&lt;li&gt;a list of the services that will be created and run&lt;/li&gt;
&lt;li&gt;said services will need to specify if they're linked to one another&lt;/li&gt;
&lt;li&gt;in addition, the service with our Python app had additional .env and secret setup&lt;/li&gt;
&lt;li&gt;any secrets we wanted in our app&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The end result is an app whose dependencies are fulfilled by Docker &lt;em&gt;rather than&lt;/em&gt; the local machine. This results in a development environemnt that performs and is set up &lt;em&gt;consistently&lt;/em&gt; every single time.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>How I Upgraded My Portfolio</title>
      <dc:creator>Wilson</dc:creator>
      <pubDate>Fri, 06 Mar 2020 22:00:55 +0000</pubDate>
      <link>https://dev.to/wilsonj806/how-i-upgraded-my-portfolio-19f4</link>
      <guid>https://dev.to/wilsonj806/how-i-upgraded-my-portfolio-19f4</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Hey, so if you're reading this, that means my new portfolio is up in some way shape or form. It's light on content for now, but this is wildly preferable to what I had before. This article is a short run down on the upgrade process.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Was v2.0.0?
&lt;/h2&gt;

&lt;p&gt;Before we can get into the nitty gritty of how I upgraded my portfolio, I feel it's important to go over the old portfolio. The old portfolio was a static site built with plain HTML and Sass hosted on Github Pages. I made it mobile first, and I tried to make the project highlights as easy and quick of a browsing experience as possible.&lt;/p&gt;

&lt;p&gt;Design-wise, I had a full research, mockup, iterate process and the end result, while simple, was pretty good.&lt;/p&gt;

&lt;p&gt;Since it was entirely static assets, it was quite a lot of work to update the portfolio with new content or pages so that fell off very quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  v3.0 Requirements
&lt;/h2&gt;

&lt;p&gt;v2.0 was pretty nice at the time, but it's been quite literally 2 years since I made it so some upgrades were necessary. At the moment, I'm very comfortable with React, and I've started to get into using Vue, so I wanted to use one of the two to build my portfolio. In addition, I wanted to be able to easily add new content into the site without having to manually generate new pages.&lt;/p&gt;

&lt;p&gt;Deciding between Vue and React was actually pretty easy. I knew my app was going to be very simple, and require very little state to hang around. That kind of disqualifies React as writing JSX feels more involved than writing with Vue's templating syntax.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As an aside, the choice between the two isn't actually that important. Both frameworks would have done the job fine, and choosing one framework means you're also taking on the downsides of that framework.&lt;/p&gt;

&lt;p&gt;In this situation, it means amongst other things, having a smaller community to find help in, more rigid rendering rules, and the framework having a potentially shaky future since it was developed outside of a company.&lt;/p&gt;

&lt;p&gt;Basically, don't get hung on what framework is better, use the tool that's right for the job, and don't get  dogmatic about someone's tool choices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As for how I handled content, there are a multitiude of options(CMS, Headless CMS, etc), but the one I wanted to check out was static site generation. Static site generation(or generators) lets you use React or Vue to build your pages and components, while also letting you build pages from your static content and data. In the end the static site generator builds all of the required pages from the data and from the templates you made. Very slick!&lt;/p&gt;

&lt;p&gt;Vue's static site generation framework is &lt;a href="https://gridsome.org/"&gt;Gridsome&lt;/a&gt;. It uses GraphQL to query your data, and while it's super young, it's still solid. It also features a growing plugin library that can handle a variety of things from finding and including files into GraphQL, to transforming Markdown into your Vue pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing The Layout
&lt;/h2&gt;

&lt;p&gt;Next up was designing a layout that would present everything I wanted in a user-friendly way. The current layout wasn't bad, but I felt that it had a bit too much going on in comparison to what I wanted. So went and did some research on web dev portfolios again with an emphasis on simplistic layouts and designs.&lt;/p&gt;

&lt;p&gt;I ended up with the below list of portfolios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://timmyomahony.com/"&gt;Tim O'Mahony&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benbate.com/"&gt;Ben Bate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.taniarascia.com/"&gt;Tania Rascia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above portfolios, while simplistic, were all stylistically unique. Imitating that would be difficult since I don't have nearly as much content to put on there, but is still worth doing. I ended up doing a layout that was a wombo combo of the three in some way, which you can find on my &lt;a href="https://wilsonjiang.netlify.com/"&gt;portfolio&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Just like the v2.0 portfolio, it features cards for projects, and a short blurb, but the big difference is there's a dedicated About page and Projects page. In addition, some pages you can't actively navigate to right now as there isn't enough content to justify it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding
&lt;/h2&gt;

&lt;p&gt;The actual coding part of this was pretty wicked fast once I felt comfortable with what I planned to do. In comparison to my first portfolio, which took a month, this took about 12 days. There was some configuration stuff I had to mess with and several layout changes along the way, but other than that the development process was pretty fluid.&lt;/p&gt;

&lt;p&gt;Writing Vue templates felt faster than writing a React component in a lot of ways, and conditional rendering feels way nicer. In addition, the simple layout meant very simple styling, so most of the styling didn't grow long enough to be extracted. Not to mention, that there was very little JavaScript that needed to be written, which meant less reasoning about what's changing and what needs to render and etc.&lt;/p&gt;

&lt;p&gt;I did hit a small roadbump in querying for my data via GraphQL, but the bundled GraphQL GUI is super handy for testing and there's very minimal special Gridsome syntax to make sure we can query our data. Getting past that was not a huge issue and the GUI basically made everything possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The portfolio's "done", but there's some extra tasks to do. First and foremost, I need to add more content; projects-wise, 3 is probably fine to start, but only having one blog article is not great. I also need to add in the Blogs page and the Contact page, with the contact page being a bit lower priority(unless I go freelancing).&lt;/p&gt;

&lt;p&gt;Other than that, there's rolling tasks like the below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fix wonky responsiveness&lt;/li&gt;
&lt;li&gt;update sections with better designs as I get better at design&lt;/li&gt;
&lt;li&gt;update the code to keep up with future releases(Vue, Gridsome, etc)&lt;/li&gt;
&lt;li&gt;add extra pages for other hobbies and the like&lt;/li&gt;
&lt;li&gt;pagination!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Obviously the list isn't comprehensive, and there's definitely going to be more that will be done as time goes on.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
