diff --git a/about/index.html b/about/index.html index cdafefc..be6435c 100644 --- a/about/index.html +++ b/about/index.html @@ -1 +1,101 @@ - About | Tom Carrick

About

About this site, not about me.

This site is made with Pelican, a Python-powered static site generator. There are a lot of SSGs out there, but I went with this one as it's written in Python, so I can easily extend it if I need to.

I wrote the theme myself. It's designed to be minimalist, have semantic markup, clean, modern CSS and use only system fonts. All these help keep the page size to a minimum. There are currently no cookies, and no plans to add any. This is not for any ideoligcal reason — I just don't need them.

The design has incorporated accessibility from the start. It should pass WCAG 2.1 AA. Getting it AAA compliant would be a lot more work for almost no benefit, so it'll only happen if I have some free time and nothing else to do. However, that doesn't mean I won't improve the accessibility generally.

The site is hosted on GitHub Pages for the sake of simplicity and not having to needlessly throw money away.

\ No newline at end of file + + + + About | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

About

+ About this site, not about me. + +
+ +
+

This site is made with Pelican, a Python-powered static site generator. +There are a lot of SSGs out there, but I went with this one as it's written in Python, +so I can easily extend it if I need to.

+

I wrote the theme myself. It's designed to be minimalist, have semantic markup, +clean, modern CSS and use only system fonts. All these help keep the page size to a +minimum. There are currently no cookies, and no plans to add any. +This is not for any ideoligcal reason — I just don't need them.

+

The design has incorporated accessibility from the start. It should pass WCAG 2.1 AA. +Getting it AAA compliant would be a lot more work for almost no benefit, so it'll only +happen if I have some free time and nothing else to do. However, that doesn't mean I +won't improve the accessibility generally.

+

The site is hosted on GitHub Pages for the sake of simplicity and not having +to needlessly throw money away.

+ +
+ +
+
+ + + \ No newline at end of file diff --git a/archives.html b/archives.html index 3633b1c..241253a 100644 --- a/archives.html +++ b/archives.html @@ -1 +1,79 @@ - Archives | Tom Carrick

Archives for Tom Carrick

Faster dependabot updates with groups
Automatically updating dependencies with dependabot
Testing Django data migrations
\ No newline at end of file + + + + Archives | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + +
+

Archives for Tom Carrick

+ +
+
+
Faster dependabot updates with groups
+
+
Automatically updating dependencies with dependabot
+
+
Testing Django data migrations
+
+
+ + + \ No newline at end of file diff --git a/author/tom-carrick.html b/author/tom-carrick.html index b003229..1dba785 100644 --- a/author/tom-carrick.html +++ b/author/tom-carrick.html @@ -1 +1,143 @@ - Articles by Tom Carrick | Tom Carrick

Articles by Tom Carrick

  1. Automatically updating dependencies with dependabot

    Published: | Updated:

    Outdated packages can open your application up to security issues. Moreover, newer versions will often have performance improvements, bug fixes and generally fewer problems. Keeping them up to date over multiple codebases can be quite painful, but it's possible to bring this effort down to close to zero with a …

  2. Testing Django data migrations

    Published:

    You probably already know the value of testing your code. Your Django migrations are code, therefore you should test them. However, testing data migrations in particular can be tricky, and there's no documentation on how to do it.

    Typically your schema migrations don't need any testing as your migrations are …

\ No newline at end of file + + + + Articles by Tom Carrick | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Articles by Tom Carrick

+
+
+
    +
  1. + +
  2. +
  3. +
    +
    +

    + + Automatically updating dependencies with dependabot + +

    + Published: + | Updated: +
    +

    Outdated packages can open your application up to security issues. Moreover, +newer versions will often have performance improvements, bug fixes and generally +fewer problems. Keeping them up to date over multiple codebases can be quite +painful, but it's possible to bring this effort down to close to zero with a …

    +
    +
  4. +
  5. +
    +
    +

    + + Testing Django data migrations + +

    + Published: +
    +

    You probably already know the value of testing your code. +Your Django migrations are code, therefore you should test them. +However, testing data migrations in particular can be tricky, +and there's no documentation on how to do it.

    +

    Typically your schema migrations don't need any testing as your +migrations are …

    +
    +
  6. +
+
+
+
+ + + \ No newline at end of file diff --git a/authors.html b/authors.html index e2cd109..ace8426 100644 --- a/authors.html +++ b/authors.html @@ -1 +1,73 @@ - Authors | Tom Carrick

Authors on Tom Carrick

\ No newline at end of file + + + + Authors | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + +
+

Authors on Tom Carrick

+ +
+ + + \ No newline at end of file diff --git a/blog/automatically-updating-dependencies-with-dependabot/index.html b/blog/automatically-updating-dependencies-with-dependabot/index.html index 7e29d6f..2980af6 100644 --- a/blog/automatically-updating-dependencies-with-dependabot/index.html +++ b/blog/automatically-updating-dependencies-with-dependabot/index.html @@ -1,51 +1,210 @@ - Automatically updating dependencies with dependabot | Tom Carrick

Automatically updating dependencies with dependabot

Published: | Updated:

Outdated packages can open your application up to security issues. Moreover, newer versions will often have performance improvements, bug fixes and generally fewer problems. Keeping them up to date over multiple codebases can be quite painful, but it's possible to bring this effort down to close to zero with a bit of up-front effort.

This post applies only if you're hosting your code on GitHub. If not, there are managed options for dependency upgrades, such as Snyk. It's very expensive, but does a lot of other things too. If you are on GitHub, this is a free or cheap alternative.

First, a few pre-requisites. You'll need to ensure "Allow auto-merge" is enabled in your repository settings. You should also configure dependabot security alerts in the "Security" tab. These alerts happen outside of the dependabot schedule we'll set up later, and will ensure you get critical security updates as quickly as possible. You'll also need to make sure GitHub Actions is enabled for your repository.

Next, you'll need to create a new file for the dependabot configuration:

.github/dependabot.yml

version: 2
-updates:
-  - package-ecosystem: "github-actions"
-    assignees:
-      - "<your_github_username>"
-    directory: "/"
-    reviewers:
-      - "<your_github_username>"
-    schedule:
-      day: "monday"
-      interval: "weekly"
-      time: "09:00"
-      timezone: "Europe/Amsterdam"
-  - package-ecosystem: "pip"
-    allow:
-      - dependency-type: all
-    assignees:
-      - "<your_github_username>"
-    directory: "/"
-    reviewers:
-      - "<your_github_username>"
-    schedule:
-      interval: "daily"
-      time: "09:00"
-      timezone: "Europe/Amsterdam"
-

The configuration is quite straightforward. Note there are two package-ecosystem sections defined. One of these is for pip, which will also work for pipenv and poetry. The other will keep any GitHub actions you use up to date. We'll be using one of these soon, so it seemed good to add it. You can set the schedule however makes sense for your workflow. You don't need to set assignees and reviewers, but I like to add them so they show up in my GitHub notifications and I can make sure I don't miss anything. Not every update will be able to be merged automatically, so it's good to know about them.

