Craig Fletcher 1 年之前
父节点
当前提交
a89a81b661
共有 5 个文件被更改,包括 1420 次插入150 次删除
  1. 0 5
      .npm-scripts/build-pipeline.js
  2. 108 35
      cv.md
  3. 1109 1
      package-lock.json
  4. 165 0
      styles-old.css
  5. 38 109
      styles.css

+ 0 - 5
.npm-scripts/build-pipeline.js

@@ -101,11 +101,6 @@ module.exports = {
         func: "writeOutFile",
         selector: state => state.selectMany(item => true),
         config: { outputDir: "./output" }
-      },
-      {
-        func: "writeOutPDF",
-        selector: state => state.selectMany(item => true),
-        config: { outputDir: "./output" }
       }
     ]
   ]

+ 108 - 35
cv.md

@@ -2,28 +2,87 @@
 
 You can call me on 07480924132, email me at [hi@leakypixel.net](mailto:hi@leakypixel.net), or see additional details at [leakypixel.net](https://www.leakypixel.net/). 
 
-I've been developing for the web for around 14 years and I'm still as eager as ever to push my skills and learn new things. I specialise in JavaScript - particularly React, but have worked with many languages, libraries and tools appropriate to the task at hand and often managing the entire stack from development to production. I primarily work remotely, and have worked for both large brands and startups alike.
+I've been developing for the web for around 16 years and I'm still as eager as ever to push my skills and learn new things. I primarily work remotely, and have led teams and worked on multiple large-scale initiatives for startups and multinational corporations alike.
+
+My primary skills include React, Vue, NodeJS and JavaScript/TypeScript generally -  though I've worked with many languages, libraries and tools appropriate to the task at hand and often managed the entire stack from development to production to support.
 
 ## Experience
 A short description of my last few roles and what they entailed. I'd be happy to
 discuss these further, but for now I'll keep it brief.
 
-### Penfold pensions - Full-stack JavaScript engineer (3 months, fully remote)
-*2021 - 2022*
+### Mint Velvet - Front-end JavaScript engineer (fully remote)
+*October 2023 - September 2024*
+
+As part of a small, highly commerically-driven team, took up various initiatives and improvements, alongside day-to-day
+BAU retail work. Initially, this started as a pure front-end role but evolved quickly into a full-stack role, owning the
+entire process of a service from design to production support. Some of the more noteworthy tasks included:
+
+* Initiated and led replacement of an external service with an in-house solution, developed using nodeJS and fastify, saving a significant
+monthly subscription cost for the business
+* Deployment and configuration of new infrastructure using Ansible and Azure
+* Liasing with third parties to connect and configure infrastructure for interdependent services
+* Site speed optimisation through use of server-side rendering (liquid templating) and advanced loading strategies for
+external dependencies, achieving a positive difference of 17 (~25%) on Google Lighthouse pagespeed
+* Migration to Cloudinary media from Shopify native, including parser and runtime modification to match component
+requirements
+* Worked very closely with lead designer to implement a component library approach, resulting in both a reduction in total number of components and much more consistent brand identity
+* Resolution of various developer headaches through use of a dockerised dev environment, greatly reducing "blocked" time
+for Windows users in particular
+* Refactoring and improving critical areas of the site to make better use of client-side caching and improve perceived
+speed through optimistic updates to the store
+
+_Skills used: Vue CompositionAPI GraphQL NodeJS Pinia TypeScript Yarn ESBuild pkg Fastify MongoDB Shopify Liquid Storybook Cloudinary Docker Ansible Azure Swagger OpenAPI React-remix_
+
+### Kloeckner Metals (Erlang Solutions) - Front-end JavaScript engineer (fully remote)
+*August 2022 - October 2023*
+
+Worked on and led various business-critical initiatives, including:
+
+* Implementing an app-wide store (Pinia) as part of the process of refactoring the app and removing developer obstacles
+* Upgrading a stock and order management app from Vue 2 to Vue 3
+* Helping develop a component library using modern techniques and tooling, including both Vue and Ember
+* Implementing stock availability across a worldwide group in a centralised app
+
+_Skills used: Vue CompositionAPI GraphQL NodeJS Vuex Vite Ember Pinia TypeScript Yarn_
+
+### Orbit - Full-stack JavaScript engineer (fully remote)
+*June - August 2022*
+
+Worked together with a cofounder of a small startup to develop core features of the product and decrease tech debt
+(primarily in the state management and data fetching areas of the app). Developed a state management and data cacheing
+solution based on Jotai and URQL which fixed a number of long-standing bugs and resulted in a 15-20% performance
+improvement across the app.
+
+_Skills used: React React-hooks GraphQL NodeJS TypeScript NPM Ramda Jotai URQL Hasura_
+
+### Attest/101ways - Full-stack JavaScript engineer (fully remote)
+*March - June 2022*
+
+Worked with a small to medium sized team to develop new features and improvements to the client application, using Vue,
+Pinia, Vuex and Ramda. Application performance was paramount, and involved heavy use of large datasets and graphing
+libraries.
+
+_Skills used: TypeScript Vue NPM HighCharts WebPack Pinia Vuex Ramda PostCSS Jest Cypress_
+
+
+### Penfold pensions - Full-stack JavaScript engineer (fully remote)
+*September 2021 - March 2022*
 
 Worked with a medium sized team to refine and develop a cross-platform app to allow customers to manage and analyse
 their penfold pension. Primary responsibilities included finding and fixing complex multi-layer bugs, developing new
 features to match stakeholder specifications and performance analysis and recommendations. 
 
-_Skills used: TypeScript React NPM WebPack Babel React-Hooks NextJS NodeJS Apollo_
+_Skills used: TypeScript React NPM WebPack Babel React-Hooks NextJS NodeJS Apollo Jest Cypress_
 
 
-### Erlang Solutions - Front end tech lead (12 months, fully remote)
-*2020 - 2021*
+### Erlang Solutions - Front end tech lead (fully remote)
+*October 2020 - September 2021*
 
-Headed up a 3-person front end team, replacing an underpeforming angular site
+Architected and led a 3-person front end team, replacing an underpeforming angular site
 with a fully modularised and modern react-based solution for a high traffic
-betting company based in South Africa.
+betting company based in South Africa, as well as upskilling the existing development team into the react ecosystem.
+As part of the team lead role, updated key stakeholders and discussed design of the solution with appropriate people
+within the business.
 
 _Skills used: TypeScript React Docker NPM WebPack Babel React-Hooks React-Sagas_
 
@@ -40,7 +99,7 @@ _Skills used: TypeScript VueJS Docker NPM WebPack Babel Vuex_
 ### EnergyLinx (GoCompare group) - JavaScript consultant (2 months, fully remote)
 *2020*
 
-Worked as the lead developer on a complete rebuild of a React and TypeScript
+Worked as the lead developer with a small (3 person) team on a complete rebuild of a React and TypeScript
 component based whitelabel system. Built an MVP with functioning cross-module
 themeing, configuration injection and a reference implementation as the sole
 developer, which was reviewed and discussed with the technical and design team
@@ -59,7 +118,7 @@ custom build and deploy system for a multinational retailer end client.
 _Skills used: Erlang/Phoenix JavaScript CSS HTML CSS3-animations_
 
 
-### AKQA - JavaScript consultant (3 months, fully remote)
+### AKQA - JavaScript consultant (6 months, fully remote)
 *2019*
 
 Worked on a high-profile project for a well-known international clothing brand,
@@ -95,25 +154,9 @@ something I really enjoyed.
 
 _Skills used: JavaScript React Redux Python Flask SQLAlchemy Docker_
 
-### Life's Great - JavaScript consultant (6 months, part remote)
-*2017 to 2018* 
-
-Upskilled team into react development and assisted with building a greenfield
-project:
-
-* Upskilling team with limited to no prior knowledge of react through pairing,
-    presentations and walkthroughs.
-
-* Built a new application to gather information from customers through a
-    conditional, staged questionnaire with complex dependencies.
-
-* Various devops related tasks from scratch, such as docker scripts.
-
-* Advising management on various technical decisions vital for the company.
-
-_Skills used: JavaScript React Redux Git Docker_
-
 ### Earlier
+*2017 to 2018 - Life's Great - JavaScript consultant (6 months, part remote)*
+
 *2017 - Tyres on the Drive - JavaScript consultant (12 months)*
 
 *2016 - The Hut Group - JavaScript developer (12 months)*
@@ -133,24 +176,30 @@ varied. A few of my favourites have been:
 * Cross-platform time tracking app for a series-A startup, using
     Quasar/Vue/Capacitor/Cordova
 * Worked with a series A startup to produce a custom-designed device for secure decommissioning and backup of spinning disk drives
+* Various Web3 projects - including dashboards, dApp interaction and web3 APIs for early-stage startups using web3js and
+    ethers
+* Successfully delivered both shopify reskins and full builds of small ecommerce sites for small to medium businesses,
+    incorporating detailed analytics and complex applications (embedded Vue apps) such as cut calculation for sheet
+    materials
 
 ## Skills
 Some of the skills I've picked up along the way and tools I've used.
 
 ### JavaScript
-I've around 10 years experience with JavaScript, and consider myself
+I've around 16 years experience with JavaScript, and consider myself
 highly proficient. I take an active interest in new developments, often spending my
 free time checking out new features and frameworks.
 
-* React (Redux/Apollo GraphQL/hooks/reselect)
-* Vue (Vuex/Quasar)
+* React (Redux/Apollo GraphQL/hooks/reselect/Jotai/React Native)
+* Vue (Vuex/Quasar/Vue Apollo/Vitest/Vite/Pinia)
+* CMS and product management platforms (Shopify/Strapi/Contentful/Wix)
 * Cross-platform wrappers (Cordova/Capacitor/Quasar/Electron/PhoneGap)
 * API integration (analytics/Facebook messenger platform/payment systems/GraphQL)
-* NodeJS (Express/Restify/Fastify/native HTTP/cloud functions)
+* NodeJS (Express/Restify/Fastify/native HTTP/cloud functions/Hasura/Prisma)
 * Document DBs (Mongo/Couchbase/DynamoDB)
 * Client-side templating (Handlebars/Mustache/jst)
 * Module loading & dependency resolution
-* Testing & automation (Jasmine/Jest/Karma/Istanbul/Selenium/nyc)
+* Testing & automation (Jasmine/Jest/Karma/Istanbul/Selenium/nyc/Vue test utils 2 & 3)
 * Build systems (Grunt/Gulp/Webpack/custom-built)
 * WebSockets (Pusher/native)
 * Modern ECMA script (Babel/Node)
@@ -162,7 +211,7 @@ infrastructure, but quickly developed into managing the full stack in my
 commerical roles.
 
 * AWS and Digital ocean
-* Continuous integration (Jenkins/Travis)
+* Continuous integration (Jenkins/Travis/GitHub actions)
 * Docker & docker-compose
 * Ansible
 * Server administration (systemd, collectd, init.d) 
@@ -197,7 +246,9 @@ interested coworkers or personal projects.
 * Agile, Kanban & Scrum
 * Project management tools (JIRA/Trello)
 * Blockchain (trading, bitcoin/iota/ethereum/bat/litecoin/monero theory and use, some experience with solidity)
+* Web3 technologies (Web3js/Ethers/Metamask)
 * Analytics (Google/server stats/pingdom/custom built)
+* AI/ML (model finetuning/local models/SKLearn/Keras)
 
 ### Experience of working with
 Working on many projects has given me contact with quite a few back end
@@ -208,11 +259,33 @@ environments, with varying degrees of depth.
 * Erlang (Phoenix, moderate)
 * C# (.NET, moderate)
 * Bash (day to day environment & scripting)
+* Rust (scripts/tools here and there)
 * Python (flask/sql alchemy/raspi-GPIO/scripting)
 * Ruby (Rails/cucumber/rspec/scripting)
 
 ### References/reviews
-Things people have said about working with me, taken directly from my LinkedIn.
+Things people have said about working with me.
+
+
+#### Kloeckner - Jan Butzner (Product Manager Innovation & Design)
+_November 2023_
+
+>I worked with Craig for over a year, very closely on a complex, high-stakes project involving Vue, GraphQL and such, with a lot of technical debt. First of all, it is a joy to work with and talk to Craig. He is very knowledgeable, intelligent, empathic and efficient. He not only managed to analyze the situation clearly, he also proactively suggested and made major improvements to the code base and was able to clearly communicate and explain it even to non-tech people. 
+>
+>We/I will dearly miss working with him and he was only "released" due to unrelated business decisions. Highly recommend hiring Craig, you will not regret it!
+
+
+#### Orbit - Sebastian Sas Mangel (Co-founder - Engineering)
+_July 2022_
+
+>Craig has been a fantastic and excellent addition to our team for a few months. We have worked together very hard to develop core features of the product and decrease tech debt in the state management and data fetching areas of our web app. He has a very thorough understanding of the React ecosystem and as a whole of front-end technologies. Craig has conducted together with myself the research and PoC implementation of Jotai, which we later have adopted throughout the app. This has resulted in a 15-20% performance improvement and it has reduced significantly the number of network requests and bugs that we have faced with our previous implementation of a data caching layer. Needless to say, this was a very challenging endeavor, with a relatively short deadline, filled with numerous moving parts. 
+>
+>We have also worked together to develop a new feature called the Treemap, which is a visual and interactive representation of the product discovery outcomes.
+>
+>He is a great communicator and very hard working individual. His technical knowledge covers areas way beyond front-end technologies. I can't recall just how many conversations we had about IoT devices, microcontrollers, networking, and security - always fascinated by the sheer amount of knowledge he has.
+>
+>We have been very pleased with the work he has done and we are grateful to him for his contribution to the team and the company.
+
 
 #### AKQA - Mike Carlisle (Group Technical Director / Consultant / Architect)
 *October 2019* 

文件差异内容过多而无法显示
+ 1109 - 1
package-lock.json


+ 165 - 0
styles-old.css

@@ -0,0 +1,165 @@
+/* General styles */
+body {
+  background-color: #f0f0f0;
+  color: #0e0e0e;
+  line-height: 1.6em;
+  letter-spacing: 0.025em;
+  font-family: "Noto sans", sans-serif;
+  font-weight: 300;
+  font-size: 10px;
+}
+
+section {
+  max-width: 42vw;
+  margin: 0 auto 2em auto;
+  overflow: hidden;
+  clear: both;
+  display: block;
+}
+
+section img {
+  display: block;
+  margin: 2em auto;
+  max-width: 100%;
+}
+
+h1 {
+  text-transform: uppercase;
+  display: inline-block;
+  font-family: "Gidole", monospace;
+  font-weight: bold;
+  font-weight: 600;
+  letter-spacing: 0.025em;
+  font-size: 2em;
+  line-height: 1.6em;
+  margin: 1em 0 2em 0;
+  box-shadow: inset 0 -1.4rem 0 #00ff00;
+}
+
+h2 {
+  text-transform: uppercase;
+  display: inline-block;
+  margin: 3em 0 1em 0;
+  font-family: "Gidole", monospace;
+  font-weight: bold;
+  font-weight: 400;
+  letter-spacing: 0.025em;
+  font-size: 1.4em;
+  line-height: 1.6em;
+  page-break-after: avoid;
+}
+
+h3 {
+  color: #4f4f4f;
+  font-family: "Gidole", monospace;
+  text-transform: uppercase;
+  font-weight: 400;
+  font-size: 1.2em;
+  margin: 4em 0 1em 0;
+  page-break-after: avoid;
+}
+
+h4 {
+  color: #4f4f4f;
+  font-family: "Gidole", monospace;
+  text-transform: uppercase;
+  font-weight: 400;
+  font-size: 1em;
+  margin: 4em 0 1em 0;
+  page-break-before: avoid;
+  page-break-after: avoid;
+}
+
+a,
+a:active,
+a:visited {
+  background-color: #0000ff;
+  color: #f0f0f0;
+  text-decoration: underline;
+  padding: 0 0.2em;
+}
+
+p {
+  font-size: 1em;
+  line-height: 1.5em;
+  margin: 0.8em 0;
+  break-inside: avoid;
+  page-break-before: avoid;
+}
+
+em {
+  font-size: 0.8em;
+}
+
+ul {
+  break-inside: avoid;
+  page-break-before: avoid;
+}
+
+li {
+  margin: 1em 0;
+  padding-left: 0.8em;
+}
+
+blockquote {
+  font-size: 0.8em;
+}
+
+/* Header */
+header {
+  margin: 1em auto 4em auto;
+}
+
+/* Smaller screen tweaks */
+@media screen and (max-width: 940px) {
+  section {
+    max-width: 90vw;
+  }
+  header {
+    max-width: 90vw;
+  }
+  footer {
+    padding: 0;
+  }
+
+  footer ul {
+    flex-flow: column;
+    margin: 3em 0 0 0;
+  }
+  footer ul li {
+    padding: 1em;
+    border-bottom: none;
+    border-left: 0.5em solid;
+  }
+  footer ul li:nth-child(1) {
+    border-bottom: none;
+  }
+  footer ul li:nth-child(2) {
+    border-bottom: none;
+  }
+  footer ul li:nth-child(3) {
+    border-bottom: none;
+  }
+}
+
+@media print {
+  p {
+    break-inside: avoid;
+  }
+  section {
+    max-width: 95%;
+    width: 95%;
+  }
+  body {
+    max-width: 95%;
+    width: 95%;
+    margin: 2em;
+    font-size: 10px;
+  }
+}
+/* Fonts */
+@import url("https://fonts.googleapis.com/css?family=Noto+Sans");
+@font-face {
+  font-family: "Gidole";
+  src: url("Gidole-Regular.ttf") format("truetype");
+}

+ 38 - 109
styles.css

@@ -1,14 +1,29 @@
-/* General styles */
+:root {
+  --dim: 2.5vw; /* Dimensions */
+  --pxt: 12; /* Pixel total each dimension */
+  --stcl: #444; /* Stroke colour */
+  --txcl: #222; /* Text colour */
+  --bgcl: #fff; /* Background colour */
+  --accl: #306dd3; /* Action colour */
+
+  --poa: 3; /* Pixels outside angle */
+  --pxs: calc(var(--dim) / var(--pxt)); /* Pixel size */
+  --asos: calc(var(--pxs) * (var(--pxt) - var(--poa))); /* Angle start offset */
+}
+@media (prefers-color-scheme: dark) {
+  :root {
+    --stcl: #cfcfcf; /* Stroke colour */
+    --txcl: #c2c2c2; /* Text colour */
+    --bgcl: #222; /* Background colour */
+    --accl: #9da2ff; /* Action colour */
+  }
+}
 body {
-  background-color: #f0f0f0;
-  color: #0e0e0e;
-  line-height: 1.6em;
-  letter-spacing: 0.025em;
-  font-family: "Noto sans", sans-serif;
-  font-weight: 300;
-  font-size: 10px;
+  font-family: "sans", Arial, sans-serif;
+  font-size: 14px;
+  background-color: var(--bgcl);
+  color: var(--txcl);
 }
-
 section {
   max-width: 42vw;
   margin: 0 auto 2em auto;
@@ -17,125 +32,46 @@ section {
   display: block;
 }
 
-section img {
-  display: block;
-  margin: 2em auto;
-  max-width: 100%;
-}
-
 h1 {
-  text-transform: uppercase;
-  display: inline-block;
-  font-family: "Gidole", monospace;
-  font-weight: bold;
-  font-weight: 600;
-  letter-spacing: 0.025em;
-  font-size: 2em;
-  line-height: 1.6em;
-  margin: 1em 0 2em 0;
-  box-shadow: inset 0 -1.4rem 0 #00ff00;
+  font-size: 1.6em;
+  font-weight: normal;
+  line-height: 1.25em;
+  margin: 3vw 0 1vw 0;
 }
-
 h2 {
-  text-transform: uppercase;
   display: inline-block;
   margin: 3em 0 1em 0;
-  font-family: "Gidole", monospace;
-  font-weight: bold;
-  font-weight: 400;
-  letter-spacing: 0.025em;
   font-size: 1.4em;
   line-height: 1.6em;
+  page-break-after: avoid;
 }
 
 h3 {
-  color: #4f4f4f;
-  font-family: "Gidole", monospace;
-  text-transform: uppercase;
-  font-weight: 400;
   font-size: 1.2em;
   margin: 4em 0 1em 0;
+  page-break-after: avoid;
 }
 
 h4 {
-  color: #4f4f4f;
-  font-family: "Gidole", monospace;
-  text-transform: uppercase;
-  font-weight: 400;
   font-size: 1em;
   margin: 4em 0 1em 0;
+  page-break-before: avoid;
+  page-break-after: avoid;
 }
-
-a,
-a:active,
-a:visited {
-  background-color: #0000ff;
-  color: #f0f0f0;
-  text-decoration: underline;
-  padding: 0 0.2em;
+a {
+  color: var(--accl);
 }
 
 p {
-  font-size: 1em;
-  line-height: 1.5em;
-  margin: 0.8em 0;
-  break-inside: avoid;
-}
-
-em {
-  font-size: 0.8em;
+  margin: 1vw 0;
 }
-
 ul {
-  break-inside: avoid;
+  margin-top: 0.6em;
+  margin-bottom: 1vw;
 }
-
 li {
-  margin: 1em 0;
-  padding-left: 0.8em;
-}
-
-blockquote {
-  font-size: 0.8em;
-}
-
-/* Header */
-header {
-  margin: 1em auto 4em auto;
+  margin-top: 0.4em;
 }
-
-/* Smaller screen tweaks */
-@media screen and (max-width: 940px) {
-  section {
-    max-width: 90vw;
-  }
-  header {
-    max-width: 90vw;
-  }
-  footer {
-    padding: 0;
-  }
-
-  footer ul {
-    flex-flow: column;
-    margin: 3em 0 0 0;
-  }
-  footer ul li {
-    padding: 1em;
-    border-bottom: none;
-    border-left: 0.5em solid;
-  }
-  footer ul li:nth-child(1) {
-    border-bottom: none;
-  }
-  footer ul li:nth-child(2) {
-    border-bottom: none;
-  }
-  footer ul li:nth-child(3) {
-    border-bottom: none;
-  }
-}
-
 @media print {
   p {
     break-inside: avoid;
@@ -143,7 +79,6 @@ header {
   section {
     max-width: 95%;
     width: 95%;
-    margin: 0;
   }
   body {
     max-width: 95%;
@@ -152,9 +87,3 @@ header {
     font-size: 10px;
   }
 }
-/* Fonts */
-@import url("https://fonts.googleapis.com/css?family=Noto+Sans");
-@font-face {
-  font-family: "Gidole";
-  src: url("Gidole-Regular.ttf") format("truetype");
-}

部分文件因为文件数量过多而无法显示