Continuous Integration is Harder Than You Think

I’ve been working on continuous integration systems for a few years, and while the basic principle of CI is straightforward, it seems that most CI deployments are not. This makes sense: project infrastructure is an easy place to defer maintenance during the development cycle, and projects often prioritize feature development and bug fixing over tweaking the buildsystem or test infrastructure, but I almost think there’s something more. This post is a consideration of what makes CI hard and perhaps provide a bit of unsolicited advice.

The Case for CI

I suppose I don’t really have to sell anyone on the utility or power of CI: running a set of tests on your software regularly allows developers and teams to catch bugs early, and saves a bucket of developer time, and that is usually enough. Really, though, CI ends up giving you the leverage to solve a number of really gnarly engineering problems:

  • how to release software consistently and regularly.
  • how to support multiple platforms.
  • how to manage larger codebases.
  • anything with distributed systems.
  • how to develop software with larger numbers of contributors.

Doing any of these things without CI isn’t really particularly viable, particularly at scale. This isn’t to say, that they “come free” with CI, but that CI is often the right place to build the kind of infrastructure required to manage distributed systems problems or release complexity.

Buildsystems are Crucial

One thing that I see teams doing some times is addressing their local development processes and tooling with a different set of expectations than they do in CI, and you can totally see and understand how this happens: the CI processes always start from a clean environment, and you often want to handle failures in CI differently than you might handle a failure locally. It’s really easy to write a shell script that only runs in CI, and then things sort of accumulate, and eventually there emerge a class of features and phenomena that only exist for and because of CI.

The solution is simple: invest in your buildsystem,1 and ensure that there is minimal (or no!) indirection between your buildsystem and your CI configuration. But buildsystems are hard, and in a lot of cases, test harnesses aren’t easily integrated into build systems, which complicates the problem for some. Having a good build system isn’t particularly about picking a good tool, though there are definitely tradeoffs for different tools, the problem is mostly in capturing logic in a consistent way, providing a good interface, and ensuring that the builds happen as efficiently as possible.

Regardless, I’m a strong believer in centralizing as much functionality in the buildsystem as possible and making sure that CI just calls into build systems. Good build systems:

  • allow you to build or rebuild (or test/subtest) only subsets of work, to allow quick iteration during development and debugging.
  • center around a model of artifacts (things produced) and dependencies (requires-type relationships between artifacts).
  • have clear defaults, automatically detect dependencies and information from the environment, and perform any required set up and teardown for the build and/or test.
  • provide a unified interface for the developer workflow, including building, testing, and packaging.

The upside, is that effort that you put into the development of a buildsystem pay dividends not just for managing to complexity of CI deployments, but also make the local development stable and approachable for new developers.

T-Shaped Matrices

There’s a temptation with CI systems to exercise your entire test suite with a comprehensive and complete range of platforms, modes, and operations. While this works great for some smaller projects, “completism” is not the best way to model the problem. When designing and selecting your tests and test dimensions, consider the following goals and approaches:

  • on one, and only one, platform run your entire test suite. This platform should probably be very close to the primary runtime of your environment (e.g. when developing a service that runs on Linux service, your tests should run in a system that resembles the production environment,) or possibly your primary development environment.
  • for all platforms other than your primary platform, run only the tests that are either directly related to that runtime/platform (e.g. anything that might be OS or processor specific,) plus some small subset of “verification” or acceptance tests. I would expect that these tests should easily be able to complete in 10% of the time of a “full build,”
  • consider operational variants (e.g. if your product has multiple major-runtime modes, or some kind of pluggable sub-system) and select the set of tests which verifies these modes of operations.