One other important thing here is the allow section. Here I've set dependency-type to all, which means that sub-dependencies will also be updated. Without this, only explicitly defined dependencies will be updated.

Other configuration options are available.

Adding this file is enough for dependabot to submit pull requests on your repo with package updates. We need to do a bit more to get them merging automatically. For this, we need GitHub Actions.

Warning

You should only have your dependencies merge automatically if you have an exhaustive CI set up. Otherwise, you may be vulnerable to obnoxious developers and supply chain attacks. Supply chain attacks may still get through your CI however, so you should judge the level of risk you're willing to tolerate.

We'll create a new file, .github/workflows/dependabot-automerge.yml.

name: Dependabot auto-merge
-on: pull_request_target
-
-permissions:
-  pull-requests: write
-  contents: write
-
-jobs:
-  dependabot-auto-merge:
-    runs-on: ubuntu-latest
-    if: ${{ github.actor == 'dependabot[bot]' }}
-    env:
-      PR_URL: ${{ github.event.pull_request.html_url }}
-      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-    steps:
-      - name: Dependabot metadata
-        id: metadata
-        uses: dependabot/fetch-metadata@v1.1.1
-        with:
-          github-token: "${{ secrets.GITHUB_TOKEN }}"
-      - name: Approve PR
-        run: gh pr review --approve "$PR_URL"
-      - name: Merge PR
-        if: ${{ steps.metadata.outputs.update-type != 'version-update:semver-major' }}
-        run: gh pr merge --auto --squash "$PR_URL"
-

Exactly what you put in this file will depend on your workflow. For example, if your pull requests do not require reviews, you can omit that section. Are you feeling risk-averse? Remove the auto-merge, or use it only for patch versions. The opposite? Remove the conditional and auto-merge everything.

This example will approve every dependabot pull request, and merge any non-major semver versions automatically so long as all required checks pass. For major versions, I like to review them to make sure nothing will break. If the project isn't using semantic versioning, it's a little difficult to know what happens here, however. My assumption is that it'll do its best to figure it out and assume it's a major version. But it may be that if it doesn't look like it's using semver, it will not count as a major update and will be merged automatically. If anyone does know the answer to this, I would love to hear it. Luckily, most packages use something similar to semantic versioning these days so I haven't yet had any problems. I'll update this post if I notice any.

I hope this saves you some time you could be using for something more fun.

\ No newline at end of file + + + + Automatically updating dependencies with dependabot | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Automatically updating dependencies with dependabot

+ Published: + | Updated: + +
+ +
+

Outdated packages can open your application up to security issues. Moreover, +newer versions will often have performance improvements, bug fixes and generally +fewer problems. Keeping them up to date over multiple codebases can be quite +painful, but it's possible to bring this effort down to close to zero with a bit +of up-front effort.

+

This post applies only if you're hosting your code on GitHub. If not, there are +managed options for dependency upgrades, such as Snyk. It's very expensive, +but does a lot of other things too. If you are on GitHub, this is a free or +cheap alternative.

+

First, a few pre-requisites. You'll need to ensure "Allow auto-merge" is +enabled in your repository settings. You should also configure dependabot +security alerts in the "Security" tab. These alerts happen outside of the +dependabot schedule we'll set up later, and will ensure you get critical security +updates as quickly as possible. You'll also need to make sure GitHub Actions +is enabled for your repository.

+

Next, you'll need to create a new file for the dependabot configuration:

+

.github/dependabot.yml

+
version: 2
+updates:
+  - package-ecosystem: "github-actions"
+    assignees:
+      - "<your_github_username>"
+    directory: "/"
+    reviewers:
+      - "<your_github_username>"
+    schedule:
+      day: "monday"
+      interval: "weekly"
+      time: "09:00"
+      timezone: "Europe/Amsterdam"
+  - package-ecosystem: "pip"
+    allow:
+      - dependency-type: all
+    assignees:
+      - "<your_github_username>"
+    directory: "/"
+    reviewers:
+      - "<your_github_username>"
+    schedule:
+      interval: "daily"
+      time: "09:00"
+      timezone: "Europe/Amsterdam"
+
+

The configuration is quite straightforward. Note there are two package-ecosystem +sections defined. One of these is for pip, which will also work for pipenv and poetry. +The other will keep any GitHub actions you use up to date. We'll be using one of +these soon, so it seemed good to add it. You can set the schedule however makes sense +for your workflow. You don't need to set assignees and reviewers, but I like to add +them so they show up in my GitHub notifications and I can make sure I don't miss +anything. Not every update will be able to be merged automatically, so it's good +to know about them.

+

One other important thing here is the allow section. Here I've set +dependency-type to all, which means that sub-dependencies will also be updated. +Without this, only explicitly defined dependencies will be updated.

+

Other configuration options are available.

+

Adding this file is enough for dependabot to submit pull requests on your repo with +package updates. We need to do a bit more to get them merging automatically. For this, +we need GitHub Actions.

+
+

Warning

+

You should only have your dependencies merge automatically if you have an +exhaustive CI set up. Otherwise, you may be vulnerable to obnoxious developers +and supply chain attacks. Supply chain attacks may still get through your CI +however, so you should judge the level of risk you're willing to tolerate.

+
+

We'll create a new file, .github/workflows/dependabot-automerge.yml.

+
name: Dependabot auto-merge
+on: pull_request_target
+
+permissions:
+  pull-requests: write
+  contents: write
+
+jobs:
+  dependabot-auto-merge:
+    runs-on: ubuntu-latest
+    if: ${{ github.actor == 'dependabot[bot]' }}
+    env:
+      PR_URL: ${{ github.event.pull_request.html_url }}
+      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    steps:
+      - name: Dependabot metadata
+        id: metadata
+        uses: dependabot/fetch-metadata@v1.1.1
+        with:
+          github-token: "${{ secrets.GITHUB_TOKEN }}"
+      - name: Approve PR
+        run: gh pr review --approve "$PR_URL"
+      - name: Merge PR
+        if: ${{ steps.metadata.outputs.update-type != 'version-update:semver-major' }}
+        run: gh pr merge --auto --squash "$PR_URL"
+
+

Exactly what you put in this file will depend on your workflow. For example, if +your pull requests do not require reviews, you can omit that section. Are you +feeling risk-averse? Remove the auto-merge, or use it only for patch versions. +The opposite? Remove the conditional and auto-merge everything.

+

This example will approve every dependabot pull request, and merge any non-major +semver versions automatically so long as all required checks pass. +For major versions, I like to review them to make sure nothing will break. +If the project isn't using semantic versioning, it's a little difficult to know +what happens here, however. My assumption is that it'll do its best to figure it out +and assume it's a major version. But it may be that if it doesn't look like it's using +semver, it will not count as a major update and will be merged automatically. +If anyone does know the answer to this, I would love to hear it. Luckily, most +packages use something similar to semantic versioning these days so I haven't yet had any +problems. I'll update this post if I notice any.

+

I hope this saves you some time you could be using for something more fun.

