469 karma · joined August 15, 2010
E-mail: hello@zwobble.org
Blog: http://mike.zwobble.org/
GitHub: http://github.com/mwilliamson
For packages where I do include tests, I've had at least one user request that I remove tests so that the footprint of the Docker image they're building is smaller.
Both are entirely reasonable requests, but package repositories don't really provide a good way of accommodating both at the same time, for instance, by allowing a separate upload of the dev gubbins such as tests.
My (perhaps overly simplistic) take would be that we should take the thinking we use on the product itself (Who's going to use it? In what context? What would they already know? And so on), and apply and adapt it to the docs as we would any other product.
So, I had a go at making a little tool that lets you quickly make rough sketches of the map, as well letting you move tokens (for the characters) around. It's not particularly fancy, but it seems to work for us!
1. I think it's worth considering how much the Baumol effect is responsible for the price changes described. Specifically: we'd expect those industries that don't benefit from improved productivity (for instance, because AI doesn't actually meaningfully help with most parts of the work) to experience price rises, since they're competing in the labour market with other sectors that have have benefited from improved productivity, and can therefore pay workers more.
Or, to put it another way, you'd expect this effect to some degree in a market operating entirely without restriction.
https://en.wikipedia.org/wiki/Baumol_effect
2. If I remember correctly, in the past, when technological innovation eliminated jobs, the new ones that sprang up generally meant a rise in wages across the board. In other words, the overall effect was low-paid jobs being replaced with higher-paid jobs.
No more. In recent years, the graph of wages of replacement jobs looks more like a U-shape: they tend to either be low-paid or high-paid. For instance, take translating a textbook. A company might decide to fire their moderately well-paid translators with a steady job, and replace them with AI (built by another company, using a smaller number (per book) of high-paid tech workers), plus some low-paid, proof readers to fix up the mistakes. And the latter group is probably precariously employed: the better the AI gets, the less they're needed. And they're probably seen as lower skilled and therefore easier to replace by the company, so perhaps their jobs look more like precarious gig economy jobs.
That's a simplification, but I think the evidence suggests that that U-shape is a pattern that, very broadly, holds true. So, we might not be unemployed, but we might have a lot of people with falling incomes and much lower job security.
(Apologies, writing this in a hurry, so can't find a source right now!)
I run a tabletop RPG for some friends over the Internet using Roll20. As a player in other (in-person) games, there have been times where we've collaboratively made a map as we've gone along rather than the GM providing one, and I wanted to be able to provide a similar experience for my players. Since we found Roll20 didn't really work for this use case, I'm cobbling together an app that tries to make the experience as fluid as possible. It's only really intended for my group when I'll be on hand to explain how it works and I'll be the only one deploying it, so the docs are somewhat sparse, but in case anyone is interested:
https://github.com/mwilliamson/ttrpg-map-sketcher
I've also been working on a compiler for the most boring programming language in the world: https://github.com/mwilliamson/clunk
I maintain a library with ports to multiple languages (JavaScript, Python, Java). They have very similar structure, which means doing the same thing in pretty much the same way three times each time I make a change.
The idea I wanted to test with my language is: is it possible to extract a common subset that compiles into reasonably idiomatic code for those target languages? The compiled interfaces should be sensible (i.e. use of the code from the target language should be as good as if written in the target language directly), while implementations can be a little less tidy, but ultimately still readable and easily refactorable if the user ever decides to eject from my language and write everything in the target language(s) instead.
I doubt I'll ever use it in anger, and since it's nowhere near ready for use of any kind there aren't really any docs. In the unlikely event someone is interested, the most illuminating thing to look at would be the very beginnings of the reimplementation of the aforementioned library. Since I use snapshot testing with examples, you can see the source code, generated code and result of running the compiled test suite in one file:
Java: https://github.com/mwilliamson/clunk/blob/main/snapshots/%5B... Python: https://github.com/mwilliamson/clunk/blob/main/snapshots/%5B... TypeScript: https://github.com/mwilliamson/clunk/blob/main/snapshots/%5B...
Remote: Yes, or hybrid/office in Cambridge
Willing to relocate: No
Technologies: Most recent experience is with Python, TypeScript, React, GraphQL and PostgreSQL, but I've also worked with C# and Java. Happy to learn new things too!
CV: Available on request
Email: whoishiring@michaelwilliamson.co.uk
I've worked for the last 12 years as a full stack web developer. That includes building backends, frontends, APIs, data ingestion tools, infrastructure in AWS.
I've worked in various domains, such as education and biotech. I'd like to contribute to something that improves the world in some way. That might be the obvious stuff like helping students learn or finding treatments for cancer, or it might be something less glamorous like working on database technologies. It probably isn't working on blockchain or in fintech.
I enjoy working in cross functional teams: that is, I like teams that have all the skills needed to consistently deliver business value, whether that's typical software roles like developers and designers, or something more domain-specific such as pharmacologists.
If you're just looking for someone to pick up tickets and churn out code, I'm probably not a good fit. I'm interested in the wider team and company goals and strategy, and would like to work in a team where everyone can contribute to product thinking, rather than (for instance) having a product manager that writes all of the tickets. In the past, I've built internal tools and worked with the domain experts that use the tools to work out what problem to solve next, and what the next most valuable increment to build would be.
I'm also interested in how people and teams collaborate. For instance, in my experience, meetings are often unstructured chatting, or have one or a small number do the vast majority of the talking. This means that many people don't meaningfully contribute -- frustrating for them, and a loss to the group as a whole -- and decisions aren't made, aren't clear, aren't understood, or aren't widely supported. I've successfully used techniques such as those in the Gamestorming book and Liberating Structures to add structure that allows everyone to contribute, for a range of options to be discussed and considered, while reaching a clear decision at the end.
I've tended to work in smaller organisations since much of the above tends to happen naturally in those circumstances, but I'd be open to working anywhere that's a good fit and treats its people as more than fungible units of resource production.
One thing I'm curious about is how other people are handling the resolution of the screen on Linux? It doesn't seem like XFCE currently supports fractional scaling well, so I ended up defining a custom 3:2 resolution and using that to increase the size of everything by about 1.5x.
I forget exactly what conversations I had, but it was also very clear that they had no problem with me doing so since it doesn't really have any connection with their core business. If I wanted to, I suspect I could have open sourced the original version so long as I stripped out the stuff that was specific to the company.
More specifically, writing:
contains_exactly("a", "b")
is equivalent to: contains_exactly(equal_to("a"), equal_to("b"))If you were to ask me "Should I use precisely in my tests?", my answer would be: it depends. The main benefit is to better describe the intent of your test, so that the assertion is neither under- nor over-specified, with the intent directly stated.
Assuming your assertion is meant to be an alternative to the example in the README:
assert_that(result, contains_exactly("a", "b"))
I'd suggest that the above states the intention of the assertion, rather than how you check it. For instance, your assertion would allow duplicate elements, whereas the assertion as originally written would suggest that this isn't desired. As other comments have pointed out, you can do things with sorted, Counter or set (depending on exactly what you want to assert), but why worry about what trick to use when you could just directly state your intention?The assertion using precisely is also (arguably) easier for a reader to know what is (and isn't) being asserted in the test, and makes the test less brittle since you're not accidentally asserting more than intended (for instance, it's common to assert equality with a list, even though you don't actually care about order).
Another common case is when you want to make assertions on a collection, but equality would check too much. For instance, suppose you have a function that fetches users from a database. The fetch can return the users in any order, and you just want to check the names of the returning users, so you can write something like:
assert_that(result, contains_exactly(
has_attr(name="Alice"),
has_attr(name="Bob"),
))
How would you write something that means the same thing without precisely? The order isn't deterministic, so you can't write something like: assert result[0].name == "Alice"
assert result[1].name == "Bob
assert len(result) == 2
We could sort the users by name before making the assertion: result = sorted(result, key=lambda user: user.name)
assert result[0].name == "Alice"
assert result[1].name == "Bob
assert len(result) == 2
Personally, I prefer the precisely assertion!What about something like an equality assertion?
assert set(result) == {
User(id=1, name="Alice", email_address="alice@example.com"),
User(id=2, name="Bob, email_address="bob@example.com"),
}
Now we've over-specified our test -- we need to know irrelevant details like the ID and e-mail address of the users, which might change and break this test even when the functionality we care about still works. We'll also break the test if we add any more attributes to users.As you've mentioned, there's a cost to learning precisely. Even if you're familiar with the library, then you're still potentially writing a more complex assertion (where more can go wrong) than just (for instance) an equality assertion. In my experience, on many projects, the ability to state the intent of assertions precisely has far outweighed the downsides, but that's from a position of already being comfortable with the library.
Better error messages was the motivation: PyHamcrest tends to put everything onto one line, which makes it hard to discern structure. In contrast, precisely tries to produce an error message that uses line breaks and indentation to match the structure of the matcher, hopefully making it clear exactly which part of the matcher has failed.
Social impact bonds are an interesting idea that might help solve this, although I know little about the practicalities. Specifically, a company would pay for the research and trials, and if it's effective, the government (say, the NHS in the UK) would pay a portion of the money saved to the company.
The advantage of this over plain .graphql files, or statically extracting queries, is that you can use all of the normal tools of TypeScript for composing queries (mainly imports and template literals), and you don't need to have globally unique names for all your queries and fragments. Having said that, I haven't looked at the recommended Apollo workflow in a little while, so I'm not sure if those issues still exist.
If you think using TDD improves the quality of your code, then it's also important for maintaining high code quality, since that enables some of the other agile practices, such as frequent releases.
I don't worry too much about whether a particular practice is agile or not. If you find TDD useful, then great! It's often included in conversations about agile development, but that doesn't mean you have to be doing agile development in order to use it.
Firstly, it gives you a set of tools to use -- sprints, TDD, product owners, and so on -- that should work well together. To use them well, I think you both need an understanding of how each of those tools supports some idea or principle that the methodology promotes, and whether or not you think that principle is important for your team.
Secondly, a methodology gives you a starting point of how to run a development team. It's easier, although not necessarily better, to start from a pre-existing cohesive set of practices than to build a process from scratch. Especially if a team isn't experienced with many of the ideas, this is not an unreasonable place to start.
I think the key is:
1) knowing what principles your team thinks is important (low defect rate? frequency of releases? developer happiness? empowerment?). This is often hard to articulate. As time goes by, you might discover principles that were previously implicit, or you might find that the principles that are important to you change.
2) knowing how each part of your process maps back to one or more of those principles
3) having a mechanism that allows you to tweak your process over time (for instance, retrospectives), whether that's adding, changing or removing parts of your process
Scrum can be a sensible starting point so long as you're willing to introspect and consider which bits are and aren't working for you, and you're empowered to do something about it.
Healx is a Cambridge, UK startup using computational methods to identify existing drugs that may treat rare diseases. We have data coming out of our ears, including biological data, scientific literature and the results of our analyses, so we've built internal web tools to help our team to make sense of it all. We're hiring a full stack developer to help us find better ways of presenting the data, whether it's for pharmacologists exploring the evidence that a drug may treat a disease, or salespeople finding information about a disorder and related charities.
To apply, please email jobs@healx.io with your CV and a few words explaining why you're interested in the role.
[1] https://github.com/mwilliamson/node-graphjoiner
However, it's rather verbose with repeated boilerplate, so to make the approach work I think you'd want to put a higher-level layer on top -- that's what I've done with a Python implementation [2]. I think the general approach is the valuable part, rather than the specific libraries, and seems more in keeping with how I'd normally write queries than the usual DataLoader approach. In particular, I've found it tends to improve performance when fetching large data sets since you don't need to call a resolution function on every single field that gets returned. (DataLoader implementations batch queries together to avoid the n+1 problem, but they mean that you need to implement a batching layer, and probably make your resolution functions asynchronous, which is especially expensive for large data sets).
Not only did AES have tens of thousands of employees, many of them joined by way of acquisitions of existing plants, rather than being hired by AES with their ethos in mind. That's not to say that everybody was a good fit (some people chose to leave given the choice), but that many stayed and eventually appreciated the change in management structure challenges the idea that self-management is only appropriate for a small proportion of people.
[1] http://www.amazon.co.uk/Made-Stick-ideas-others-unstuck-x/dp...