In general the shape of the matrix should be t-shaped, or “wide across” with a long “narrow down.” The danger more than anything is in running too many tests, which is a problem because:

  • more tests increase the chance of a false negative (caused by the underlying systems infrastructure, service dependencies, or even flakey tests,) which means you risk spending more time chasing down problems. Running tests that provide signal is good, but the chance of false negatives is a liability.
  • responsiveness of CI frameworks is important but incredibly difficult, and running fewer things can improve responsiveness. While parallelism might help some kinds of runtime limitations with larger numbers of tests, this incurs overhead, is expensive.
  • actual failures become redundant, and difficult to attribute failures in “complete matrices.” A test of certain high level systems may pass or fail consistently along all dimensions creating more noise when something fails. With any degree of non-determinism or chance of a false-negative, running tests more than once just make it difficult to attribute failures to a specific change or an intermittent bug.
  • some testing dimensions don’t make sense, leading to wasted time addressing test failures. For example when testing an RPC protocol library that supports both encryption and authentication, it’s not meaningful to test the combination of “no-encryption” and “authentication,” although the other three axes might be interesting.

The ultimate goal, of course is to have a test matrix that you are confident will catch bugs when they occur, is easy to maintain, and helps you build confidence in the software that you ship.

Conclusion

Many organizations have teams dedicated maintaining buildsystems and CI, and that’s often appropriate: keeping CI alive is of huge value. It’s also very possible for CI and related tools to accrued complexity and debt in ways that are difficult to maintain, even with dedicated teams: taking a step back and thinking about CI, buildsystems, and overall architecture strategically can be very powerful, and really improve the value provided by the system.


  1. Canonically buildsystems are things like makefiles (or cmake, scons, waf, rake, npm, maven, ant, gradle, etc.) that are responsible for converting your source files into executable, but the lines get blurry in a lot of languages/projects. For Golang, the go tool plays the part of the buildsystem and test harness without much extra configuration, and many environments have a pretty robust separation between building and testing. ↩︎

Get More Done

It’s really easy to over think the way that we approach our work and manage our own time and projects. There are no shortage of tools, services, books, and methods to organizing your days and work, and while there are a lot of good ideas out there, it’s easy to get stuck fiddling with how you work, at the expense of actuallying getting work done. While I’ve definitely thought about this a lot over time, for a long time, I’ve mostly just done things and not really worried much about the things on my to-do list.1

I think about the way that I work similarly to the way that I think about the way I work with other people. The way you work alone is different from collaboration, but a lot of the principles of thinking about big goals, and smaller actionable items is pretty transferable.

My suggestions here are centered around the idea that you have a todo list, and that you spend a few moments a day looking at that list, but actually I think the way I think about my work is really orthogonal to any specific tools. For years, most of my personal planning has revolved around making a few lists in a steno pad once or twice a day,2 though I’ve been trying to do more digital things recently. I’m not sure I like it. Again, tools don’t matter.

Smaller Tasks are Always Better

It’s easy to plan projects from the “top down,” and identify the major components and plan your work around those components, and the times that I run in to trouble are always the times when my “actionable pieces” are too big. Smaller pieces help you build momentum, allow to move around to different areas as your attention and focus change, and help you use avalible time effectively (when you want.)

It’s easy to find time in-between meetings, or while the pasta water is boiling, to do something small and quick. It’s also very easy to avoid starting something big until you have a big block of unfettered time. The combination of these factors makes bigger tasks liabilities, and more likely to take even longer to complete.

Multi-Task Different Kinds of Work

I read a bunch of articles that suggest that the way to be really productive is to figure out ways of focusing and avoiding context switches. I’ve even watched a lot of coworkers organize their schedules and work around these principles, and it’s always been something of a mystery for me. It’s true that too much multi-tasking and context switching can lead to a fragmented experience and make some longer/complicated tasks harder to really dig into, but it’s possible to manage the costs of context switching, by breaking apart bigger projects into smaller projects and leaving notes for your (future) self as you work.

Even if you don’t do a lot of actual multitasking within a given hour or day of time, it’s hard to avoid really working on different kinds of projects on the scale of days or weeks, and I’ve found that having multiple projects in flight at once actually helps me get more done. In general I think of this as the idea that more projects in flight means that you finish things more often, even if the total number of projects completed is the same in the macro context.