+ +
+ + +
+
+ + + \ No newline at end of file diff --git a/blog/faster-dependabot-updates-with-groups/index.html b/blog/faster-dependabot-updates-with-groups/index.html index 633db8f..2baba22 100644 --- a/blog/faster-dependabot-updates-with-groups/index.html +++ b/blog/faster-dependabot-updates-with-groups/index.html @@ -1,13 +1,136 @@ - Faster dependabot updates with groups | Tom Carrick

Faster dependabot updates with groups

Published:

Back in 2022, I wrote about automatically updating dependencies with dependabot. However, this can be quite tedious. If you have a lot of dependencies, or even if you don't, you'll likely get spammed with many pull requests on your scheduled update time. This can be quite annoying, especially if you have a lot of repositories.

Every time you merge one of these pull requests, if you're strict about only merging branches when they're up to date with the base branch, you'll have to update the next pull request, wait for all your CI checks to pass, burning through your GitHub actions minutes (or other CI credits), and warming the planet a little. And then, the next PR. And the next. And the next.

Now, you can just YOLO merge without updating the branch if you're happy to take the risk. And it doesn't take much time to update the branch, you can spread this out over a day in those few minutes between tasks, or when pretending to pay attention in a meeting, but you don't need to do any of this anymore.

Last year, GitHub released a grouping feature for dependabot. You can now group your dependencies in the dependabot configuration like so:

.github/dependabot.yml

version: 2
-- package-ecosystem: "pip"
-  directory: "/"
-  groups:
-    all:
-      patterns:
-        - "*"
-  schedule:
-    day: "monday"
-    interval: "weekly"
-    time: "09:00"
-    timezone: "Europe/Amsterdam"
-

I simplified the configuration a bit from last time, but the important thing is the groups key. This allows you to group your dependencies by a pattern. In this case, I'm grouping all dependencies with the pattern *. This will group all dependencies together, so you'll only get one pull request for all your dependencies, rather than one for each. You can have multiple groups, so you can group your dependencies however you like, although I don't personally find much utility in this.

A huge time saver, and a huge annoyance saver.

\ No newline at end of file + + + + Faster dependabot updates with groups | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Faster dependabot updates with groups

+ Published: + +
+ +
+

Back in 2022, I wrote about automatically updating dependencies with dependabot. +However, this can be quite tedious. If you have a lot of dependencies, or even +if you don't, you'll likely get spammed with many pull requests on your scheduled +update time. This can be quite annoying, especially if you have a lot of repositories.

+

Every time you merge one of these pull requests, if you're strict about only merging +branches when they're up to date with the base branch, you'll have to update the next +pull request, wait for all your CI checks to pass, burning through your GitHub actions +minutes (or other CI credits), and warming the planet a little. And then, the next PR. +And the next. And the next.

+

Now, you can just YOLO merge without updating the branch if you're happy to take the risk. +And it doesn't take much time to update the branch, you can spread this out over a day in +those few minutes between tasks, or when pretending to pay attention in a meeting, +but you don't need to do any of this anymore.

+

Last year, GitHub released a grouping feature for dependabot. +You can now group your dependencies in the dependabot configuration like so:

+

.github/dependabot.yml

+
version: 2
+- package-ecosystem: "pip"
+  directory: "/"
+  groups:
+    all:
+      patterns:
+        - "*"
+  schedule:
+    day: "monday"
+    interval: "weekly"
+    time: "09:00"
+    timezone: "Europe/Amsterdam"
+
+

I simplified the configuration a bit from last time, but the important thing is the +groups key. This allows you to group your dependencies by a pattern. In this case, +I'm grouping all dependencies with the pattern *. This will group all dependencies +together, so you'll only get one pull request for all your dependencies, rather than +one for each. You can have multiple groups, so you can group your dependencies however +you like, although I don't personally find much utility in this.

+

A huge time saver, and a huge annoyance saver.

+ +
+ + +
+
+ + + \ No newline at end of file diff --git a/blog/index.html b/blog/index.html index 49717a4..1fcbe76 100644 --- a/blog/index.html +++ b/blog/index.html @@ -1 +1,143 @@ - Tom Carrick: Web development consultat using Pythong & Django

All articles

  1. Automatically updating dependencies with dependabot

    Published: | Updated:

    Outdated packages can open your application up to security issues. Moreover, newer versions will often have performance improvements, bug fixes and generally fewer problems. Keeping them up to date over multiple codebases can be quite painful, but it's possible to bring this effort down to close to zero with a …

  2. Testing Django data migrations

    Published:

    You probably already know the value of testing your code. Your Django migrations are code, therefore you should test them. However, testing data migrations in particular can be tricky, and there's no documentation on how to do it.

    Typically your schema migrations don't need any testing as your migrations are …

\ No newline at end of file + + + + Tom Carrick: Web development consultant using Python & Django + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

All articles

+
+
+
    +
  1. + +
  2. +
  3. +
    +
    +

    + + Automatically updating dependencies with dependabot + +

    + Published: + | Updated: +
    +

    Outdated packages can open your application up to security issues. Moreover, +newer versions will often have performance improvements, bug fixes and generally +fewer problems. Keeping them up to date over multiple codebases can be quite +painful, but it's possible to bring this effort down to close to zero with a …

    +
    +
  4. +
  5. +
    +
    +

    + + Testing Django data migrations + +

    + Published: +
    +

    You probably already know the value of testing your code. +Your Django migrations are code, therefore you should test them. +However, testing data migrations in particular can be tricky, +and there's no documentation on how to do it.

    +

    Typically your schema migrations don't need any testing as your +migrations are …

    +
    +
  6. +
+
+
+
+ + + \ No newline at end of file diff --git a/blog/tags/dependencies/index.html b/blog/tags/dependencies/index.html index ef69c85..d422d97 100644 --- a/blog/tags/dependencies/index.html +++ b/blog/tags/dependencies/index.html @@ -1 +1,127 @@ - dependencies | Tom Carrick

Articles tagged with dependencies

  1. Automatically updating dependencies with dependabot

    Published: | Updated:

    Outdated packages can open your application up to security issues. Moreover, newer versions will often have performance improvements, bug fixes and generally fewer problems. Keeping them up to date over multiple codebases can be quite painful, but it's possible to bring this effort down to close to zero with a …

\ No newline at end of file + + + + dependencies | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Articles tagged with dependencies

+
+
+
    +
  1. + +
  2. +
  3. +
    +
    +

    + + Automatically updating dependencies with dependabot + +

    + Published: + | Updated: +
    +

    Outdated packages can open your application up to security issues. Moreover, +newer versions will often have performance improvements, bug fixes and generally +fewer problems. Keeping them up to date over multiple codebases can be quite +painful, but it's possible to bring this effort down to close to zero with a …

    +
    +
  4. +
+
+
+
+ + + \ No newline at end of file diff --git a/blog/tags/django/index.html b/blog/tags/django/index.html index 3d0fe85..ac29227 100644 --- a/blog/tags/django/index.html +++ b/blog/tags/django/index.html @@ -1 +1,108 @@ - django | Tom Carrick

