I recently got a new laptop; a Dell XPS 13. It's pretty swanky, but it isn't a MacBook, which is a first for me in quite some time. That's meant getting used to a new physical construction, a new keyboard, a new trackpad, and even a new operating system! I installed Elementary OS because I wanted a Linux, and I wanted it to be simple and easy to use. So far, it's mostly lived up to these things, which has been great.
I've generally been really happy with both the laptop and the OS, but one of my annoyances is that it doesn't have dedicated buttons to make the screen brighter or dimmer; you can click the power indicator and get a scroll-bar for brightness, but that's a little clicker than I'd like. So I did some learning...
It turns out there's a file through which you can control brightness: /sys/class/backlight/intel_backlight/brightness - it contains a number between 0 and 7500 (inclusive) which shows your current brightness level, and you can write a number in that same range to the file to set the brightness level. It can only be written to by root.
The Keyboard settings pane has an option to set shortcuts, so you can say "If I press control and the NextTrack button, run this command".
So, the answer seems to be: Write a tiny little program which updates that file, make it setuid-root (so that when anyone runs it, it runs as root), and set up a shortcut which runs it.
So I wrote a tiny little program (in Rust). Note that this needs to be setuid-root, which means it needs to be carefully designed. Scripts aren't allowed to be setuid-root, so it needs to be a compiled program. And it keeps its user input space pretty minimal; the path it's writing to is hard-coded (if it took it as a parameter, people could write to arbitrary files as root - scary!), it takes instructions like "up" and "down" rather than take a value to set (to avoid needing to sanitise input), and it crashes out aggressively if anything goes even a little bit wrong.
I built it, by running (after installing the rust toolchain as per https://rustup.rs):
cargo build --release
made it setuid-root by running:
sudo chown root:root target/release/set-brightness
sudo chown 4755 target/release/set-brightness
put it on the $PATH by running:
sudo mv target/release/set-brightness /usr/local/bin/
and created my shortcuts by opening up System Settings, going to Keyboard, clicking Custom, clicking the +, entering the command set-brightness up, clicking where it says "Disabled", and pressing the shortcut keys I wanted.
Now I have "brightness up" and "brightness down" keyboard shortcuts, and life is good :)
illicitonion
Sunday, 2 September 2018
Monday, 11 June 2018
What I want from a code review tool
Many of my friends and colleagues will have heard me decry the state of code review tooling in the open source world. Here, I try to collect my thoughts on what I feel is missing; maybe it will help motivate some of the big players in that direction, maybe it will serve as a roadmap for my next side-project.
I'm going to assume that as a reader, you're bought into the general idea of code review: a place for people to get constructive feedback about a change they want to make (a "Pull Request") before that change is merged onto a target branch.
So what do I want from a code review tool?
As a code author, I want to easily see the status of my change. What needs to happen before I'm comfortable merging it? Some examples:
I'm going to assume that as a reader, you're bought into the general idea of code review: a place for people to get constructive feedback about a change they want to make (a "Pull Request") before that change is merged onto a target branch.
So what do I want from a code review tool?
As a code author, I want to easily see the status of my change. What needs to happen before I'm comfortable merging it? Some examples:
- Have my reviewers looked at the code yet?
- If not, I probably don't want to merge my code (obviously, there are exceptions).
- There is some nuance here - as a code author, am I just looking for someone to look over my code, just to sanity check it? Am I looking for Janet to review this code, because we had a discussion about the design, and she's best placed? Do I also want Sophie to also take a look, because she probably knows a better language construct I could be using? Whose review is sufficient?
- There's more nuance that gets added from the reviewer side; I've yet to use a code review tool which has relationships between reviewers: "I'm ok with it if Sophie is". It's hard to express these concepts elegantly, but I suspect it can be done.
- Have any of my reviewers left comments which I haven't addressed? Which comments still need addressing?
- My general rule of thumb is that all comments should either be addressed in code, or explained as to why they're not.
- There is some nuance here - some comments are trivially addressable; some may need discussion, or I may try to address them, but not do a great job of it, and need follow-up. Ideally, the nuance of "I've left a comment, feel free to ignore it" vs "I've left a comment, I'm sure you'll address it fine" vs "I've left a comment, but would like to have another look before it's considered addressed" would be captured, in a low-friction way.
- If any tests have been run, have any failed? If so, I probably want to investigate that before I merge my code.
I've yet to use a code review tool in the open source world which actually meets these three criteria. Most shy away from modelling the social interactions and connotations of code review (things like "I'm ok with it if Sophie is"), and instead try to dump all of the information that could be relevant at you. Saying in one place "Janet has accepted, Sophie hasn't reviewed yet", and in another "Janet mentioned half-way through a paragraph that Sophie should probably take a look). Worse - many of them hide information they deem out of date. When nuance can only be expressed through text, it's great to have the text there for people to read, but wouldn't it be nice if a green tick meant "Good to merge", rather than maybe "Good to merge" or maybe "Good to merge if you make this change" or maybe "Good to merge but it would be great for Sophie to have a look too"?
As a code reviewer, I want to see what I need to do to unblock people.
- Has someone asked for my review, which I haven't provided?
- Has someone responded to one of my comments?
- Has someone acted on one of my comments where there's follow-up I should do?
Within the tool, there are two very distinct conversations to have; "Is this change generally sensible" and "Are the specifics of the code sensible?" - fortunately, the existing tools seem to cover this pretty well, with "change comments" and "line comments".
Now that the general concepts are covered, what specifics do I want in a code review tool?
- High quality code browsing.
- Syntax highlighting.
- Click-through and find-usages of symbols.
- High quality diffing.
- Code diff chunks should include the name of the function, and type, the code is in.
- Reviewing similar images? Show a diff!
- Context of wider change.
- Is there a ticket/issue describing the larger-scale work that this change is part of? Link to it! Render some text from it!
- Are there follow-up changes? Does it build on previous changes?
- Does this change depend on other pending changes? Should they be merged atomically?
- Ideally changes should be very small, but navigable with the right context to understand the bigger picture. Being able to change that level of granularity ("show me the change to this file in this pull request", "show me the whole change of the whole stack of dependent pull requests") would be nice, too.
- Previews.
- Editing a markdown document? Render a preview, and render a diff!
- Editing a web frontend? Host a preview of the site somewhere, and link to it.
- An elegant, at a glance view of what I need to do, both per-review, and across all reviews.
- Reviewers should be able to give code-edit suggestions.
- Double-clicking on the code, fixing the typo, and presenting the code author with an "Accept suggestion" button is so much lower friction than saying "nit: It's just a typo, but there's an extra s here", and then requiring the code author to change branch, make an edit, commit, push, and say they've fixed it.
- Automated reviewers should be easy to plug in.
- If I can write a tool which detects problems, I can save humans time.
- Doubly so, if they can propose code-edit suggestions which can be accepted at a button-press.
- There are a few classes of these; "always correct" suggestions vs "maybe a good idea" suggestions.
- Merging code by pressing a button in a web UI is nice.
- Having an option to merge automatically when reviewers are happy is even nicer.
What don't I want in my code review tool?
- Anything to do with the specifics of a version control system.
- Maybe the system ingests things via git push or ingesting a patch file, and maybe it can merge things onto a branch, but those should be the only times version control matters.
- Visual clutter.
- Everything I want to know about a review should be quick and easy to discern at a glance. I should be able to dig in deeper when I need/want to.
- An overly simplified, or overly strict, model of review.
- Different projects, teams, companies, and people, use different models for code review requirements, and code ownership. Code review tools all seem to either treat all reviewers as equal, or assume that each reviewer ticks a certain box (generally "owns directory X"). If what I want to say is "I'm happy with this code, but Sophie should check it over", or "I'm happy with this code, but here are some trivial things you should address first", or "Two people should review every change", I want that to be obvious.
There are also some crazy ideas that I'd love to see, but which sound hard:
- AST-aware formatting, diffing, and history.
- It's crazy that people need to have style guides, and style wars, over when lines should wrap, or how much things should be indented. "Lines" of code is a weird concept. Statements and expressions are the building blocks of code, not lines!
- Semantically aware change decomposition.
- You renamed a field, then extracted a function, then added a new call to the function. Wouldn't it be cool if your code review tool could tell your reviewer that's what you did, rather than them inferring it from reading?
Sunday, 3 June 2018
Rust minimum versions: SemVer is a lie!
A couple of months ago, cargo got a new feature I've been wanting for a while; an option to select the minimum, rather than maximum, compatible versions of each of your (transitive) dependencies, according to semver. So if you say you depend on foobar version 1.1, it will pick 1.1.0 not 1.1.16, as opposed to the standard behaviour of choosing 1.1.16. By traditional wisdom, this isn't something you actually want to use in real life, because newer versions tend to have optimisations / security fixes / ... which older versions don't. But it's a useful tool for checking whether your declared supported dependency versions are accurate.
This has particularly been in my mind recently because of Russ Cox's recent work on semantic versioning dependencies in Go. The tl;dr of that is: Avoid making breaking changes, libraries specify their minimum supported version of their dependencies, and the Go tooling will choose the minimum supported version of each dependency which works for the transitive set of dependencies. It does exactly the thing that traditional wisdom says is bad, but Russ argues pretty convincingly that this is good [1]. However, Russ's arguments rely on this being a community-wide adopted standard practice; if the community isn't all using the minimum supported version of things, it doesn't work, because nothing advances the base version of libraries, and everyone ends up stuck with super old versions of everything.
I thought I'd see how minimum versions worked out in the Rust ecosystem. I used my current main Rust project, the scheduling engine of the Pants build tool, as my playground. The project is about 50kloc, and has 134 transitive dependencies. Those dependencies include a handful of fairly common pure-rust libraries (clap, futures, tokio), a handful of C/C++ libraries (lmdb, grpcio, fuse), and a long tail of others.
I was expecting some things not to work, but I was mostly expecting to just need to bump some versions because libraries were using features introduced in newer minor versions than they claimed. I was surprised by some of the ways that things didn't work, and how hard it was to fix them...
1: Russ Cox's series of blog posts is very interesting, and well written, and I recommend giving it a read if you're interested in this kind of thing. I have mixed opinions on the design in general, but that's a conversation for a different day!
This has particularly been in my mind recently because of Russ Cox's recent work on semantic versioning dependencies in Go. The tl;dr of that is: Avoid making breaking changes, libraries specify their minimum supported version of their dependencies, and the Go tooling will choose the minimum supported version of each dependency which works for the transitive set of dependencies. It does exactly the thing that traditional wisdom says is bad, but Russ argues pretty convincingly that this is good [1]. However, Russ's arguments rely on this being a community-wide adopted standard practice; if the community isn't all using the minimum supported version of things, it doesn't work, because nothing advances the base version of libraries, and everyone ends up stuck with super old versions of everything.
I thought I'd see how minimum versions worked out in the Rust ecosystem. I used my current main Rust project, the scheduling engine of the Pants build tool, as my playground. The project is about 50kloc, and has 134 transitive dependencies. Those dependencies include a handful of fairly common pure-rust libraries (clap, futures, tokio), a handful of C/C++ libraries (lmdb, grpcio, fuse), and a long tail of others.
I was expecting some things not to work, but I was mostly expecting to just need to bump some versions because libraries were using features introduced in newer minor versions than they claimed. I was surprised by some of the ways that things didn't work, and how hard it was to fix them...
Language stability
For the last couple of years, Rust has felt like a relatively stable, but quickly improving language. If you look through the "Compatibility Notes" and "Breaking Changes" section of the release notes since 1.0 (now 3 years ago), pretty much everything is a minor and niche issue; the language has been adding many things, but rarely breaking old ones.
There has been some discussion as to whether the minimum version of rustc you need to compile with should be considered part of a crate's API, and whether increasing that value should require a major version change. I was surprised, however, to find that the opposite was a common problem when pinning to minimum versions - the minimum supported semvers of some of my transitive dependencies are so low that they don't compile with recent (or for some, any post 1.0) versions of rust!
Some examples, with rust 1.25:
- log is, surprisingly, a problematic crate. One of my dependencies specifies a '0.*' dependency on log, I guess because it doesn't want to be the most constraining dependency for something it doesn't care much about - the antithesis of the requirement for the whole community to bump minimums of Russ's proposals for Go. This means that I actually end up with all of log 0.4.1, log 0.3.1, and log 0.1.0, all in my application. But log 0.1.0 uses regex 0.1.0, which was released in 2014, pre rust 1.0, when Rust was a very different language. But it's not obvious what this crate should be doing. Technically, if you found the right compiler, log 0.1 would probably be fine for this library. In all practical terms, it doesn't work with log 0.1, because I suspect there isn't a version of the compiler that supports both regex 0.1.0 and the language features of my dependency. What version should it specify? Should it find whichever version of log's transitive dependencies built with rust 1.0, and specify that? Or rust 1.12? Or rust 1.20?
- rand 0.3.13 (released January 2016) doesn't compile, because it depends on winapi 0.0.1, again released in 2014. I guess it was useful to find out that the protocol buffer compiler I'm using is using a two year old crate for making temporary files, which itself depends on rand 0.3.13 (and that there are much more commonly used crates for this purpose), but am I really going to send them a PR moving them over to use tempfile instead? Maybe... Maybe switching to actively maintained crates with stable versions is beneficial to the ecosystem. But that feels like it would be a surprising PR to receive, and certainly isn't the base expectation of the Rust community today.
- All of my C/C++ dependencies end up depending on pkg-config 0.3.0, which doesn't work with any rust since 1.0. But eeeeeverything does that! libz-sys, libgit2-sys, libssh2-sys, lzma-sys, libsqlite3-sys, libsodium-sys, ffmpeg-sys, libdbus-sys, glib-2-0-sys, and dozens of other widely used libraries maintained by people who know what they're doing, specify their pkg-config dependenciy as ^0.3. Are they all doing something wrong? Surely not...
Fixing these things is hard
I got my library compiling, eventually, but it took a lot of effort, and required forking several projects. Let's take a look at the log example. Ideally, I should somehow be able to say "I don't care what my dependencies say they need, give them log 0.4.1, that's the log I want to use". I found the [patch] section which looked like it did what I wanted, but it doesn't appear to cover transitive dependencies. Maybe there's something I missed, here?
So I started forking all of my dependencies which themselves had problematic dependencies. Ideally I can get PRs merged to update these things, but it's not obvious that "increase the minimum version you specify so that the minimum version actually compiles on modern Rust" is a reasonable pull request; partially because rust versions don't factor into versioning anywhere, and partially because minimum versions aren't expected to be used, even though they may technically be expected to work. Again, it feels like a weird PR to receive.
Does this matter?
Maybe this doesn't matter, in practical terms. Cargo prefers the most recent available version, and that mostly works for people. And maybe this whole problem is just a relic of pre-1.0 to post-1.0 transition, and it will go away at some point. But it seems strange that we bother to go through all of this writing down semvers of our dependencies, only for them to frequently be lies. Maybe Russ Cox is right, and you need to force people to keep them accurate by actually using the minimum versions. Maybe we should give up with specifying minimum versions at all, and just always use the most recent version (relying on Cargo.lock files for reproducibility). Maybe now that we have -Z minimal-versions, it will be easy to add these checks to people's CI (or even on the crate publishing path), and we can enforce that what we write down is accurate. Maybe this is yet another reason we should be factoring "supported rust versions" into dependency resolution (either by including it in semver, or by tracking it separately in Cargo.toml files). I don't know what we should do as a community, but right now, things feel a little weird.
1: Russ Cox's series of blog posts is very interesting, and well written, and I recommend giving it a read if you're interested in this kind of thing. I have mixed opinions on the design in general, but that's a conversation for a different day!
Monday, 8 January 2018
Rust: Lacking equivalence under simple refactorings
I've been writing a fair bit of Rust recently. I'm new to the language, and it's been alternating between making me very happy, and making me very frustrated. One of the things I've been finding frustrating is the number of places that I expect two pieces of code to be equivalent where they are not. Here's some sample code, which I'm going to use in a few examples:
First, let's look at call_one and call_two. These look like they should be identical code; the simple application of an "inline" refactoring (or "extract variable", if going in the other direction). But in reality, call_two is fine, but the borrow checker is unhappy with call_one:
So what's going on here? When you declare a variable with let, its lifetime begins, and it remains live until the variable it's bound to goes out of scope. But if you never bind an expression to a variable with let, its lifetime immediately ends, and it gets dropped. There seem to be some special-cases where this is transparently handled for you (look at call_three - it's exactly the same as call_one which the borrow checker finds problematic, but the borrow checker is fine with this one. The only difference is that bar borrows self mutably, whereas foo doesn't. I assume that internally, the compiler is somehow promoting foo to be an owned type, or creating a hidden temporary which owns the Foo. It would be nice if the same courtesy could be afforded to more mutable references until something actually tries to violate constraints, like actually modifying the reference, rather than just preventing anonymous mutable borrows entirely). The big place I've seen this be a problem in real life is with the builder pattern; if I want to populate my builder with some arguments, and then build from it more than once, I need three statements: to assign the un-populated builder, to populate it, and to build it, where I'd really like two: to assign the populated builder, and to build it.
There is work underway in the language to solve part of this problem, with something called non-lexical lifetimes (NLL). Take a look at call_four, call_five, and call_six. Again, these look like they should be equivalent, but call_four makes the borrow checker unhappy.
This time, the borrow checker is unhappy for the opposite reason: a variable's lifetime is bounded by its scope, and its scope continues until the end of the block in which it was declared, so baz, which mutably borrows f, precludes bar from being able to borrow it, even though baz could be analysed by the compiler to be dead. You can work around this by avoiding the assignment, as in call_five, or by introducing an inner scope, after which baz gets dropped, as in call_six. The NLL work will address this, and perform the liveness analysis to render these workarounds unnecessary.
Having to re-structure code which otherwise feels like it should be equivalent to satisfy the borrow checker is pretty frustrating, and occasionally means sacrificing clarity. It's great to see work being done to improve this situation, and I hope it continues to go further!
#[derive(Debug)]
struct Foo {}
impl Foo {
fn foo(&self) -> &Foo {
self
}
fn bar(&mut self) -> &Foo {
self
}
fn baz(&mut self) -> &mut Foo {
self
}
}
fn call_one() {
let bar = Foo{}.bar();
println!("{:?}", bar);
}
fn call_two() {
let mut foo = Foo{};
let bar = foo.bar();
println!("{:?}", bar);
}
fn call_three() {
let foo = Foo{}.foo();
println!("{:?}", foo);
}
fn call_four() {
let mut f = Foo{};
let baz = f.baz();
println!("{:?}", baz);
let bar = f.bar();
println!("{:?}", bar);
}
fn call_five() {
let mut f = Foo{};
println!("{:?}", f.baz());
println!("{:?}", f.bar());
}
fn call_six() {
let mut f = Foo{};
{
let baz = f.baz();
println!("{:?}", baz);
}
let bar = f.bar();
println!("{:?}", bar);
}
First, let's look at call_one and call_two. These look like they should be identical code; the simple application of an "inline" refactoring (or "extract variable", if going in the other direction). But in reality, call_two is fine, but the borrow checker is unhappy with call_one:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:19:26
|
19 | let bar = Foo{}.bar();
| ----- ^ temporary value dropped here while still borrowed
| |
| temporary value created here
20 | println!("{:?}", bar);
21 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
So what's going on here? When you declare a variable with let, its lifetime begins, and it remains live until the variable it's bound to goes out of scope. But if you never bind an expression to a variable with let, its lifetime immediately ends, and it gets dropped. There seem to be some special-cases where this is transparently handled for you (look at call_three - it's exactly the same as call_one which the borrow checker finds problematic, but the borrow checker is fine with this one. The only difference is that bar borrows self mutably, whereas foo doesn't. I assume that internally, the compiler is somehow promoting foo to be an owned type, or creating a hidden temporary which owns the Foo. It would be nice if the same courtesy could be afforded to more mutable references until something actually tries to violate constraints, like actually modifying the reference, rather than just preventing anonymous mutable borrows entirely). The big place I've seen this be a problem in real life is with the builder pattern; if I want to populate my builder with some arguments, and then build from it more than once, I need three statements: to assign the un-populated builder, to populate it, and to build it, where I'd really like two: to assign the populated builder, and to build it.
There is work underway in the language to solve part of this problem, with something called non-lexical lifetimes (NLL). Take a look at call_four, call_five, and call_six. Again, these look like they should be equivalent, but call_four makes the borrow checker unhappy.
error[E0499]: cannot borrow `f` as mutable more than once at a time
--> src/main.rs:39:15
|
37 | let baz = f.baz();
| - first mutable borrow occurs here
38 | println!("{:?}", baz);
39 | let bar = f.bar();
| ^ second mutable borrow occurs here
40 | println!("{:?}", bar);
41 | }
| - first borrow ends here
Having to re-structure code which otherwise feels like it should be equivalent to satisfy the borrow checker is pretty frustrating, and occasionally means sacrificing clarity. It's great to see work being done to improve this situation, and I hope it continues to go further!
Pixel 2
For the last 6ish years, I’ve primarily been an iPhone user. Every few years, I’ve tried out a flagship Android phone as my main phone for a non-trivial period of time (most recently the Nexus 6), and I’ve always switched back to an iPhone. About six weeks ago, I got a Pixel 2, and I’ve been using it pretty much exclusively. Here are my thoughts on being both an Android user, and a Pixel 2 user.
tl;dr: Android is pretty good - definitely up to iOS quality. The hardware is pretty solid, but lacks a lot of finesse. If I switch back to an iPhone, it will be because of the physical build quality, but I’m not likely to do that at least until this phone dies.
Android
Android has gotten a lot better. The user experience is a lot more consistent and a lot less flaky than it used to be. I’ve only had Google Play Services crash once. The permissions model is a lot cleaner (you can deny specific permissions to specific apps, though more on that later). In the past, when I’ve switched from an iPhone to an Android phone, I’ve instantly felt painful regressions, and they wouldn’t go away no matter how much I got used to the operating system. This time, while there are things I prefer about each system, I can’t obviously point at one and say “I strongly prefer this one”. I don’t really have any major complaints about the core Android operating system any more. But there are some things I really like about it:
- ChromeView integration. If I open a link in the Twitter app, I can select “Open in Chrome” from the drop-down menu, and my exact screen will be preserved, scroll-location and all, just in a standalone Chrome tab. This is amazing.
- Chrome tabs are preserved offline a lot more than I saw on my iPhone, and the “download when next online” feature is pretty swanky too.
- Gboard (Google’s swipe keyboard) is really nice (and because it’s better system-wide supported, works in most apps, unlike on iOS). Nonetheless, every now and then an app appears to use its own custom keyboard, or something, and I find that my attempts to swipe to type fail randomly.
- Sharing intents work a lot nicer than iOS’s half-baked copy of them.
I still don’t understand why Phone and Contacts are separate apps, or when I’m meant to use each of them.
Region-locked app-store
My one big complaint, which I’m aware is a little niche, is around region locking in the Play store. For weird historical reasons, my Google account is US-based rather than UK-based. Accordingly, I cannot install the apps for one of my banks, or one of my credit cards, and the BBC iPlayer and iPlayer Radio apps don’t let me download content. On iOS, I could switch the country in which my account is registered through an official process, by entering a billing address and card in that country, which would let me download apps from the other country, and then switch back. On Android, I can only emulate this by signing in as a second user, which is a generally poorly supported flow. For one thing, it means I need to switch accounts to get to the apps, and for another, storage doesn’t really work properly (downloads from the BBC apps fail in obscure ways, for instance).
The workaround here would be to side-load the apps, but that’s kind of sketchy security-wise.
If you want to install apps from multiple regions, I recommend an iPhone.
Permissions
- “All files and photos”. Oh god. If you want to give an app permission to save any files or photos or data, you need to give it permission to read, write, or delete all files and/or photos on your phone. This is very alarming! Please please please let apps have a private sandbox, and a separate permission for some kind of global storage!
- Notifications are on by default. Accordingly, my notifications are super spammy, until I manually tweak them down. This is pretty annoying; I suspect that one of the reasons that iOS is less spammy notification-wise is that there’s a user prompt before notifications can ever be sent, and so app developers need to convince people to enable notifications with some good reason before they can spam.
- Each bank / credit card app on my phone told me it needed permission to make and manage phone calls, and promised me it wouldn’t ever actually use it, but it needed to use it to verify security somehow. Weird.
Photos
The Photos app doesn’t appear to have a way to let me scroll through all of my taken photos, received photos from WhatsApp, received photos from each other app, screenshots, etc, in one view; I need to remember which one of the above the photo I’m looking for was, and open the correct folder. Not the end of the world, but a little annoying.
Android Pay
Android Pay appears to have less broad adoption from credit card companies and banks than Apple Pay does. But I don’t really use either, so it doesn’t matter to me that much.
WiFi Connections
My iPhone was pretty sluggish to connect to wifi, and often needed prompting, particularly when on the tube. My Pixel 2 appears to join wifi networks really quickly, and without prompting, which gives a much smoother experience on the tube.
Automatic re-enabling of Wifi
I found out about this feature yesterday! If you’ve disabled wifi, and Android detects that you’re near a wifi network which it thinks is good, it will turn your wifi back on! This is a terrible feature to enable by default! Firstly, if I’ve disabled my wifi, it’s for a reason, and you shouldn’t assume to know better. Secondly, I can only assume that it does this detection by probing, which means that 1) it’s using my battery to do so, and 2) it’s broadcasting my MAC address when I may have asked it not to.
The back button
I find it pretty hard to predict what the back button will do at any time. If I open a link from an email, and press back, it closes the Chrome tab and takes me back to my email. If I click a Twitter link from Signal, and press back, it takes me to the most recent Tweet before that which I opened from a link in Signal. What?
Camera
The camera is pretty good. A similar quality to what I’d expect on an iPhone (though slightly worse in low-light conditions). It takes “motion images” by default, which are kind of fun (they give a 1-3 second animation around the frame you’re actually taking), but a little annoying to share (if I try to email them to myself, they’re about 8MB each, and there doesn’t appear to be an easy way to just send one frame).
Pixel 2 software
This is something I’m actually really disappointed about. One of the joys of getting a Google experience phone is that vendors don’t mess with the UI, bundle in un-removable apps, etc. And yet, on my homescreen I cannot move or remove the search bar at the bottom of the screen (which I never use, but frequently accidentally tap on when I’m trying to open one of my pinned apps), and I cannot move or remove the “At a glance” display at the top of the screen. I really wish I could actually configure my device as I want to, without rooting it.
Pixel 2 hardware
Weirdly, this is my area where I have the most complaints. Which I wasn’t expecting, considering the price tag and marketing of the phone.
Screen
My screen is covered in scratches. I have no idea what from; I’ve not had any incidents which should have scratched it. I’ve used it exactly the same as my iPhone; keeping it in the same pocket with the same things, putting it on my same bed-side table. I can only assume the iPhone screen is made of a tougher material, or has a coating, or something. I’m actually pretty disappointed that my phone has several noticeable scratches six weeks in.
Fingerprint sensor
I really dislike the location of the fingerprint sensor. It’s on the back, just above where your index finger rests on the back of the phone. With my iPhone, if I had the phone on my desk, I could tap the sensor with my index finger, and interact with my phone. With my Pixel 2, I need to pick up the phone, and poke the back of it; this is a surprisingly much higher friction activity to do something like glance at a message I’ve received.
I also accidentally press the fingerprint sensor a lot when my phone is in my pocket when fumbling for my phone, or wallet, or whatever, which necessitates putting in my PIN to unlock (because it hits the fingerprint attempt limit). Minor, but annoying.
Speaker location
At night, I leave my phone face-down because it has a flashy light on it. The speaker appears to be on the front of the phone. So if I want to settle down with a podcast or music or something, I can’t really hear it. My iPhone didn’t suffer from this problem, as the speaker is at the bottom.
One USB-C port is awful
My biggest wish is that my phone had either a 3.5mm headphone jack, or two USB-C ports, so that I can plug in both a charger and headphones. I have some good bluetooth headphones, but sometimes I want to use cheap earphones, so I’ve bought a bluetooth receiver (which is excellent, for the record) that I can plug my earphones into, but I need to carry it around, and charge it, and just ugh.
I looked at getting a splitter which allows you to plug both headphones and power into one end, and plugs into the USB-C port on the phone. As far as I can tell, there are several available, but most of them probably don’t work with any particular phone. Ugh.
The bundled USB-C -> 3.5mm adapter is awful
You need to jiggle it around before it actually works. And there’s no indication on the phone anywhere that headphones are plugged in, so reliably I will start playing music out of the phone speaker, and then keep jiggling the adapter until it plays through the earphones. This is simply not acceptable.
USB-C is far from ubiquitous
I bought a set of USB-C - USB-A cables, so that I can plug my phone into existing chargers, or my laptop, or whatever, to charge. Bundling one of these would have been nice.
Size
The phone is big. Bigger than I’d like. I can just about use it with one hand (I have pretty big hands). But most annoying, big without it being for the screen. About 1.3cm are added at both the top and bottom around the screen for… Black plastic. Seems annoying. I’d love my phone to just be 2.5cm shorter.
Sharing by Bluetooth
I miss Airdrop. I’ve tried sharing images over bluetooth from my phone several times, both to other phones and computers. It’s failed 100% of the time. I just email stuff now, but I’d rather not have to.
Wednesday, 6 January 2016
Ethical Banking and Saving
I generally seek to have a positive effect on the world where I can, particularly where it’s easy to achieve with only small changes in behaviour. I have a bank account. I have a savings account. Right now, the profits of these largely go to banks who, while serving a useful function, aren’t necessarily my dream beneficiaries.
I spent a while trying to find some good places to put my money, and figured I might as well write up my research in case it’s useful to anyone else. I was definitely trying to solve my own problems, so I should probably describe my aims: I live in the United Kingdom (in London). I have a current account, which I largely use for direct debits and to pay off a credit card with which I buy most things. It is always in credit. I have a few tens of thousands of pounds of savings. My life is fairly unstable, so I want relatively easy access to those savings (instant, or at most three months notice), in case I decide to move country, or buy a house, or start a company, or who knows what. I don’t particularly care about making the most interest I could make (I’m not a huge fan of making money from having money), but some would be nice, and more would be nicer. I don’t want an ISA. I travel a lot, and have a lot of foreign transactions. So practically, what I’m looking for is:
- A place to put tens of thousands of pounds of savings with at most 90 days of notice to withdraw (with probably some in instant access).
- A current account which handles me traveling well, offers a debit card, direct debits, and good online banking.
With that established, the next question is, what are my ethical aims? What are the available families of ethical ideologies? I have found only a fairly small handful of “ethical” banks (they’re not all banks, but I’m going to use that term broadly), and many fewer who offer current accounts. The broad families seem to be:
- Banks who only lend people/companies/groups who they judge to be making an actively positive influence in the world (Triodos Bank, Ecology Building Society, Charity Bank, Shared Interest). I call these “whitelisters” because they look for actively good things which they approve of, rather than invest anywhere that isn’t negative (“blacklisting”).
- Banks who lend to local communities, who don’t necessarily vet their borrowers for ethics, but whose target is mostly people or local enterprises rather than large companies, and whose scale means they probably work out ok (most of the building societies, credit unions, arguably Metro Bank).
- Religious banks (Al Rayan Bank, Reliance Bank).
What will I be doing?
For my current account, I really value convenience and customer service, so despite being far from the most ethical choice, I’ll be opening a current account with Metro Bank, with an aim to keep it pretty empty.
For instant access savings, I will be saving with Triodos and one of my local credit unions.
For term-notice savings, I will be saving with Ecology.
How did I get to that decision?
What follows is a brief narrative about each of the banks I investigated, starting with those who offer current accounts:
Reliance Bank
I did not investigate Reliance particularly heavily; they’re the bank of the Salvation Army, and I have problems with that particular organisation, so they were never really a contender for me. But some relevant information:
- They offer current accounts (with everything you’d expect), and savings accounts which don’t pay any meaningful interest.
- They blacklist certain trades (tobacco, alcohol, gambling, pornography, arms, the socially irresponsible, and those who don’t uphold the Universal Declaration of Human Rights).
- They pay their employees the living wage.
- They have only one branch, but have arrangements with other banks to allow you to use their branches for paying in.
- Foreign transactions have a flat £1.25 fee.
Al Rayan Bank (formerly: Islamic Bank of Britain)
Loosely speaking, the Qur’an forbids charging interest on loans and generally making money from money (and accordingly, making interest on savings). Al Rayan, accordingly, don’t formally pay interest, but instead share the profits of the bank with their members. It’s certainly a subtle dance. One thing that this means is that they don’t quote interest rates, they quote “expected profit rates” which may be missed.
- They offer current accounts and savings accounts. Their instant access savings don’t provide a meaningful expected profit, but if you’re willing to take a notice account or fixed-term account, they’re fairly competitive (ranging from 1% 60-day-notice to 2.88% 3-year-fixes).
- Their investments are all in property or low-risk commodities; they blacklist the standard “evil” industries, and require actual assets underlying their investments.
- They pay their employees the living wage.
- They have five branches and three agencies spread across particularly Islamic cities of England.
- There are limits on what countries accept their debit cards, what locations accept their debit cards (e.g. not petrol pumps), and they seem not to be part of the major ATM networks, so expect some fees. If you’re not near one of their branches, the accounts sound like hassle to operate.
Metro Bank
Metro Bank were founded in 2010 with an aim towards customer service. They do not brand themselves as particularly ethically focused (though they do talk about being community-focused, responsible, and charitable); their focus is definitely on profit via good customer service. In particular, they neither blacklist nor whitelist specific industries or groups. They don’t have an investment bank, they’re a small-ish straightforward deposit-taker-loan-lender retail group.
- They offer current accounts (optimising for ease-of-use) and savings returning decent rates (0.75% instant access, 1% 90 day term).
- European transactions charge no fee. Outside Europe, 1.9% is charged.
- Their branches (“stores”) are spread mostly across London and the South East, and are open seven days a week.
- They don’t have any particular ethical stance with their lending.
Building Societies
Building societies tend to offer decent rates of interest on savings, often times also offering current accounts. They tend to have a small number of branches in a local area, and to use their savings deposits exclusively to back mortgages (often only locally) though occasionally also for loans and/or insurance. If you’re looking for local community investment (where community here literally means “the people around you”), they’re not a bad choice. They’re formally owned and run by their members, and that gives some control over direction and aims. The largest few (Nationwide, Yorkshire, Coventry, and some others) have many branches across the nation (often times as the result of mergers of smaller societies), but quite quickly you get into the realms of them being very localised, and either only being accessible to those in the area, or possibly able to be operated by post or online.
Credit Unions
Credit unions operate fairly similarly to Building Societies; the notable differences are:
- They require members to have a common bond (typically an area in which they live or work).
- They are typically more strongly targeted to those of lesser means; they typically offer small loans rather than mortgages, and also many try to offer less obscene alternatives to increasingly prevalent payday loans.
- Along those lines, they are typically less choosy with to whom they will lend. For instance, most credit union websites explicitly talk about the benefits their members are probably on. They try to provide banking to all.
- They explicitly don’t seek to maximise profit, and they tend not to pay precise guaranteed interest; instead each year the members look at the profit made, and share it out as a dividend across the members.
- They typically only have one or two branches, and if they offer current accounts, tend to charge a fee for operating them.
- They frequently operate on much smaller scales than banks or building societies, and may not have full banking facilities. Some, for instance, manually process transactions (which may add a day or two to processing times), or require payments in to go to a shared account, with your account number as a reference, rather than actually allocating account numbers under a sort code.
They’re probably a more impactful place to put money than building societies, but they’re also likely to be a less convenient place to operate with; that said, they are frequently lauded for their customer service, and they definitely have very real impact in local communities.
Triodos Bank
Triodos Bank only lend money to people and organisations they view to be actively making a positive impact on society (whitelisting cultural, social, and environmental borrowers) rather than avoiding actively bad companies. Their definitions of positive are open to question (for instance, they happily fund homeopathy), but for the most part seems decent, and certainly better than most of the field.
- They currently only operate savings accounts, though say current accounts should be coming in late 2016.
- They pay their employees the living wage.
- They offer 1% interest for online accounts, or more (but not much more) for term accounts of at least a year.
- They are very transparent with their lending, actively listing all of their borrowers online.
- They have only two branches in the UK, though as a savings-only provider this is probably less of an issue than for current account providers.
- Their deposit protection is from the Netherlands, and so its limit is slightly subject to fluctuations on the GBP-EUR exchange rate.
One thing to note is that they also offer some ethical investment funds; note that they hold companies in these funds to a lower standard than those to whom they will lend, though still not a bad standard.
Ecology Building Society
The Ecology Building Society take deposits in savings accounts and lend only to support environmentally friendly, sustainable projects, particularly ecological new builds, energy-saving improvements, renovations, and preference to affordable housing. They also very consciously track and aim to improve their environmental footprint (e.g. publishing their “grams of CO2 per £ of new lending”).
- They offer only savings accounts, but pay a good rate on them (1% instant access, up to 1.6% with 90 days notice).
- Their banking facilities are somewhat limited; they operate by transferring money to their shared bank account with your account as a reference number; they have some online banking, but notice for notice accounts can only be given by post.
Charity Bank
Charity Bank only lend money to charities and social enterprises from savings deposits. They treat their employees and customers well, foregoing bonuses and hard sales targets in favour of a living wage. Their board are also unpaid volunteers. Their shareholders are all charities, trusts, or foundations, hopefully giving a good direction.
- They operate only savings accounts, paying around 0.6% for 33 day notice accounts. This number is noticeably lower than others available, as they favour cheaper rates to borrowing charities over higher interest to their savers.
- Their accounts are entirely operated by post.
Shared Interest
Shared Interest are a co-operative who provide unsecured loans to the fair trade industry; both to producers and buyers, in an attempt to cover the gaps that exist in the production/sales lifecycle. They are run very strongly as a co-operative, including a shadow-board of randomly selected members to oversee the board.
- They operate share accounts, rather than deposit accounts, so there is no protection scheme for your money. This is a theoretically risky account.
- Their interest rate is rather low, currently at 0.5%, and their roughly aim to target base rate minus 4%. They also offer an option to automatically donate this interest.
- Their board is currently 37.5% female, which is almost unheard of in the industry.
- They have a somewhat loose links to Christianity, which may be an issue for some.
So why my decisions?
For my current account choice (Metro Bank), I sided mostly with convenience. A bank which is open seven days a week, who charge no foreign transaction fees, and who seem to actually care about the experience of their customers is exciting. The alternatives here were: Reliance (except Salvation Army), Al Rayan (whose offering seems fraught with inconvenience, e.g. problems using cards in America or at fuel pumps), building societies (either not local to me, or not necessarily as convenient), or credit unions (for whom operating current accounts is actually quite expensive, and with whom a current account seems somewhat inconvenient). When Triodos offer a current account, this may change.
For savings, I found Shared Interest too risky for my profile. I found Charity Bank quite interesting, but a) I’d like to know more about their lending criteria, and b) I’m not entirely convinced that pushing loans on charities is the best way to support them. I find credit unions more compelling than building societies. And I find Triodos and Ecology both quite compelling, the former more so than the latter.
Please help me!
If there are any interesting offerings I’ve missed, please let me know! If you’d like to talk about these issues more, disagree with anything I’ve written, or generally have an interest, I’d love to hear from you too! Get in touch - dawagner AT gmail DOT com :)
Subscribe to:
Posts (Atom)