Regardless, different stages of a project require different kind of attention and energy and having a few things in flight increases the chance that when you’re in the mood to do some research, or editing, or planning, you have a project with that kind of work all queued up. I prefer to be able to switch to different kinds of work depending on my attention and mood. In general my work falls into the following kinds of activities:

  • planning (e.g. splitting up big tasks, outlining, design work,)
  • generative work (e.g. writing, coding, etc.)
  • organizational (email, collaboration coordination, user support, public issue tracking, mentoring, integration, etc.)
  • polishing (editing, writing/running tests, publication prepping,)
  • reviewing (code review, editing, etc.)

Do the Right Things

My general approach is “do lots of things and hope something sticks,” which makes the small assumption that all of the things you do are important. It’s fine if not everything is the most important, and it’s fine to do things a bit out of order, but it’s probably a problem if you do lots of things without getting important things done.

So I’m not saying establish a priority for all tasks and execute them in strictly that priority, at all. Part of the problem is just making sure that the things on your list are still relevant, and still make sense. As we do work and time passes, we have to rethink or rechart how we’re going to complete a project, and that reevaluation is useful.

Prioritization and task selection is incredibly hard, and it’s easy to cast “prioritization” in over simplified terms. I’ve been thinking about prioritization, for my own work, as being a decision based on the following factors:

  • deadline (when does this have to be done: work on things that have hard deadlines or expected completion times, ordered by expected completion date, to avoid needing to cram at the last moment.)
  • potential impact (do things that will have the greatest impact before lesser impact, this is super subjective, but can help build momentum, and give you a chance to decide if lower-impact items are worth doing.)
  • time availability fit (do the biggest thing you can manage with the time you have at hand, as smaller things are easier to fit in later,)
  • level of understanding (work on the things that you understand the best, and give yourself the opportunity to plan things that you don’t understand later. I sometimes think about this as “do easy things first,” but that might be too simple.)
  • time outstanding (how long ago was this task created: do older things first to prevent them from becoming stale.)
  • number of things (or people) that depend on this being done (work on things that will unblock other tasks or collaborators before things that don’t have any dependencies, to help increase overall throughput.)

Maintain a Pipeline of Work

Productivity, for me, has always been about getting momentum on projects and being able to add more things. For work projects, there’s (almost) always a backlog of tasks, and the next thing is ususally pretty obvious, but sometimes this is harder for personal projects. I’ve noticed a tendency in myself to prefer “getting everything done” on my personal todo list, which I don’t think particularly useful. Having a pipleine of backlog of work is great:

  • there’s always something next to do, and there isn’t a moment when you’ve finished and have to think about new things.
  • keeping a list of things that you are going to do in the more distant future lets you start thinking about how bigger pieces fit together without needint to starting to work on that.
  • you can add big things to your list(s) and then break them into smaller pieces as you make progress.

As an experiment, think about your todo list, not as a thing that you’d like to finish all of the items, but as list that shouldn’t be shorter than a certain amount (say 20 or 30?) items with rate of completion (10 a week?) though you should choose your own numbers, and set goals based on what you see yourself getting done over time.


  1. Though, to be clear, I’ve had the pleasure and benefit of working in an organization that lives-and-dies by a bug tracking system, with a great team of folks doing project management. So there are other people who manage sprints, keep an eye on velocity, and make sure that issues don’t get stuck. ↩︎

  2. My general approach is typically to have a “big projects” or “things to think about” list and a “do this next list”, with occasional lists about all the things in a specific big project. In retrospect these map reasonable well to SCRUM/Agile concepts, but it also makes sense. ↩︎

Lessons from the Knitting Hiatus

I took years and years off of knitting: life and priorities change and I must confess that a few years of living in a very small apartment with very active cats made it difficult to have the space to really get into knitting. Anyway, it was really nice to have a hobby sitting on the metaphoric shelf that I could get right back into without a big learning curve.