Articles tagged with django

  1. Testing Django data migrations

    Published:

    You probably already know the value of testing your code. Your Django migrations are code, therefore you should test them. However, testing data migrations in particular can be tricky, and there's no documentation on how to do it.

    Typically your schema migrations don't need any testing as your migrations are …

\ No newline at end of file + + + + django | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Articles tagged with django

+
+
+
    +
  1. +
    +
    +

    + + Testing Django data migrations + +

    + Published: +
    +

    You probably already know the value of testing your code. +Your Django migrations are code, therefore you should test them. +However, testing data migrations in particular can be tricky, +and there's no documentation on how to do it.

    +

    Typically your schema migrations don't need any testing as your +migrations are …

    +
    +
  2. +
+
+
+
+ + + \ No newline at end of file diff --git a/blog/tags/github-actions/index.html b/blog/tags/github-actions/index.html index f54a83d..551d11d 100644 --- a/blog/tags/github-actions/index.html +++ b/blog/tags/github-actions/index.html @@ -1 +1,127 @@ - github-actions | Tom Carrick

Articles tagged with github-actions

  1. Automatically updating dependencies with dependabot

    Published: | Updated:

    Outdated packages can open your application up to security issues. Moreover, newer versions will often have performance improvements, bug fixes and generally fewer problems. Keeping them up to date over multiple codebases can be quite painful, but it's possible to bring this effort down to close to zero with a …

\ No newline at end of file + + + + github-actions | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Articles tagged with github-actions

+
+
+
    +
  1. + +
  2. +
  3. +
    +
    +

    + + Automatically updating dependencies with dependabot + +

    + Published: + | Updated: +
    +

    Outdated packages can open your application up to security issues. Moreover, +newer versions will often have performance improvements, bug fixes and generally +fewer problems. Keeping them up to date over multiple codebases can be quite +painful, but it's possible to bring this effort down to close to zero with a …

    +
    +
  4. +
+
+
+
+ + + \ No newline at end of file diff --git a/blog/tags/migrations/index.html b/blog/tags/migrations/index.html index 31ae12f..453e4e9 100644 --- a/blog/tags/migrations/index.html +++ b/blog/tags/migrations/index.html @@ -1 +1,108 @@ - migrations | Tom Carrick

Articles tagged with migrations

  1. Testing Django data migrations

    Published:

    You probably already know the value of testing your code. Your Django migrations are code, therefore you should test them. However, testing data migrations in particular can be tricky, and there's no documentation on how to do it.

    Typically your schema migrations don't need any testing as your migrations are …

\ No newline at end of file + + + + migrations | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Articles tagged with migrations

+
+
+
    +
  1. +
    +
    +

    + + Testing Django data migrations + +

    + Published: +
    +

    You probably already know the value of testing your code. +Your Django migrations are code, therefore you should test them. +However, testing data migrations in particular can be tricky, +and there's no documentation on how to do it.

    +

    Typically your schema migrations don't need any testing as your +migrations are …

    +
    +
  2. +
+
+
+
+ + + \ No newline at end of file diff --git a/blog/tags/testing/index.html b/blog/tags/testing/index.html index a054abb..b307148 100644 --- a/blog/tags/testing/index.html +++ b/blog/tags/testing/index.html @@ -1 +1,108 @@ - testing | Tom Carrick

Articles tagged with testing

  1. Testing Django data migrations

    Published:

    You probably already know the value of testing your code. Your Django migrations are code, therefore you should test them. However, testing data migrations in particular can be tricky, and there's no documentation on how to do it.

    Typically your schema migrations don't need any testing as your migrations are …

\ No newline at end of file + + + + testing | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Articles tagged with testing

+
+
+
    +
  1. +
    +
    +

    + + Testing Django data migrations + +

    + Published: +
    +

    You probably already know the value of testing your code. +Your Django migrations are code, therefore you should test them. +However, testing data migrations in particular can be tricky, +and there's no documentation on how to do it.

    +

    Typically your schema migrations don't need any testing as your +migrations are …

    +
    +
  2. +
+
+
+
+ + + \ No newline at end of file diff --git a/blog/testing-django-data-migrations/index.html b/blog/testing-django-data-migrations/index.html index 6f62d73..1bb8f99 100644 --- a/blog/testing-django-data-migrations/index.html +++ b/blog/testing-django-data-migrations/index.html @@ -1,77 +1,250 @@ - Testing Django data migrations | Tom Carrick

Testing Django data migrations

Published:

You probably already know the value of testing your code. Your Django migrations are code, therefore you should test them. However, testing data migrations in particular can be tricky, and there's no documentation on how to do it.

Typically your schema migrations don't need any testing as your migrations are run during tests, unless you're skipping migrations to speed up your tests. I recommend against doing this, but that's another blog post.

However, only your data migrations forwards are tested. Even then, they are only tested if they don't have any branching, and if there is something to do. Most data migrations during tests have nothing to do because there is no data during migrations to run against. But why test data migrations in the first place?

Why test your data migrations?

I often use data migrations for a few purposes. The first is to add initial data. For example, you might want to store a list of countries in the database. You don't want to add them directly to the database, but you want them to always be there, and if some new country is formed in the future, you can add it in another data migration, say. This could also be done with a management command or in a multitude of other ways, so it's not the main reason for using a data migration.

The other reason is probably more useful. You'll often have a new requirement that needs you to restructure your database, and as a part of that, you have to make a change to some of your data. For example, you might decide to add a required username to your user model, and to populate the initial values, you want to use the first part of the user's email address. Please don't do this in real life. Generating public information from private information is not very good for a user's privacy.

Testing these with real data is important. You may have users in your database with valid emails where the username part wouldn't validate as a username. As migrations are typically only ran once in production, you'll certainly find out when you deploy and run your migrations that something is wrong. However, is the data in your staging environment as good as that in your production environment? Even if it is, it would be nice to find these problems earlier, and without the stress of dealing with potential problems that aborting a deployment can entail.

How to test your data migrations?

If you find yourself doing this a lot, there is a package called django-test-migrations. I haven't used it myself but it will probably be more robust than the simple approach below. However, if you're averse to installing yet another package, let's see what we can put together without too much work.

Let's use the example above and say we have the following data migration:

from django.db import migrations
-
-def populate_usernames(apps, schema_editor):
-    User = apps.get_model("accounts", "User")
-    for user in User.objects.all():
-        user.username = user.email.rpartition("@")[0]
-        user.save()
-
-def depopulate_usernames(apps, schema_editor):
-    User = apps.get_model("accounts", "User")
-    User.objects.update(username=None)
-
-class Migration(migrations.Migration):
-    dependencies = [("accounts", "0002_add_username")]
-    operations = [migrations.RunPython(populate_usernames, depopulate_usernames)]
-

To test migrations like this, I decided to write a small class to run the migrations. You may notice that this is a class with a single method and __init__, so it could just be a function, but setting the apps attribute felt better than returning apps directly.

