In the Swift Book Companion series, where I provide exercises for each chapter of Apple’s Swift book:
In the watchOS app development series:
In the Swift Book Companion series, where I provide exercises for each chapter of Apple’s Swift book:
In the watchOS app development series:
A couple of days ago I wrote about sonifications, the sound equivalent to visualizations. Even though they haven’t permeated business culture in the same way visualizations have, they are around us used in a folk way—meaning, designers use sound in their interfaces, but it isn’t systematic or directly supported in tools.
Even without that discipline, sonifications generally do a much better job of making themselves actionable. This is because that’s the main reason you use sound. You need to interrupt the user and get them to do something now. In my last essay on this topic, I gave a list of examples you encounter while driving: car honks, sirens, lane-drift warnings, etc—they all need immediate attention.
If we look at visualizations we encounter while driving, actionability is a core-driver. The gas light, tire-pressure warning, traffic lights all translate to simple actions. Even the check engine light wants you take an action (which is true even if you ignore it).
A lot of visualizations I see elsewhere aren’t that clear. It’s easy to make charts in most software that has data, and the easiest thing to do is to pick a chart template and populate it. It practically makes itself.
The problem is that many visualizations are communicating the list of data and not the action. Instead of random lines going up and down periodically, I want a green or red light*. And just like in my hometown of Queens, if I don’t pay attention to the light, a honk.
* Augmented for color-blindness and accessibility, of course
I cringe when I hear a GUI described as “ugly”. It’s not that I don’t see it too, but the feedback isn’t helpful. I can’t set the ugliness lower.
If something looks “ugly” to you, use that to guide your attention and analysis. What we often perceive as ugly is rooted in rules of perception and communication.
To give you an idea, considering just the visual look of a design (not its interactions), try to judge
Then, try to express you critique as: this “attribute of the design” doesn’t accomplish “this specific communication goal”
Here are some examples of what I mean:
Look at the visual variables: colors, values (lightness/darkness), sizes, positions, and shapes. Consider whitespace. Look at the relationships between the components.
Consider if there is too much or too little contrast. Is there harmony between things that are supposed to be the same? Do the most important things draw the eye? Can you scan?
These are just the surface level. Bad UIs are usually bad at a level deeper than that. But if it looks “ugly”, expressing that as contrast/harmony of visual variables is more actionable.
I am developing a series of articles based on my experience developing Sprint-o-Mat. The first one explains Why You Should Use SwiftUI for Developing Apple Watch Apps.
My Apple Watch app, Sprint-o-Mat, was originally an iPhone/Watch app combination because, at that time, a Watch app needed to be paired with an iPhone app.
Then, 3 months after I started, Apple changed everything about Apple Watch app development.
I’ll be covering Apple Watch app development in detail, with an emphasis on workout apps. Subscribe to get email notifications of new articles if you want to follow along.
I posted a new article to app-o-mat that walks you through recreating the Breathe animation using SwiftUI.
This is part of an ongoing series I’m writing about WatchKit development.
Senior Developers are expected to be more skilled in the technical aspects of software development. Just by having more years of experience they should be able to solve more problems, have more techniques, be faster, etc.
But, this alone is not enough to make them “senior” in my view. They will be more valuable than a junior developer doing tasks, but you can’t scale a team with a group of expert task doers.
The biggest differentiator between a junior developer and a more senior one is in the scope of their thinking and planning.
To keep it simple, imagine four levels of engineer (Jr, Dev, Sr, Lead). Here are some of the differences aside from programming skill. This distinction has nothing to do with people management—none of these levels have management responsibilities.
There is more to it than this, but the essence is increasing scope of time, planning, and coordination.
Another way to think of it is in what their goals are:
To be fair, everyone should be working on the mission of the company. The difference is how they think about the work they are doing and how they evaluate success.
On my first day at Trello, my peer mentor showed me two things. One of them ended up being the topic of my talk on Reactive Programming. The second thing he told me was, on our team, PR’s should tell a story.
Then we pair constructed a PR. To be clear, he was already in a local branch, and the code was already written and committed.
He showed me how he used git reset and git rebase to rewrite the commits. He explained that he was rebuilding the commits to make the PR easy to review. He constructed each commit to be atomic—to do a single coherent thing.
This was the PR style for our team for the whole time I worked there. The goal of a PR was to make it easy to review, and we expected reviewers to open each commit in a tab and review them one-by-one. We considered it acceptable to decline a PR if it was too big or hard to review (in practice, this happened very infrequently).
Other practices:
These practices helped us, but the important part is our team mindset that PRs were constructed to be easy to review.
The Liskov Substitution Principle is an Object-Oriented class design guideline that says that a sub-class should be substitutable for a super-class and that clients to the super-class should not be impacted.
You achieve this by specifying a contract for each public method of a class.
First, you specify a pre-condition/requirement.
If the caller meets the requirements, then the method makes a promise of a post-condition and result.
A sub-class is substitutable if it makes the same promises under the same requirements. It is also substitutable if it can make the same promise with fewer requirements. And, finally, it’s still substitutable if it makes more promises.
So, sub-classes can require less and promise more than the specification of their super-classes. But, they can neither require more nor promise less.
Some OO languages, like Eiffel, have ways of encoding the contract, but in Swift and many other languages, this is something usually stated in documentation.
But, substitution is not just an OO principle, or at least, I don’t only apply it to super/sub class relationships. I think it should be applied to versioning of any public library of any kind of code (OO, functional, whatever). To do this, think of vNext as a subclass of vCurrent.
So, vNext can require less and promise more. It can’t:
Unfortunately, many languages would think of some acceptable changes as a compile-time breaking change. For example, in Swift if a method returned T? and you changed it to return T, then callers that used guards would not compile. Strictly speaking, T is always substitutable for T?, but you should not do this change.
This is not how many library authors think, Instead, I think we’ve been corrupted by semantic versioning and the idea of acceptable breaking changes. Under substitutable versioning, there is no such thing as a breaking change.
Under semantic versioning (major.minor.patch), most library providers only think of patch version increases as being substitutable and for sure major version increases are not. I would say in practice, minor version increases are sometimes breaking.
In a fully substitutable versioning system, this would never be the case. vNext would always be substitutable for vCurrent. This means that:
To be clear, if clients write to implementations and not specifications, they might break with future versions, so documentation needs to clearly explain what is required and promised. The actual behavior should not be confused with the contract.
A common example of this is relying on buggy behavior. If I call a method and it has some bug, I might write code to work-around that bug. If a future version fixes the bug and my software breaks because of my work-around, that’s still considered a substitutable change as the bug was not a promised behavior.
In a talk on clojure specs, Rich Hickey called this concept accretion and railed against breaking change. I know that semantic versioning is too entrenched right now to change, but something like what Rich is describing would do a lot to relieve dependency hell.
To help new Swift learners, I’ve been going through Apple’s Swift book chapter by chapter and writing a companion article that gives you a simple exercise to do to make sure you understand the content of the chapter before moving on.
The whole series is available here.
The latest chapter is a companion to the Subscripts chapter.
I started a podcast about a week ago and the first episode was an exercise that helped me overcome writer’s block. In the episode I said that I don’t get “coder’s block”.
This is more or less true, but I want to elaborate. I don’t mean that I can instantly solve any bug or program anything I want at will. I mean that I can make progress and do something.
When I have a problem I need to solve and literally have no idea what to do next, here are a few things that help.
And, sometimes it’s right to put a hard problem on the back burner and come back to it later.