The interesting thing, I think is in observing is that the hiatus made some subtle changes to the way that I approach knitting things, at least relative to what I remember.

  • I’m less opposed to garter stitch, and have been using little bits of it here and there in some projects.
  • I’ve gotten much better at wrap-and-turn short rows in stocking stitch., they now look pretty good and I remember them always looking terrible.
  • I knit the yoke of a sweater back and forth, which is a thing that I would have found unimaginable.
  • Knitting plain stocking stitch in the round has always been a great joy of mine, but in the last couple of months I’ve done it rather a lot, knitting 3, or so, plain sweaters, which I’ve found quite captivating. I always seemed to feel like I needed some kind of patterning (color work, lace, cables etc) to keep things interesting, and that doesn’t really seem to be the case.
  • I’ve yet to knit anything post-hiatus on needles other than US 0s (which are quite small,) and it doesn’t seem to bug me very much. I continue to make progress on projects and rounds with 250-340 (or so) stitches don’t seem oppressively long.
  • The problem of having little gaps between the sleeve of a sweater and the body at the “bottom corner,” always used to be a big problem, and these days I haven’t need to sew up these gaps at all, which is kind of novel.
  • My cast on edges have gotten better: I’ve managed to get edges that are as elastic as they need to be, and all of the usual problems (a twist, mistakes in rubbing, problems in counting, misjudging the length of the long-tail) haven’t been a problem at all.

Of course some things didn’t change:

  • I still don’t really like to do things that involve knitting rows very much, and would prefer to knit as much as possible in the round.
  • My taste in yarns seems to be heavy on the “boring fine wool” and while I’ve been looking around at the kinds of yarns that are available and popular, I am (for the most part,) pretty content to stick to the really simple and boring yarn.
  • I haven’t yet vanquished a number of old fears/struggles like making an EPS-style sweater that I really like, knitting sleeves from the cuff-up, cardigans. Many of these things are on my list of things to explore more in the future, but we’ll see how I fair.

It’s all very curious! I’m excited to see if anything else changes!

Open Source Emacs Configuration Improvements

In retrospect I’m not totally sure why I released my emacs configuration to the world. I find tweaking Emacs Lisp to be soothing, and in 2020 these kinds of projects are particularly welcome. I’ve always thought about making it public: I feel like I get a lot out of Emacs, and I’m super aware that it’s very hard for people who haven’t been using Emacs forever to get a comparable experience.1

I also really had no idea of what to expect, and while it’s still really recent, I’ve noticed a few things which are worth remarking:

  • Making your code usable for other people really does make it easy for people to find bugs. While it’s likely that there are bugs that people never noticed, I found a few things very quickly:

    • Someone reported higher than expected CPU use, and I discovered that there were a number of functions that ran regularly in timers, and I was able to quickly tune some knobs in order to reduce average CPU use by a lot. This is likely to be great both for the user in question, but also because it’ll help battery life.
    • The config includes a git submodule (!) with the contents of all third-party packages, mostly to reduce friction for people getting started. Downloading all of the packages fresh from the archive would take a few minutes, and the git clone is just faster. I realized, when someone ran into some problems when running with emacs 28 (e.g. the development/mainline build,) that the byte-compilation formats were different, which made the emacs27 files not work on emacs28. I pushed a second branch.

    More than anything the experience of getting bug reports and feedback has been great. It both makes it possible to focus time because the impact of the work is really clear, and it also makes it clear to me that I’ve accumulated some actually decent Emacs Lisp skills, without really noticing it.2

  • I was inspired to make a few structural improvements.

    • For a long time, including after the initial release, I had a “settings” file, and a “local functions” file that held code that I’d written or coppied from one place or another, and I finally divided them all into packages named tychoish-<thing>.el which allowed me to put all or most of the configuration into use-package forms, which is more consistent and also helps startup time a bit, and makes the directory structure a bit easier.
    • I also cleaned up a bunch of local snippets that I’d been carrying around, which wasn’t hurting anything but is a bit more clear in the present form.
  • I believe that I’ve hit the limit, with regards to startup speed. I’d really like to get a GUI emacs instance to start (with no buffers) in less than a second, but it doesn’t seem super plausible. I got really close. At this point there are two factors that constrain:

    • Raw CPU speed. I have two computers, and the machine with the newer CPU is consistently 25% faster than the slow computer.
    • While the default configuration doesn’t do this, my personal configuration sets a font (this is reasonable,) but seems that the time to do this is sometimes observable, and proportional to the number of fonts you have installed on the system.3
    • Dependencies during the early load. I was able to save about 10% time by moving a function between package to reduce the packages that startup code depended upon. There’s just a limit to how much you can clean up here.

    Having said that, these things can drift pretty easily. I’ve added some helper macros with-timer and with-slow-op-timer that I can use to report the timing of operations during startup to make sure that things don’t slow down.

    Interestingly, I’ve experimented with byte-compiling my local configuration and I haven’t really noticed much of a speedup at this scale, so for ease I’ve been leaving my own lisp directory unbytecompiled.

  • With everything in order, there’s not much to edit! I guess I’ll have other things to work on, but I have made a few improvements, generally:

    • Using the alert package for desktop notification, which allowed me to delete a legacy package I’ve been using. Deleting code is awesome.
    • I finally figured out how to really take advantage of projectile, which is now configured correctly, and has been a lot of help in my day-to-day work.
    • I’ve started using ERC more, and only really using my irssi (in screen) session as a fallback. My IRC/IM setup is a bit beyond the scope of this post but ERC has been a bit fussy to use on machines with intermittent connections, but I think I’ve been able to tweak that pretty well and have an experience that’s quite good.