from django.db import connection
-from django.db.migrations.executor import MigrationExecutor
-
-
-class Migrator:
-    def __init__(self, connection=connection):
-        self.executor = MigrationExecutor(connection)
-
-    def migrate(self, app_label: str, migration: str):
-        target = [(app_label, migration)]
-        self.executor.loader.build_graph()
-        self.executor.migrate(target)
-        self.apps = self.executor.loader.project_state(target).apps
-

There's not too much going on here. We initialise the class with a migration executor, using a passed connection, or the default connection if none is passed. Then you can run the migrate method, with your app label and migration name. This will run the migration and set the apps attribute that you'll use in your test to make sure you have the right version of the models, similar to how it's used in the data migration itself.

Using the migrator in pytest is pretty simple. We can write a single-line fixture:

@pytest.fixture
-def migrator():
-    return Migrator
-

Then we can write our tests, migrating to where we need to be:

@pytest.mark.django_db
-def test_populate_emails(migrator):
-    migrator = migrator()
-    migrator.migrate("accounts", "0002_add_username")
-    User = migrator.apps.get_model("accounts", "User")
-    user = User.objects.create_user(email="test123@example.com")
-    assert user.username is None
-
-    migrator.migrate("accounts", "0003_populate_usernames")
-    assert User.objects.filter(email="test123@example.com", username="test123").exists()
-

Of course, we can also migrate backwards. Typically, migrating backwards is only used when developing, but in case you want that 100% coverage or really want to be sure:

@pytest.mark.django_db
-def test_depopulate_emails(migrator):
-    migrator = migrator()
-    migrator.migrate("accounts", "0002_add_username")
-    User = migrator.apps.get_model("accounts", "User")
-    user = User.objects.create_user(email="test123@example.com")
-    migrator.migrate("accounts", "0003_populate_usernames")
-    migrator.migrate("accounts", "0002_add_username")
-    User = migrator.apps.get_model("accounts", "user")
-    assert User.objects.get(email="test123@example.com").username is None
-

unittest

If you're using Django's default unittest framework, you can use it in much the same way:

from django.test import TestCase
-
-
-class MigrationTest(TestCase):
-    def setUp(self):
-        self.migrator = Migrator()
-        self.migrator.migrate("accounts", "0002_add_username")
-
-    def test_populate_usernames(self):
-        User = self.migrator.apps.get_model("accounts", "User")
-        user = User.objects.create_user(email="test123@example.com")
-        assert user.username is None
-
-        migrator.migrate("accounts", "0003_populate_usernames")
-        assert User.objects.filter(
-            email="test123@example.com", username="test123"
-        ).exists()
-
-    def test_depopulate_emails(migrator):
-        User = migrator.apps.get_model("accounts", "User")
-        user = User.objects.create_user(email="test123@example.com")
-        migrator.migrate("accounts", "0003_populate_usernames")
-        migrator.migrate("accounts", "0002_add_username")
-        User = migrator.apps.get_model("accounts", "user")
-        assert User.objects.get(email="test123@example.com").username is None
-

So, get out there and test those data migrations.

\ No newline at end of file + + + + Testing Django data migrations | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Testing Django data migrations

+ Published: + +
+ +
+

You probably already know the value of testing your code. +Your Django migrations are code, therefore you should test them. +However, testing data migrations in particular can be tricky, +and there's no documentation on how to do it.

+

Typically your schema migrations don't need any testing as your +migrations are run during tests, unless you're skipping migrations +to speed up your tests. I recommend against doing this, but that's another +blog post.

+

However, only your data migrations forwards are tested. Even then, they are +only tested if they don't have any branching, and if there is something to do. +Most data migrations during tests have nothing to do because there is no data +during migrations to run against. But why test data migrations in the first +place?

+
+

Why test your data migrations?

+

I often use data migrations for a few purposes. The first is to add initial data. +For example, you might want to store a list of countries in the database. You don't +want to add them directly to the database, but you want them to always be there, +and if some new country is formed in the future, you can add it in another data +migration, say. This could also be done with a management command or in a multitude +of other ways, so it's not the main reason for using a data migration.

+

The other reason is probably more useful. You'll often have a new requirement that +needs you to restructure your database, and as a part of that, you have to make a +change to some of your data. For example, you might decide to add a required username +to your user model, and to populate the initial values, you want to use the first part +of the user's email address. Please don't do this in real life. Generating public +information from private information is not very good for a user's privacy.

+

Testing these with real data is important. You may have users in your database with +valid emails where the username part wouldn't validate as a username. As migrations +are typically only ran once in production, you'll certainly find out when you deploy +and run your migrations that something is wrong. However, is the data in your staging +environment as good as that in your production environment? Even if it is, +it would be nice to find these problems earlier, and without the stress of dealing +with potential problems that aborting a deployment can entail.

+
+
+

How to test your data migrations?

+

If you find yourself doing this a lot, there is a package called +django-test-migrations. I haven't used it myself but it will probably be +more robust than the simple approach below. +However, if you're averse to installing yet another package, let's see what +we can put together without too much work.

+

Let's use the example above and say we have the following data migration:

+
from django.db import migrations
+
+def populate_usernames(apps, schema_editor):
+    User = apps.get_model("accounts", "User")
+    for user in User.objects.all():
+        user.username = user.email.rpartition("@")[0]
+        user.save()
+
+def depopulate_usernames(apps, schema_editor):
+    User = apps.get_model("accounts", "User")
+    User.objects.update(username=None)
+
+class Migration(migrations.Migration):
+    dependencies = [("accounts", "0002_add_username")]
+    operations = [migrations.RunPython(populate_usernames, depopulate_usernames)]
+
+

To test migrations like this, I decided to write a small class to +run the migrations. You may notice that this is a class with a single +method and __init__, so it could just be a function, but setting +the apps attribute felt better than returning apps directly.

+
from django.db import connection
+from django.db.migrations.executor import MigrationExecutor
+
+
+class Migrator:
+    def __init__(self, connection=connection):
+        self.executor = MigrationExecutor(connection)
+
+    def migrate(self, app_label: str, migration: str):
+        target = [(app_label, migration)]
+        self.executor.loader.build_graph()
+        self.executor.migrate(target)
+        self.apps = self.executor.loader.project_state(target).apps
+
+

There's not too much going on here. We initialise the class with a +migration executor, using a passed connection, or the default connection +if none is passed. Then you can run the migrate method, with your app +label and migration name. This will run the migration and set the apps +attribute that you'll use in your test to make sure you have the right +version of the models, similar to how it's used in the data migration itself.

+

Using the migrator in pytest is pretty simple. +We can write a single-line fixture:

+
@pytest.fixture
+def migrator():
+    return Migrator
+
+

Then we can write our tests, migrating to where we need to be:

+
@pytest.mark.django_db
+def test_populate_emails(migrator):
+    migrator = migrator()
+    migrator.migrate("accounts", "0002_add_username")
+    User = migrator.apps.get_model("accounts", "User")
+    user = User.objects.create_user(email="test123@example.com")
+    assert user.username is None
+
+    migrator.migrate("accounts", "0003_populate_usernames")
+    assert User.objects.filter(email="test123@example.com", username="test123").exists()
+
+