It’s been interesting! And I’m looking forward to continuing to do this!


  1. Sure, other editors also have long setup curves, but Emacs is particularly gnarly in this regard, and I think adoption by new programmers is definitely constrained by this fact. ↩︎

  2. I never really thought of myself as someone who wrote Emacs Lisp: I’ve never really written a piece of software in Emacs, it’s always been a function here or there, or modifying some snippet from somewhere. I don’t know if I have a project or a goal that would involve writing more emacs software, but it’s nice to recognize that I’ve accidentally acquired a skill. ↩︎

  3. On Windows and macOS systems this may not matter, but you may have more fonts installed than you need. I certianly did. Be aware that webbrowsers often downlaod their own fonts separately from system fonts, so having fonts installed is really relevant to your GTK/QT/UI use and not actually to the place where you’re likely doing most of your font interaction (e.g. the browser.) ↩︎

Knitting Pictures

I’ve never been really good at the blogging+picture game, and while maybe once upon a time it was technical limitation--taking photos and getting them online was complicated--anymore it’s probably not. To this end, I’ve started a knitting specific Instagram account as a kind of photoblog for knitting things. It’s @gestaltknitting, if you’re interested.


While I took this picture a while ago, I must confess that my knitting basically looks the same now.

View this post on Instagram

A post shared by tychoish (@gestaltknitting)

The same, not because I’ve made no progress, but because sleeves take a while and it’s just plain knitting, so unless you have a very discerning eye, you might miss the details.

Indeed, I really want my next project to also have a lot of plain knitting with black yarn: I expect the photographs will be captivating. Perhaps it will be enjoyable for people to be able to spot the different patterns of embedded cat hair in the sweaters.


I get that knitting is visual for a lot of people, and I do like a smart looking sweater as much as the next guy, but I’ve always felt somewhat resistant to this view: knitting is about the process and the act more than it is about the product, and so the things that are most exciting aren’t the visuals.

While it’s gotten much easier to take high quality pictures, my intention for this book that I’ve been writing is that it mostly would not be a book with a lot of picture, though we’ll see: If anything, I suspect that diagrams and cartoons may be more effective for this kind of application.

Having said that, it’s nice to see what other people are knitting, and I like the way that the ephemeral nature of instagram stories make it less daunting to post in-progress updates on projects. So I’ve definitely been enjoying that.

We’ll see!

Learning Common Lisp Again

In a recent post I spoke about abandoning a previous project that had gone off the rails, and I’ve been doing more work in Common Lisp, and I wanted to report a bit more, with some recent developments. There’s a lot of writing about learning to program for the first time, and a fair amount of writing about lisp itself, neither are particularly relevant to me, and I suspect there may be others who might find themselves in a similar position in the future.

My Starting Point

I already know how to program, and have a decent understanding of how to build and connect software components. I’ve been writing a lot of Go (Lang) for the last 4 years, and wrote rather a lot of Python before that. I’m an emacs user, and I use a Common Lisp window manager, so I’ve always found myself writing little bits of lisp here and there, but it never quite felt like I could do anything of consequence in Lisp, despite thinking that Lisp is really cool and that I wanted to write more.

My goals and rational are reasonably simple:

  • I’m always building little tools to support the way that I use computers, nothing is particularly complex, but it’d enjoy being able to do this in CL rather than in other languages, mostly because I think it’d be nice to not do that in the same languages that I work in professionally.1
  • Common Lisp is really cool, and I think it’d be good if it were more widely used, and I think by writing more of it and writing posts like this is probably the best way to make that happen.
  • Learning new things is always good, and I think having a personal project to learn something new will be a good way of stretching my self as a developer. Most of my development as a programmer has focused on
  • Common Lisp has a bunch of features that I really like in a programming language: real threads, easy to run/produce static binaries, (almost) reasonable encapsulation/isolation features.

On Learning

Knowing how to program makes learning how to program easier: broadly speaking programming languages are similar to each other, and if you have a good model for the kinds of constructs and abstractions that are common in software, then learning a new language is just about learning the new syntax and learning a bit more about new idioms and figuring out how different language features can make it easier to solve problems that have been difficult in other languages.

In a lot of ways, if you already feel confident and fluent in a programming language, learning a second language, is really about teaching yourself how to learn a new language, which you can then apply to all future languages as needed.

Except realistically, “third languages” aren’t super common: it’s hard to get to the same level of fluency that you have with earlier languages, and often we learn “third-and-later” languages are learned in the context of some existing code base or project4, so it’s hard to generalize our familiarity outside of that context.

It’s also the case that it’s often pretty easy to learn a language enough to be able to perform common or familiar tasks, but fluency is hard, particularly in different idioms. Using CL as an excuse to do kinds of programming that I have more limited experience with: web programming, GUI programming, using different kinds of databases.

My usual method for learning a new programming language is to write a program of moderate complexity and size but in a problem space that I know pretty well. This makes it possible to gain familiarity, and map concepts that I understand to new concepts, while working on a well understood project. In short, I’m left to focus exclusively on “how do I do this?” type-problems and not “is this possible,” or “what should I do?” type-problems.

Conclusion

The more I think about it, the more I realize that when we talk about “knowing a programming language,” inevitably linked to a specific kind of programming: the kind of Lisp that I’ve been writing has skewed toward the object oriented end of the lisp spectrum with less functional bits than perhaps average. I’m also still a bit green when it comes to macros.

There are kinds of programs that I don’t really have much experience writing:

  • GUI things,
  • the front-half of the web stack,2
  • processing/working with ASTs, (lint tools, etc.)
  • lower-level kind of runtime implementation.

There’s lots of new things to learn, and new areas to explore!

Notes


  1. There are a few reasons for this. Mostly, I think in a lot of cases, it’s right to choose programming languages that are well known (Python, Java+JVM friends, and JavaScript), easy to learn (Go), and fit in with existing ecosystems (which vary a bit by domain,) so while it might the be right choice it’s a bit limiting. It’s also the case that putting some boundaries/context switching between personal projects and work projects could be helpful in improving quality of life. ↩︎

  2. Because it’s 2020, I’ve done a lot of work on “web apps,” but most of my work has been focused on areas of applications including including data layer, application architecture, and core business logic, and reliability/observability areas, and less with anything material to rendering web-pages. Most projects have a lot of work to be done, and I have no real regrets, but it does mean there’s plenty to learn. I wrote an earlier post about the problems of the concept of “full-stack engineering” which feels relevant. ↩︎

Pattern Fragment 0

I was doing some knitting pattern math,1 and I thought I’d share it without a lot of context:

Cast on 228 stitches using the “German Twisted” method,2, placing a marker half way, after 114 stitches. Knit 2 inches of knit 1 purl 1 ribbing.

After two inches, switch to stocking stitch: knit 21 stitches, increase 1 stitch, place a marker, knit 72 stitches, place a marker, increase 1 stitch, knit 21 more stitches. You should have arrived at the “half way” marker from before.