Of course, we can also migrate backwards. Typically, migrating backwards +is only used when developing, but in case you want that 100% coverage or +really want to be sure:

+
@pytest.mark.django_db
+def test_depopulate_emails(migrator):
+    migrator = migrator()
+    migrator.migrate("accounts", "0002_add_username")
+    User = migrator.apps.get_model("accounts", "User")
+    user = User.objects.create_user(email="test123@example.com")
+    migrator.migrate("accounts", "0003_populate_usernames")
+    migrator.migrate("accounts", "0002_add_username")
+    User = migrator.apps.get_model("accounts", "user")
+    assert User.objects.get(email="test123@example.com").username is None
+
+
+

unittest

+

If you're using Django's default unittest framework, +you can use it in much the same way:

+
from django.test import TestCase
+
+
+class MigrationTest(TestCase):
+    def setUp(self):
+        self.migrator = Migrator()
+        self.migrator.migrate("accounts", "0002_add_username")
+
+    def test_populate_usernames(self):
+        User = self.migrator.apps.get_model("accounts", "User")
+        user = User.objects.create_user(email="test123@example.com")
+        assert user.username is None
+
+        migrator.migrate("accounts", "0003_populate_usernames")
+        assert User.objects.filter(
+            email="test123@example.com", username="test123"
+        ).exists()
+
+    def test_depopulate_emails(migrator):
+        User = migrator.apps.get_model("accounts", "User")
+        user = User.objects.create_user(email="test123@example.com")
+        migrator.migrate("accounts", "0003_populate_usernames")
+        migrator.migrate("accounts", "0002_add_username")
+        User = migrator.apps.get_model("accounts", "user")
+        assert User.objects.get(email="test123@example.com").username is None
+
+

So, get out there and test those data migrations.

+
+
+ +
+ + +
+
+ + + \ No newline at end of file diff --git a/categories.html b/categories.html index eafc77a..f8e43c3 100644 --- a/categories.html +++ b/categories.html @@ -1 +1,73 @@ - Categories | Tom Carrick

Categories on Tom Carrick

\ No newline at end of file + + + + Categories | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + +
+

Categories on Tom Carrick

+ +
+ + + \ No newline at end of file diff --git a/category/misc.html b/category/misc.html index de949da..121d773 100644 --- a/category/misc.html +++ b/category/misc.html @@ -1 +1,143 @@ - misc | Tom Carrick

Articles in the misc category

  1. Automatically updating dependencies with dependabot

    Published: | Updated:

    Outdated packages can open your application up to security issues. Moreover, newer versions will often have performance improvements, bug fixes and generally fewer problems. Keeping them up to date over multiple codebases can be quite painful, but it's possible to bring this effort down to close to zero with a …

  2. Testing Django data migrations

    Published:

    You probably already know the value of testing your code. Your Django migrations are code, therefore you should test them. However, testing data migrations in particular can be tricky, and there's no documentation on how to do it.

    Typically your schema migrations don't need any testing as your migrations are …

\ No newline at end of file + + + + misc | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Articles in the misc category

+
+
+
    +
  1. + +
  2. +
  3. +
    +
    +

    + + Automatically updating dependencies with dependabot + +

    + Published: + | Updated: +
    +

    Outdated packages can open your application up to security issues. Moreover, +newer versions will often have performance improvements, bug fixes and generally +fewer problems. Keeping them up to date over multiple codebases can be quite +painful, but it's possible to bring this effort down to close to zero with a …

    +
    +
  4. +
  5. +
    +
    +

    + + Testing Django data migrations + +

    + Published: +
    +

    You probably already know the value of testing your code. +Your Django migrations are code, therefore you should test them. +However, testing data migrations in particular can be tricky, +and there's no documentation on how to do it.

    +

    Typically your schema migrations don't need any testing as your +migrations are …

    +
    +
  6. +
+
+
+
+ + + \ No newline at end of file diff --git a/cv/index.html b/cv/index.html index 81ae5f0..1e77f33 100644 --- a/cv/index.html +++ b/cv/index.html @@ -1 +1,422 @@ - CV | Tom Carrick

CV

👋🏻 Welcome

Hello. I'm Tom Carrick, and this is my curriculum vitae, or my resume, if you prefer. Maybe I linked this to you instead of sending a PDF, maybe I saved this as a PDF and sent it to you,or perhaps you found your own way here.

Originally from the North-East of England, but I've been living in Amsterdam, Netherlands since the beginning of 2019. I'm a software engineer working mostly with web technologies, particularly Python / Django / PostgreSQL. Usually I'm building complex web applications with REST APIs.

This CV is ordered in such a way that the most important things are at top, and the less useful things are at the bottom. So don't feel like you need to read the whole thing. It's also not 100% complete — there's a lot of freelance work I've excluded, as well as less relevant work experience. With that said, let's get on with it.

📇 Contact

🧰 Skills, languages & tools

  • 🐍 Python
  • 🦄 Django
  • ⚡ FastAPI
  • 🐘 PostgreSQL
  • 📄 HTML
  • 🎨 CSS
  • 🐋 Docker
  • 🐙 Git

💼 Work

–present Tech lead at Carbon Equity
  • Leeding development of Carbon Equity, the world’s first private market climate investing platform.
  • More to come once I've been here a while.
  • Python, Django, PostgreSQL, Redis, HTML, CSS, JS.
Lead web developer at Scene Connect
  • Led development of ZuOS, an application providing energy flexibility services for energy communities.
  • Designed the architecture of the platform capable of handling millions of IoT messages.
  • Led a team of 5 engineers, helping with their career growth as well as with technical problems.
  • Python, Django, PostgreSQL, Redis, HTML, CSS, JS.
Engineering manager at Lightmatter
  • Responsible for the growth of a team of engineers, mentoring, pair programming, reviewing performance and helping them with their career goals and to add value to the rest of the company.
  • Technical leadership of multiple projects.
  • Python, Django, PostgreSQL, Redis, HTML, CSS, JS.
Senior Python/Django developer at Stream
  • Led a rewrite of the backend of the website and the customer dashboard to falicitate a new design, more functionality and better maintainability.
  • Implemented new features for the public Python API libraries for the chat product.
  • Conducted interviews and helped onboard a new developer.
  • Python, Django, Celery, PostgreSQL, Redis, Elasticsearch.
Python developer at Croud
  • Helped lead a rewrite of an existing PHP platform to Python / Django.
  • Created a REST-powered framework for launching runs of automated tools asynchronously with complex dependency chains.
  • Python, Django, Celery, FastAPI, PostgreSQL, RabbitMQ, Redis.
Senior software engineer at Local Motors
  • Writing the backend for Launch Forth, a collaborative engineering platform with challenges and user interaction.
  • Led the migration of a large code base from Python 2 to Python 3.
  • Python, Django, Celery, PostgreSQL, Redis.
Software engineer at 7bridges
  • Helped rewrite the backend code to support a complex logistics platform.
  • Implemented adapters to read unstandardised logistics data from multiple couriersin different formats to a standardised database structure.
  • Python, Django, PostgreSQL, Redis
Software engineer at ezhome
  • Designed and build RESTful APIs for frontend services.
  • Built backend architecture for a customer management platform.
  • Python, Django, PostgreSQL.
Web developer at Calm Digital
  • Wrote multiple fullstack websites for various clients.
  • Designed and built a standard admin interface for most of the company's websiets, greatly reducing development time.
  • Python, Django, PHP, WordPress, Magento, HTML, CSS, JS.

💚 Volunteering, etc.

Open source contributions

I contribute to open source projects where I can. This mostly manifests in occasional contributions to Django .

Django Girls coaching

I'm a semi-regular coach at Django Girls events. I try to get to the ones at DjangoCon EU and anything reasonably close to where I happen to be at the time.

Django Accessibility Team

I'm a member of and helped create Django's Accessibility Team. It's still in its formative days and we're still setting things up.

DjangoCon Europe 2023 organisation

I'm helping (in a small way) to organise DjangoCon Europe 2023.

Personal projects

This website

↖️ You are here. There's not much to say about it, but I've written up the technical details regardless.

django-snakeoil

django-snakeoil is a project I've had for a while for keeping SEO and other meta tags updated in a Django project. It works well enough for me, but since I rewrote this site in Pelican I don't use it myself anymore.

Carbon Timeline

Carbon Timeline (code) is a small project I wrote to teach myself Vue.js. It uses your Google Maps timeline data (downloaded from Google Takeout) to estimate the carbon footprint of your travel using Mike Berners-Lee's (yes, Tim's brother) estimates from his book How Bad Are Bananas?. It's a nice project but I'm more than 99% sure that I'm the only perosn to ever use it. Maybe that will change now that you've read this?

harmony

harmony is just a discord bot with some fun commands. It's not very interesting 🙂.

🎓 Education

MSc Advanced Computer Science (with distinction) at Newcastle University, UK

Masters thesis: Detecting cheating in online poker. Developed applications to analyse more than 20 million hands of online poker in order to detect collusion, suspicious play, and other patterns. Included a quite early use of Neo4j, a graph database.

This degree was partially taught, and partially research-based. In addition to thesis, the teaching had a focus on security and the web.

BSc (Honours) Computing at The Open University, UK

Your typical undergraduate CS degree 🤷.

📰 Publications

  1. T. Carrick, A. Rashid and P. J. Taylor, Mimicry in online conversations: An exploratory study of linguistic analysis techniques, 2016 IEEE/ACM International Conference on Advances in Social Networks Analysis and Mining (ASONAM), pp. 732-736, doi: 10.1109/ASONAM.2016.7752318.

Hobbies & interests

I know, nobody cares, this shouldn't be on your CV, etc. etc., but this is a website, so I'm not wasting space on the page 🙂. Feel free to stop reading here.

I enjoy bouldering, but I'm not amazing at it. I typically boulder indoors at around font level 6b. I play a bit of tennis occasionally but am extremely bad at it.

I would code for fun if it wasn't my full time job.

I enjoy hiking, foraging, anything outdoors in nature, really.

I spend too much time thinking about climate change.

\ No newline at end of file + + + + CV | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

CV

+ + +
+ +
+ +
+
+

👋🏻 Welcome

+

+ Hello. I'm Tom Carrick, and this is my curriculum vitae, or my resume, + if you prefer. Maybe I linked this to you instead of sending a PDF, + maybe I saved this as a PDF and sent it to you,or perhaps you found + your own way here. +

+ +

+ Originally from the North-East of England, but I've been living in + Amsterdam, Netherlands since the beginning of 2019. + I'm a software engineer working mostly with web technologies, + particularly Python / Django / PostgreSQL. Usually I'm building complex + web applications with REST APIs. +

+ +

+ This CV is ordered in such a way that the most important things are at + top, and the less useful things are at the bottom. So don't feel like + you need to read the whole thing. It's also not 100% complete — + there's a lot of freelance work I've excluded, as well as less relevant + work experience. With that said, let's get on with it. +

+
+ +
+

📇 Contact

+
+ +
+
+ +
+

🧰 Skills, languages & tools

+
    +
  • 🐍 Python
  • +
  • 🦄 Django
  • +
  • ⚡ FastAPI
  • +
  • 🐘 PostgreSQL
  • +
  • 📄 HTML
  • +
  • 🎨 CSS
  • +
  • 🐋 Docker
  • +
  • 🐙 Git
  • +
+
+ +
+

💼 Work

+
+ + –present + Tech lead at Carbon Equity + +
    +
  • + Leeding development of Carbon Equity, + the world’s first private market climate investing platform. +
  • +
  • + More to come once I've been here a while. +
  • +
  • Python, Django, PostgreSQL, Redis, HTML, CSS, JS.
  • +
+
+
+ + + Lead web developer at Scene Connect + +
    +
  • + Led development of ZuOS, an application providing energy flexibility + services for energy communities. +
  • +
  • + Designed the architecture of the platform capable of handling millions + of IoT messages. +
  • +
  • + Led a team of 5 engineers, helping with their career growth + as well as with technical problems. +
  • +
  • Python, Django, PostgreSQL, Redis, HTML, CSS, JS.
  • +
+
+
+ + + Engineering manager at Lightmatter + +
    +
  • + Responsible for the growth of a team of engineers, + mentoring, pair programming, reviewing performance and + helping them with their career goals and to add value to the + rest of the company. +
  • +
  • Technical leadership of multiple projects.
  • +
  • Python, Django, PostgreSQL, Redis, HTML, CSS, JS.
  • +
+
+
+ + + Senior Python/Django developer at Stream + +
    +
  • + Led a rewrite of the backend of the website and the customer dashboard + to falicitate a new design, more functionality and better maintainability. +
  • +
  • + Implemented new features for the public Python API libraries + for the chat product. +
  • +
  • Conducted interviews and helped onboard a new developer.
  • +
  • Python, Django, Celery, PostgreSQL, Redis, Elasticsearch.
  • +
+
+
+ + + Python developer at Croud + +
    +
  • Helped lead a rewrite of an existing PHP platform to Python / Django.
  • +
  • + Created a REST-powered framework for launching runs of automated tools + asynchronously with complex dependency chains. +
  • +
  • Python, Django, Celery, FastAPI, PostgreSQL, RabbitMQ, Redis.
  • +
+
+
+ + + Senior software engineer at Local Motors + +
    +
  • + Writing the backend for Launch Forth, a collaborative engineering platform + with challenges and user interaction. +
  • +
  • Led the migration of a large code base from Python 2 to Python 3.
  • +
  • Python, Django, Celery, PostgreSQL, Redis.
  • +
+
+
+ + + Software engineer at 7bridges + +
    +
  • + Helped rewrite the backend code to support a complex logistics platform. +
  • +
  • + Implemented adapters to read unstandardised logistics data from + multiple couriersin different formats to a standardised database structure. +
  • +
  • Python, Django, PostgreSQL, Redis
  • +