Over the next half (115 stitches), space out 14 increases. This doesn’t divide evenly, so try: knit 5, increase 1 stitch and then knit 8 stitches, increase 1 stitch 13 times, or in short hand: K5 M1, * K8 M1, repeat from * 13 times, K5).

The “first half” is the back of the sweater and the “second” half is the front. Increase one stitch before and after the markers on the back of the sweater 7 times, every 1.5 or 2 inches (somewhere between 10 or 20 rows,) depending on how you’d like the taper.

Meanwhile3 insert 3 sets of short rows across the back of the sweater, which should get wider. For the first short row stop 3 inches from the edges, for the second 2 inches, and for the last 1 inch. I’d put an inch or two between each short row, maybe half way between the first three increases.

Notes


  1. I’ve not, to be clear, actually knit this yet, though I plan to soon. ↩︎

  2. As in this video, though there are many videos that may be more clear for you. I’m pretty sure that learned this method from Meg Swansen and/or Amy Detjin. ↩︎

  3. I have to say, that the “meanwhile” part of knitting patterns is always my favorite. ↩︎

Reknitting Projects

I’m presently in the middle of knitting a sweater that I knit and designed years and years ago, with only minor modifications, and I have a number of projects that I’m thinking about that involve “reknitting” past projects. While I don’t think that I’ve peaked, or am out of ideas for knitting, it’s very clear to me that novelty isn’t exactly my guiding principle as a knitter: I enjoy the process and the act above all else, and the pleasure of wearing handknits is (for me) mostly about custom fit and less about novelty or fashion, exactly.

The chance to re-knit things, removes a lot of the questions of a design from the process and not only fix mistakes, but also polish and iterate on a garment with less guess work. It’s also the case that these projects often feel like returning to an old friend, which is incredibly comforting. Some of these projects, on my backlog include:

  • This basic two-color sweaters (colorblock, I suppose,) that I’m presently knitting and have/will knit again where the lower part of the body is in black--or similar very dark--except for the top 3-4 inches of the body in a contrasting color, matched by the sleeves and the collar, which I try and push into the black section.
  • Alice Starmore’s Faroe Sweater, from Fishermen’s Sweaters, but scaled to actually fit and maybe with a more fitted shoulder. I’ve also, apparently knit a very heavy weight version of the Norway sweater that I never wore, and they’re such great classic designs that are very fun to knit that knitting them again to modernize them sounds like a fun project.
  • A round pi shawl in a dark color, with no lace work (including using raised bar increases rather than yarn overs), and a contrasing set of stripes along the outer edge. There’s this stripe pattern that I think of as “Calvin Klein” stripes, but I don’t kno what the origin of that association is, the basic plan is three stripes, two wide stripes in the contrasting color, and a thin stripe of the original color in between, with the wide stripes being 3 times the width of the interior stripe.
  • I’ve knit two sweaters from Joyce Willams’ Latvian Dreams book, the sweater on the cover and one that I knit from several charts, using yarn that ended up pilling a lot. They were delightful to knit: the patterns were originally weaving charts rather than knitting patterns, and thus had a 4-way radial summary symmetry that was just fun to knit. I’d like to try some of these again with better yarn and perhaps use this as a space to explore color work again, but in ways that might be more subtle and also well suited to cardigans and the like.
  • I’ve knit a handful of sweaters with all-over mitten or stocking patterns from various extant knitting traditions, mostly Scandinavian and Turkish, and I think it would be fun to revisit these patterns.

For and Against Garter Stitch

I never used to like garter stitch1 very much, and hadn’t really knit things with a lot of garter stitch. Sure, a scarf here or there in the beginning, and I think I used it for the hem of an early sweater that didn’t turn out particularly well. There are so many clever patterns that use a lot of garter stitch, and I’d never really felt it. While I don’t know that I’m rushing to knit or design patterns out of a lot of garter stitch, I’ve definitely discovered that I’ve softened on it over my hiatus.