+
+
+ + + Software engineer at ezhome + +
    +
  • Designed and build RESTful APIs for frontend services.
  • +
  • Built backend architecture for a customer management platform.
  • +
  • Python, Django, PostgreSQL.
  • +
+
+
+ + + Web developer at Calm Digital + +
    +
  • Wrote multiple fullstack websites for various clients.
  • +
  • + Designed and built a standard admin interface for most of the company's + websiets, greatly reducing development time. +
  • +
  • Python, Django, PHP, WordPress, Magento, HTML, CSS, JS.
  • +
+
+
+ +
+

💚 Volunteering, etc.

+
+ Open source contributions +

+ I contribute to open source projects where I can. + This mostly manifests in occasional + + contributions to Django + . +

+
+
+ Django Girls coaching +

+ I'm a semi-regular coach at + Django Girls events. + I try to get to the ones at DjangoCon EU + and anything reasonably close to where I happen to be at the time. +

+
+
+ Django Accessibility Team +

+ I'm a member of and helped create Django's Accessibility Team. + It's still in its formative days and we're still setting things up. +

+
+
+ DjangoCon Europe 2023 organisation +

+ I'm helping (in a small way) to organise + DjangoCon Europe 2023. +

+
+
+ +
+

Personal projects

+
+ This website +

+ ↖️ You are here. There's not much to say about it, but I've written up + the technical details regardless. +

+
+
+ django-snakeoil +

+ django-snakeoil + is a project I've had for a while for keeping SEO and other meta tags + updated in a Django project. It works well enough for me, but since I + rewrote this site in Pelican I don't use it myself anymore. +

+
+
+ Carbon Timeline +

+ Carbon Timeline + (code) is a small + project I wrote to teach myself Vue.js. It uses your Google Maps timeline + data (downloaded from Google Takeout) to estimate the carbon footprint of + your travel using Mike Berners-Lee's (yes, Tim's brother) estimates from + his book How Bad Are Bananas?. It's a nice project but I'm + more than 99% sure that I'm the only perosn to ever use it. + Maybe that will change now that you've read this? +

+
+
+ harmony +

+ harmony is just a discord bot + with some fun commands. It's not very interesting 🙂. +

+
+
+ +
+

🎓 Education

+
+ + + MSc Advanced Computer Science (with distinction) at Newcastle University, UK + +

+ Masters thesis: Detecting cheating in online poker. + Developed applications to analyse more than 20 million hands of online poker + in order to detect collusion, suspicious play, and other patterns. Included + a quite early use of Neo4j, a graph database. +

+

+ This degree was partially taught, and partially research-based. + In addition to thesis, the teaching had a focus on security and the web. +

+
+
+ + + BSc (Honours) Computing at The Open University, UK + +

Your typical undergraduate CS degree 🤷.

+
+
+ +
+

📰 Publications

+
    +
  1. + T. Carrick, A. Rashid and P. J. Taylor, + Mimicry in online conversations: An exploratory study of linguistic analysis techniques, + 2016 IEEE/ACM International Conference on Advances in Social Networks Analysis and Mining (ASONAM), + pp. 732-736, doi: 10.1109/ASONAM.2016.7752318. +
  2. +
+
+ +
+

Hobbies & interests

+

+ I know, nobody cares, this shouldn't be on your CV, etc. etc., but this + is a website, so I'm not wasting space on the page 🙂. + Feel free to stop reading here. +

+

+ I enjoy bouldering, but I'm not amazing at it. I typically boulder indoors + at around font level 6b. I play a bit of tennis occasionally but am + extremely bad at it. +

+

I would code for fun if it wasn't my full time job.

+

I enjoy hiking, foraging, anything outdoors in nature, really.

+

I spend too much time thinking about climate change.

+
+
+ +
+ + +
+
+ + + \ No newline at end of file diff --git a/index.html b/index.html index 7680c91..1dbbd0b 100644 --- a/index.html +++ b/index.html @@ -1 +1,103 @@ - Tom Carrick | Tom Carrick

Tom Carrick

Web development consultant. Python, Django.

Hello there 👋🏻

I'm Tom Carrick, professional web developer. I work mostly with Python, Django, PostgreSQL, and sometimes FastAPI. I'm currently rekindling my JS skills.

The most useful things on this site at the moment are the blog and my CV.

My focus is on web development. Usually I work on application backends but I also have an interest in frontend development, particularly around accessibility. As you can perhaps tell from the design of this site, I also have an interest in keeping page sizes down and designs uncluttered to help reduce the CO2e emissions of sites, and I'm also interested in using infrastructure in the most efficient and least carbon-intensive way possible.

I'm a semi-regular contributor to Django, and occasionally to other open source projects. I sometimes coach for Django Girls workshops (pandemic permitting), and I still don't feel like I'm doing enough.

\ No newline at end of file + + + + Tom Carrick | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

Tom Carrick

+ Web development consultant. Python, Django. + +
+ +
+

Hello there 👋🏻

+

I'm Tom Carrick, professional web developer. I work mostly with Python, +Django, PostgreSQL, and sometimes FastAPI. I'm currently rekindling my JS skills.

+

The most useful things on this site at the moment are the blog and my CV.

+

My focus is on web development. Usually I work on application backends but I also +have an interest in frontend development, particularly around accessibility. As +you can perhaps tell from the design of this site, I also have an interest in keeping +page sizes down and designs uncluttered to help reduce the CO2e emissions of sites, +and I'm also interested in using infrastructure in the most efficient and least +carbon-intensive way possible.

+

I'm a semi-regular contributor to Django, and occasionally to other open source +projects. I sometimes coach for Django Girls workshops (pandemic permitting), +and I still don't feel like I'm doing enough.

+ +
+ +
+
+ + + \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 35edb0a..031251b 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -6,35 +6,35 @@ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> https://carrick.eu/about/ -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 monthly 0.5 https://carrick.eu/archives.html -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 https://carrick.eu/author/tom-carrick.html -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 https://carrick.eu/authors.html -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 https://carrick.eu/blog/ -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 @@ -55,35 +55,35 @@ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> https://carrick.eu/blog/tags/dependencies/ -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 https://carrick.eu/blog/tags/django/ -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 https://carrick.eu/blog/tags/github-actions/ -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 https://carrick.eu/blog/tags/migrations/ -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 https://carrick.eu/blog/tags/testing/ -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 @@ -97,14 +97,14 @@ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> https://carrick.eu/categories.html -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 https://carrick.eu/category/misc.html -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 @@ -118,7 +118,7 @@ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> https://carrick.eu/tags.html -2024-09-16T09:57:07-00:00 +2024-09-22T12:40:23-00:00 weekly 0.2 diff --git a/tags.html b/tags.html index 5a2e5a9..42bf8ac 100644 --- a/tags.html +++ b/tags.html @@ -1 +1,77 @@ - Tags | Tom Carrick

Tags for Tom Carrick

\ No newline at end of file + + + + Tags | Tom Carrick + + + + + + + + + + + + + + + + + + + + + + + +
+

Tags for Tom Carrick

+ +
+ + + \ No newline at end of file