My earlier discontent with garter stitch was the combination of:

  • garter stitch is quite dense, because the fabric pulls in so much vertically, so it takes a lot of yarn and a lot of time, and results in a warmer fabric that I often don’t like'
  • the vertical pull in of the fabric can get pulled out by blocking or by the weight of the fabric which can be rather uneven.
  • normal tension irregularity is super apparent.
  • I’ve never much liked the way that knitting things with rows require you to flip the knitting and I don’t like the way that this can break up the rhythm of the knitting.
  • the strong horizontal line of the garter ridges always feels awkward to work with.
  • I always struggled to get a selvage edge that I really liked that wasn’t totally sloppy.

These, however, are tractable problems I realized, and I’ve always used a few garter stitches for selvage on the edge of sock heel flaps. The things that I’ve realized:

  • garter stitch often works best with very fine yarn, which helps ameliorate the additional bulk, and at least for me, helps provide for more even tension.
  • the look of garter stitch sideways is quite compelling, for me, and in most cases it won’t stretch out in the same way.
  • a little bit goes a long way, particularly when embedded in another piece of knitting.
  • I’ve settled down and find that knitting, rather than slipping, the first stitch and giving the yarn a slight tug when knitting the second stitch leads to a pretty clean edge.
  • designing with garter stitch is quite compelling, because the ratio of stitches to rows is basically 2:1, because of the way the ridges pull in, you can sort of approach it as “square,” picking up one stitch for every garter ridge lays very flat, so the math is never very complicated.

I’m working on a hat where I knit a ~2 inch wide garter stitch strip to fit around my head and then picked up to knit the crown of the hat along one of the sides of the strip, and along the other to knit a lining. I could have used a provisional cast on, of course, but the strip allowed me to be more confident about sizing, and it ends up being pretty sharp.

I’m not sure I’m going to plan to knit things out of primarily garter stitch, but I’ve definitely softened rather a lot.


  1. The fabric that results from knitting all stitches on both the front and back of the fabric. The fabric is dense, and it grows slowly, because the “ridges” account for two rows of knitting and it pulls in rather a lot. ↩︎

Sweater Measurements

Hand knitting provides the opportunity to customize sizing and shaping to fit your body (or that of whomever you’re knitting for,) and it’s possible to produce garments that really fit, but even though it’s possible it’s not always easy.

First, measuring a body directly is complicated:

  • posture impacts the measurements, and it’s difficult to get measurements of the body in the kinds of shapes and positions that you’re likely to hold while wearing the garment.
  • ease, or the difference between the actual measurement of your body and the actual measurement of the garment, is both subjective and a matter of preference.

For this reason, I normally recommend measuring another sweater that has a fit that you enjoy as a starting point, but there are challenges:

  • measurements for different styles of sweaters can have different internal proportions: the length of the sleeve depends on the width of the shoulders, and the depth of the armhole
  • most machine produced garments and conventional knitting patterns are based on typical measurements and proportions which are good as starting points but typically leave something to be desired.

While people’s measurements are broadly similar, and proportional, they’re not the same, so if you have slightly longer arms or shoulders that are a bit more broad or angular, the “average” might be off by an inch or two, which might be enough to care about.

I’d still recommend starting from a garment that you know fits well, and record the garment’s measurements as clearly as possible, but also note modifications separately. The basic idea is lay the garment out as flat as possible and measure the garment which is less likely to move than a person. There are three or four measurements that are really critical:

  • width of body at across the chest below the arms.
  • width of the body at the bottom hem/edge.
  • distance from the middle of the back of the neck to the cuff.
  • length of the sweater from the top of the shoulder to the bottom hem.

Sleeve length is pretty stable when measured from the bottom of the sleeve (where it joins the body at the underarm) to the cuff, as this avoids the impact of shoulder shape on the sleeve. Measuring arm length from a common point, the middle back of the neck, to the cuff is also a stable way to take this measurement. You may also require additional measurement’s if you want the body of the garment to have contores.

While it’s true that you can deduce other measurements from the four basic measurements, there are other fit considerations that are worth noting: width of the sleeve at/above the cuff and at the shoulder; depth, height, and aperture of the collar; as well as “true” shoulder width. May of these details I’ve figured out empirically and iteratively for myself: it’s sometimes difficult to get these measurements correctly from a model garment.