Manish Goregaokar: Wrapper Types in Rust: Choosing Your Guarantees |
In my previous post I talked a bit about why the RWlock pattern is important for accessing data, which is why Rust enforces this pattern either at compile time or runtime depending on the abstractions used.
It occurred to me that there are many such abstractions in Rust, each with their unique guarantees. The programmer once again has the choice between runtime and compile time enforcement. It occurred to me that this plethora of “wrapper types”1 could be daunting to newcomers; in this post I intend to give a thorough explanation of what some prominent ones do and when they should be used.
I’m assuming the reader knows about ownership and borrowing in Rust. Nevertheless, I will attempt to keep the majority of this post accessible to those not yet familiar with these concepts. Aside from the two links into the book above, these two blog posts cover the topic in depth.
Box
Box
is an “owned pointer” or a “box”. While it can hand out borrowed references to the data, it is the only
owner of the data. In particular, when something like the following occurs:
let x = Box::new(1);
let y = x;
// x no longer accessible here
Here, the box was moved into y
. As x
no longer owns it,
the compiler will no longer allow the programmer to use x
after this. A box
can similarly be moved out of a function by returning, and when a
box (one which hasn’t been moved) goes out of scope, destructors are run, deallocating
the inner data.
This abstraction is a low cost abstraction for dynamic allocation. If you want to allocate some memory on the heap and safely pass a pointer to that memory around, this is ideal. Note that you will only be allowed to share borrowed references to this by the regular borrowing rules, checked at compile time.
Copy
Move/ownership semantics are not special to Box
; it is a feature of all types which are not Copy
.
A Copy
type is one where all the data it logically encompasses (usually, owns) is part of its stack
representation2.
Most types containing pointers to other data are not Copy
, since there is additional data
elsewhere, and simply copying the stack representation may accidentally share ownership of that data
in an unsafe manner.
Types like Vec
and String
which also have data on the heap are also not Copy
. Types
like the integer/boolean types are Copy
&T
and raw pointers are Copy
. Even though they do point
to further data, they do not “own” that data. Whereas Box
can be thought of as
“some data which happens to be dynamically allocated”, &T
is thought of as “a borrowing reference
to some data”. Even though both are pointers, only the first is considered to be “data”. Hence,
a copy of the first should involve a copy of the data (which is not part of its stack representation),
but a copy of the second only needs a copy of the reference. &mut T
is not Copy
because mutable aliases
cannot be shared, and &mut T
“owns” the data it points to somewhat since it can mutate.
Practically speaking, a type can be Copy
if a copy of its stack representation doesn’t violate
memory safety.
&T
and &mut T
These are immutable and mutable references respectively. They follow the “read-write lock” pattern described in my previous post, such that one may either have only one mutable reference to some data, or any number of immutable ones, but not both. This guarantee is enforced at compile time, and has no visible cost at runtime. In most cases such pointers suffice for sharing cheap references between sections of code.
These pointers cannot be copied in such a way that they outlive the lifetime associated with them.
*const T
and *mut T
These are C-like raw pointers with no lifetime or ownership attached to them. They just point to some location
in memory with no other restrictions. The only guarantee that these provide is that they cannot be dereferenced
except in code marked unsafe
.
These are useful when building safe, low cost abstractions like Vec
, but should be avoided in safe code.
Rc
This is the first wrapper we will cover that has a runtime cost.
Rc
is a reference counted pointer. In other words, this lets us have multiple “owning” pointers
to the same data, and the data will be freed (destructors will be run) when all pointers are out of scope.
Internally, it contains a shared “reference count”, which is incremented each time the Rc
is cloned, and decremented
each time one of the Rc
s goes out of scope. The main responsibility of Rc
is to ensure that destructors are called
for shared data.
The internal data here is immutable, and if a cycle of references is created, the data will be leaked. If we want data that doesn’t leak when there are cycles, we need a garbage collector. I do not know of any existing GCs in Rust, but I am working on one with Michael Layzell and there’s another cycle collecting one being written by Nick Fitzgerald.
The main guarantee provided here is that the data will not be destroyed until all references to it are out of scope.
This should be used when you wish to dynamically allocate and share some data (read-only) between various portions
of your program, where it is not certain which portion will finish using the pointer last. It’s a viable alternative
to &T
when &T
is either impossible to statically check for correctness, or creates extremely unergonomic code where
the programmer does not wish to spend the development cost of working with.
This pointer is not thread safe, and Rust will not let it be sent or shared with other threads. This lets one avoid the cost of atomics in situations where they are unnecessary.
There is a sister smart pointer to this one, Weak
. This is a non-owning, but also non-borrowed, smart pointer.
It is also similar to &T
, but it is not restricted in lifetime — a Weak
can be held on to forever. However,
it is possible that an attempt to access the inner data may fail and return None
, since this can outlive the owned
Rc
s. This is useful for when one wants cyclic data structures and other things.
As far as memory goes, Rc
is a single allocation, though it will allocate two extra words as compared to
a regular Box
(for “strong” and “weak” refcounts).
Rc
has the computational cost of incrementing/decrementing the refcount whenever it is cloned or goes out of
scope respectively. Note that a clone will not do a deep copy, rather it will simply increment the inner reference count
and return a copy of the Rc
“Cells” provide interior mutability. In other words, they contain data which can be manipulated even
if the type cannot be obtained in a mutable form (for example, when it is behind an &
-ptr or Rc
).
The documentation for the cell
module has a pretty good explanation for these.
These types are generally found in struct fields, but they may be found elsewhere too.
Cell
Cell
is a type that provides zero-cost interior mutability, but only for Copy
types.
Since the compiler knows that all the data owned by the contained value is on the stack, there’s
no worry of leaking any data behind references (or worse!) by simply replacing the data.
It is still possible to violate your own invariants using this wrapper, so be careful when
using it. If a field is wrapped in Cell
, it’s a nice indicator that the chunk of data is mutable
and may not stay the same between the time you first read it and when you intend to use it.
let x = Cell::new(1);
let y = &x;
let z = &x;
x.set(2);
y.set(3);
z.set(4);
println!("{}", x.get());
Note that here we were able to mutate the same value from various immutable references.
This has the same runtime cost as the following:
let mut x = 1;
let y = &mut x;
let z = &mut x;
x = 2;
*y = 3;
*z = 4;
println!("{}", x;
but it has the added benefit of actually compiling successfully.
This relaxes the “no aliasing with mutability” restriction in places where it’s
unnecessary. However, this also relaxes the guarantees that the restriction provides;
so if one’s invariants depend on data stored within Cell
, one should be careful.
This is useful for mutating primitives and other Copy
types when there is no easy way of
doing it in line with the static rules of &
and &mut
.
G'abor Lehel summed up the guarantees provided by Cell
in a rather succinct manner:
The basic guarantee we need to ensure is that interior references can’t be invalidated (left dangling) by mutation of the outer structure. (Think about references to the interiors of types like
Option
,Box
,Vec
, etc.)&
,&mut
, and Cell each make a different tradeoff here.&
allows shared interior references but forbids mutation;&mut
allows mutation xor interior references but not sharing;Cell
allows shared mutability but not interior references.
[because Cell
operates by copying, it can’t create interior references]
This comment by Eddy also touches on the guarantees of Cell
and the alternatives
There is no runtime cost to using Cell
, however if one is using it
to wrap larger (Copy
) structs, it might be worthwhile to instead wrap individual
fields in Cell
since each write is a full copy of the struct.
RefCell
RefCell
also provides interior mutability, but isn’t restricted to Copy
types.
Instead, it has a runtime cost. RefCell
enforces the RWLock pattern at runtime (it’s like a single-threaded mutex),
unlike &T
/&mut T
which do so at compile time. This is done by the borrow()
and
borrow_mut()
functions, which modify an internal reference count and return smart pointers
which can be dereferenced immutably and mutably respectively. The refcount is restored
when the smart pointers go out of scope. With this system, we can dynamically ensure that
there are never any other borrows active when a mutable borrow is active. If the programmer
attempts to make such a borrow, the thread will panic.
let x = RefCell::new(vec![1,2,3,4]);
{
println!("{:?}", *x.borrow())
}
{
let my_ref = x.borrow_mut();
my_ref.push(1);
}
Similar to Cell
, this is mainly useful for situations where it’s hard or impossible to satisfy the
borrow checker. Generally one knows that such mutations won’t happen in a nested form, but it’s good
to check.
For large, complicated programs, it becomes useful to put some things in RefCell
s to
make things simpler. For example, a lot of the maps in the ctxt
struct in the rust compiler
internals are inside this wrapper. These are only modified once (during creation, which is not
right after initialization) or a couple of times in well-separated places. However, since this struct is
pervasively used everywhere, juggling mutable and immutable pointers would be hard (perhaps impossible)
and probably form a soup of &
-ptrs which would be hard to extend. On the other hand, the RefCell
provides a cheap (not zero-cost) way of safely accessing these. In the future, if someone adds some code
that attempts to modify the cell when it’s already borrowed, it will cause a (usually deterministic) panic
which can be traced back to the offending borrow.
Similarly, in Servo’s DOM we have a lot of mutation, most of which is local to a DOM type, but
some of which crisscrosses the DOM and modifies various things. Using RefCell
and Cell
to guard
all mutation lets us avoid worrying about mutability everywhere, and it simultaneously
highlights the places where mutation is actually happening.
Note that RefCell
should be avoided if a mostly simple solution is possible with &
pointers.
RefCell
relaxes the static restrictions preventing aliased mutation, and
replaces them with dynamic ones. As such the guarantees have not changed.
RefCell
does not allocate, but it contains an additional “borrow state”
indicator (one word in size) along with the data.
At runtime each borrow causes a modification/check of the refcount.
Many of the types above cannot be used in a threadsafe manner. Particularly, Rc
and RefCell
,
which both use non-atomic ref counts, cannot be used this way. This makes them cheaper to use, but one
needs thread safe versions of these too. They exist, in the form of Arc
and Mutex
/RWLock
Note that the non-threadsafe types cannot be sent between threads, and this is checked at compile time. I’ll touch on how this is done in a later blog post.
There are many useful wrappers for concurrent programming in the sync module, but I’m only going to cover the major ones.
Arc
Arc
is just a version of Rc
that uses an atomic reference count (hence, “Arc”). This can be sent
freely between threads.
C++’s shared_ptr
is similar to Arc
, however in C++s case the inner data is always mutable. For semantics
similar to that from C++, we should use Arc>
, Arc>
, or Arc>
3 (UnsafeCell
is a cell type that can be used to hold any data and has no runtime cost, but accessing it requires unsafe
blocks).
The last one should only be used if one is certain that the usage won’t cause any memory unsafety. Remember that
writing to a struct is not an atomic operation, and many functions like vec.push()
can reallocate internally
and cause unsafe behavior (so even monotonicity may not be enough to justify UnsafeCell
)
Like Rc
, this provides the (thread safe) guarantee that the destructor for the internal data
will be run when the last Arc
goes out of scope (barring any cycles).
This has the added cost of using atomics for changing the refcount (which will happen whenever it is cloned
or goes out of scope). When sharing data from an Arc
in
a single thread, it is preferable to share &
pointers whenever possible.
Mutex
and RwLock
Mutex
and RwLock
provide mutual-exclusion via RAII guards. For both of these, the
mutex is opaque until one calls lock()
on it, at which point the thread will
block until a lock can be acquired, and then a guard will be returned. This guard
can be used to access the inner data (mutably), and the lock will be released when the
guard goes out of scope.
{
let guard = mutex.lock();
// guard dereferences mutably to the inner type
*guard += 1;
} // lock released when destructor runs
RwLock
has the added benefit of being efficient for multiple reads. It is always
safe to have multiple readers to shared data as long as there are no writers; and RwLock
lets readers acquire a “read lock”. Such locks can be acquired concurrently and are kept track of
via a reference count. Writers must obtain a “write lock” which can only be obtained when all readers
have gone out of scope.
Both of these provide safe shared mutability across threads, however they are prone to deadlocks. Some level of additional protocol safety can be obtained via the type system. An example of this is rust-sessions, an experimental library which uses session types for protocol safety.
These use internal atomic-like types to maintain the locks, and these are similar pretty costly (they can block all memory reads across processors till they’re done). Waiting on these locks can also be slow when there’s a lot of concurrent access happening.
A common gripe when reading Rust code is with stuff like Rc>>
and more complicated
compositions of such types.
Usually, it’s a case of composing together the guarantees that one needs, without paying for stuff that is unnecessary.
For example, Rc>
is one such composition. Rc
itself can’t be dereferenced mutably;
because Rc
provides sharing and shared mutability isn’t good, so we put RefCell
inside to get
dynamically verified shared mutability. Now we have shared mutable data, but it’s shared in a way
that there can only be one mutator (and no readers) or multiple readers.
Now, we can take this a step further, and have Rc>>
or Rc>>
.
These are both shareable, mutable vectors, but they’re not the same.
With the former, the RefCell
is wrapping the Vec
, so the Vec
in its entirety is mutable.
At the same time, there can only be one mutable borrow of the whole Vec
at a given time. This
means that your code cannot simultaneously work on different elements of the vector from different
Rc
handles. However, we are able to push and pop from the Vec
at will. This is similar to an &mut Vec
with the borrow checking done at runtime.
With the latter, the borrowing is of individual elements, but the overall vector is immutable.
Thus, we can independently borrow separate elements, but we cannot push or pop from the vector.
This is similar to an &mut [T]
4, but, again, the borrow checking is at runtime.
In concurrent programs, we have a similar situation with Arc>
, which provides shared
mutability and ownership.
When reading code that uses these, go in step by step and look at the guarantees/costs provided.
When choosing a composed type, we must do the reverse; figure out which guarantees we want, and at which
point of the composition we need them. For example, if there is a choice between Vec>
and RefCell>
,
we should figure out the tradeoffs as done above and pick one.
http://manishearth.github.io/blog/2015/05/27/wrapper-types-in-rust-choosing-your-guarantees/
|
Mozilla Addons Blog: Update on Extension Signing and New Developer Agreement |
If you have an active extension listing on AMO you probably got a message from us already, explaining how we will automatically sign your add-on and provide it to your users via automatic updates. The automatic signing process will run this week, in batches, and we will notify you when your add-on is signed. Please take some time to test the signed version in the current release version of Firefox and either Developer Edition or Nightly (where Firefox already warns about unsigned extensions).
If you’re unfamiliar with extension signing, please read the original announcement for context.
Next week, we will activate two new features on AMO: signing of new add-on versions after they are reviewed, and add-on submission for developers who wish to have their add-ons signed but don’t want them listed on AMO. We will post another update once this happens. When this is done, all extension developers will be able to have their extensions signed, with enough time to update their users before signing becomes a requirement in release versions of Firefox.
Since we will be signing add-ons that won’t be listed on AMO, we have updated the Add-on Distribution Developer Agreement to cover the new ways in which we will handle add-ons. This document hadn’t been touched for years, so we took our time and significantly updated its contents to reflect how we do things now. Hopefully it is also easier to read than its previous version.
Note that the new agreement will go into effect on June 1st. The version that is displayed on AMO when you submit a new add-on will be updated then, and all active developers on AMO will be notified about it.
If you want to stay up to date with changes related to extension signing, you can follow this blog or check in regularly to the wiki page, where I update the timeline information as it becomes clearer.
https://blog.mozilla.org/addons/2015/05/27/update-signing-new-developer-agreement/
|
Air Mozilla: Bugzilla Development Meeting |
Help define, plan, design, and implement Bugzilla's future!
https://air.mozilla.org/bugzilla-development-meeting-20150527/
|
Gervase Markham: The Jeeves Test |
What is a browser for? What should it do, or not do? What should it be?
People within the Mozilla project have been recently discussing the user value of some new features in Firefox. I think a person’s view of questions of this nature will depend on their view of the role of the browser. One option is the “featureless window on the web” view – the browser is nothing, the site is everything. But as one participant said, this leads to all the value-add and features being provided by the sites, which is not a recipe for user control, or for using the browser to advance the Mozilla mission.
I think the best vision for Firefox is as your “Internet butler” – quiet and refined, highly capable, provides what you need even before you know you need it, who gently guides you out of trouble but generally does his thing without you needing to think about him or provide explicit direction or management.
Bertie using an early voice interface prototype
So I’d like to propose the “Jeeves Test” for evaluating feature proposals for Firefox. It works like this: imagine Bertie Wooster, relaxing in an armchair in his apartment, with a cigarette, a gin and tonic, and a tablet computer. Then take the user value proposition of an idea, write it in appropriately deferential language, and see if you can imagine Jeeves whispering it into his ear. If you can’t, perhaps it’s not something we want to do.
To make that a bit more concrete, here are some examples of things that might pass: “Here’s an English translation of this Serbian page, sir”, or “For your safety, sir, access to this malware page has been blocked”. And here are some which might not: “For your convenience, sir, I’ve exempted aol.com from your popup blocker”, or “You’ll be pleased to find, sir, that the user interface has been substantially rearranged”.
There may be occasions where we’d want to do something which doesn’t obviously pass the Jeeves Test, if the effects on the broader web ecosystem of making the change are significantly positive. Some of the things we do to improve web security but which have a short-term compatibility impact might fall into that category. “Let me ensure this site doesn’t load for you, sir” generally doesn’t go down well, after all. But in those cases, that longer-term or broader value has to be clearly articulated – before we make the change – if we are to avoid an exasperated “Dash it, Jeeves… why?” from our userbase.
http://feedproxy.google.com/~r/HackingForChrist/~3/uy-LPl8GZAk/
|
Mozilla Release Management Team: Firefox 38.0.5 rc to rc2 |
A small update for next week release. We took a patch to fix a JS top crash and 3 changes to fix an important regression in WebRTC.
Extension | Occurrences |
cpp | 5 |
xml | 1 |
txt | 1 |
mn | 1 |
html | 1 |
h | 1 |
Module | Occurrences |
js | 5 |
mobile | 1 |
media | 1 |
dom | 1 |
config | 1 |
browser | 1 |
List of changesets:
tbirdbld | Automated checkin: version bump for thunderbird 38.0b6 release. DONTBUILD CLOSED TREE a=release - 7eb2d1522ac2 |
Margaret Leibovic | Bug 1166392 - Include about:reader strings on Android. r=mfinkle, a=sledru - a468d1edeac8 |
Tooru Fujisawa | Bug 1159973 - Abort parsing when TokenStream::SourceCoords hits OOM. r=jorendorff, a=sylvestre - 414d430012ee |
Paul Adenot | Bug 1166183 - Back out the direct listener removal landed by mistake in Bug 1141781. r=jesup, a=sledru - 9525d8723413 |
Paul Adenot | Bug 1166183 - Work around Bug 934512 in track_peerConnection_replaceTrack.html. r=pehrson, a=sledru - 6ee39f753d19 |
Andreas Pehrson | Bug 1166183 - Reset PipelineListener's flag after ReplaceTrack(). r=bwc, a=sledru - 19b9ffda6e2f |
http://release.mozilla.org/statistics/38_0/2015/05/27/fx-38.0.5rcto-rc2.html
|
Byron Jones: happy bmo push day! |
the following changes have been pushed to bugzilla.mozilla.org:
discuss these changes on mozilla.tools.bmo.
https://globau.wordpress.com/2015/05/27/happy-bmo-push-day-143/
|
Daniel Stenberg: picturing curl’s future |
There will be more stuff over time in the cURL project. Exactly which stuff and how long time it takes for everything, we don’t know. It depends largely on who works on what and how much time said persons can spend on implementing the stuff they work on…
I suspect we might be able to do things slightly faster over time, which is why the red arrow isn’t just a straight line.
I drew this little picture inspired from discussions with friends after a talk I did about curl and how development works in an open source project such as this. We know we will work on things that will improve the products but we don’t see exactly what very far in advance. I tweeted this picture a few days ago, and it turned out very popular.
http://daniel.haxx.se/blog/2015/05/26/picturing-curls-future/
|
Doug Belshaw: Web Literacy: what happens beyond peak centralisation and software with shareholders? |
There’s no TIDE podcast this week, so I thought I’d record a blog post today. Here’s the abstract:
We’re at peak centralisation of our data in online services, with data as the new oil. It’s a time of ‘frictionless sharing’, but also a time when we’re increasingly having decisions made on our behalf by algorithms. Education is now subject to a land grab by ‘software with shareholders’ looking to profit from collecting, mining, packaging, and selling learner data. This article explores some of the issues at stake, as well as pointing towards the seeds of a potential solution.
The Code Acts in Education blog I mention in the introduction to this piece can be found here and Ben Williamson is @BenPatrickWill on Twitter.
Comments (once you’ve listened!) much appreciated. I’ve still got time to re-work this…
(no audio? click here!)
Belshaw, D.A.J. (2014a). Software with shareholders (or, the menace of private public spaces). Doug Belshaw’s blog. 23 April 2014. http://dougbelshaw.com/blog/2014/04/23/software-with-shareholders.
Belshaw, D.A.J. (2014b). Curate or Be Curated: Why Our Information Environment is Crucial to a Flourishing Democracy, Civil Society. DMLcentral. 23 October 2014. http://dmlcentral.net/blog/doug-belshaw/curate-or-be-curated-why-our-information-environment-crucial-flourishing-democracy.
Dixon-Thayer, D. (2015). Mozilla View on Zero-Rating. Open Policy & Advocacy Blog. Mozilla. 5 May 2015. https://blog.mozilla.org/netpolicy/2015/05/05/mozilla-view-on-zero-rating.
Flew, T. (2008). New Media: An Introduction (3rd ed.). Melbourne: Oxford University Press.
Gillula, J. & Malcolm, J. (2015). Internet.org Is Not Neutral, Not Secure, and Not the Internet. Deeplinks Blog. Electronic Frontier Foundation. 18 May 2015. https://www.eff.org/deeplinks/2015/05/internetorg-not-neutral-not-secure-and-not-internet.
Kramer, A.D.I., Guillory, J.E., Hancock, J.T. (2014) Experimental evidence of massive-scale emotional contagion through social networks. Proceedings of the National Academy of Sciences of the United Sates of America. 111(24).
McNeal, G.S. (2014). Facebook Manipulated User News Feeds To Create Emotional Responses. Forbes. 28 June 2014. http://www.forbes.com/sites/gregorymcneal/2014/06/28/facebook-manipulated-user-news-feeds-to-create-emotional-contagion
Mozilla. (2015). Web Literacy Map v1.1. https://teach.mozilla.org/teach-like-mozilla/web-literacy
Thorp, J. (2012). Big Data Is Not the New Oil. Harvard Business Review. 30 November 2012. https://hbr.org/2012/11/data-humans-and-the-new-oil.
Image CC BY-NC Graham Chastney
|
Air Mozilla: SpiderMonkey garbage collection update |
An overview of the progress we've made in the last two years development on the SpiderMonkey GC implementing generational collection and starting work on compacting.
https://air.mozilla.org/spidermonkey-garbage-collection-update/
|
Chris AtLee: RelEng 2015 (part 1) |
Last week, I had the opportunity to attend RelEng 2015 - the 3rd International Workshop of Release Engineering. This was a fantastic conference, and I came away with lots of new ideas for things to try here at Mozilla.
I'd like to share some of my thoughts and notes I took about some of the sessions. As of yet, the speakers' slides aren't collected or linked to from the conference website. Hopefully they'll get them up soon! The program and abstracts are available here.
For your sake (and mine!) I've split up my notes into a few separate posts. This post covers the introduction and keynote.
"Continuous deployment" of web applications is basically a solved problem today. What remains is for organizations to adopt best practices. Mobile/desktop applications remain a challenge.
Cisco relies heavily on collecting and analyzing metrics to inform their approach to software development. Statistically speaking, quality is the best driver of customer satisfaction. There are many aspects to product quality, but new lines of code introduced per release gives a good predictor of how many new bugs will be introduced. It's always challenging to find enough resources to focus on software quality; being able to correlate quality to customer satisfaction (and therefore market share, $$$) is one technique for getting organizational support for shipping high quality software. Common release criteria such as bugs found during testing, or bug fix rate, are used to inform stakeholders as to the quality of the release.
Bram Adams and Foutse Khomh kicked things off with an overview of "continuous deployment" over the last 5 years. Back in 2009 we were already talking about systems where pushing to version control would trigger tens of thousands of tests, and do canary deployments up to 50 times a day.
Today we see companies like Facebook demonstrating that continuous deployment of web applications is basically a solved problem. Many organizations are still trying to implement these techniques. Mobile [and desktop!] applications still present a challenge.
Pete Rotella from Cisco discussed how he and his team measured and predicted release quality for various projects at Cisco. His team is quite focused on data and analytics.
Cisco has relatively long release cycles compared to what we at Mozilla are used to now. They release 2-3 times per year, with each release representing approximately 500kloc of new code. Their customers really like predictable release cycles, and also don't like releases that are too frequent. Many of their customers have their own testing / validation cycles for releases, and so are only willing to update for something they deem critical.
Pete described how he thought software projects had four degrees of freedom in which to operate, and how quality ends up being the one sacrificed most often in order to compensate for constraints in the others:
resources (people / money): It's generally hard to hire more people or find room in the budget to meet the increasing demands of customers. You also run into the mythical man month problem by trying to throw more people at a problem.
schedule (time): Having standard release cycles means organizations don't usually have a lot of room to push out the schedule so that features can be completed properly.
I feel that at Mozilla, the rapid release cycle has helped us out to some extent here. The theory is that if your feature isn't ready for the current version, it can wait for the next release which is only 6 weeks behind. However, I do worry that we have too many features trying to get finished off in aurora or even in beta.
content (features): Another way to get more room to operate is to cut features. However, it's generally hard to cut content or features, because those are what customers are most interested in.
quality: Pete believes this is where most organizations steal resources for to make up for people/schedule/content constraints. It's a poor long-term play, and despite "quality is our top priority" being the Official Party Line, most organizations don't invest enough here. What's working against quality?
Why should we focus on quality? Pete's metrics show that it's the strongest driver of customer satisfaction. Your product's customer satisfaction needs to be more than 4.3/5 to get more than marginal market share.
How can RelEng improve metrics?
Interestingly, handling the backlog of bugs has minimal impact on customer satisfaction. In addition, there's substantial risk introduced whenever bugs are fixed late in a release cycle. There's an exponential relationship between new lines of code added and # of defects introduced, and therefore customer satisfaction.
Another good indicator of customer satisfaction is the number of "Customer found defects" - i.e. the number of bugs found and reported by their customers vs. bugs found internally.
Pete's data shows that if they can find more than 80% of the bugs in a release prior to it being shipped, then the remaining bugs are very unlikely to impact customers. He uses lines of code added for previous releases, and historical bug counts per version to estimate number of bugs introduced in the current version given the new lines of code added. This 80% figure represents one of their "Release Criteria". If less than 80% of predicted bugs have been found, then the release is considered risky.
Another "Release Criteria" Pete discussed was the weekly rate of fixing bugs. Data shows that good quality releases have the weekly bug fix rate drop to 43% of the maximum rate at the end of the testing cycle. This data demonstrates that changes late in the cycle have a negative impact on software quality. You really want to be fixing fewer and fewer bugs as you get closer to release.
I really enjoyed Pete's talk! There are definitely a lot of things to think about, and how we might apply them at Mozilla.
|
Andrea Marchesini: Console API in workers and DevTools |
As web developer, debugging Service Workers code can be a complex process. For this reason, we are putting extra effort in improving debugging tools for Firefox. This blog post is focusing on our developments on the Console API and how it can be used in any kind of Worker and shown up in the DevTools WebConsole.
As you probably know, since February 2014 Firefox supports the Console API in Workers (bug 965860). In so doing, we have recently extended the support to different kind of Workers (January 2015 - bug 1058644). However, any use of the Console API in those Workers has not been shown yet into the DevTools WebConsole.
I am pleased to say that, in the nightly, and soon in release builds, you are now able to choose and see the log messages from Shared Workers, Service Workers and Addon-on Workers, which enable them from the ‘logging’ menu. Here a screenshot:
This works with remote debugging too! Happy debugging!
|
Air Mozilla: Reaching more users through better accessibility |
Using Firefox OS to test your apps for better accessibility and usability of your mobile web application
https://air.mozilla.org/reaching-more-users-through-better-accessibility/
|
Air Mozilla: Privacy features for Firefox for Android |
Supporting privacy on the mobile web with built-in features and add-ons
https://air.mozilla.org/privacy-features-for-firefox-for-android-2/
|
Air Mozilla: Martes mozilleros |
Reuni'on bi-semanal para hablar sobre el estado de Mozilla, la comunidad y sus proyectos. Bi-weekly meeting to talk (in Spanish) about Mozilla status, community and...
|
Air Mozilla: Servo (the parallel web browser) and YOU! |
A beginner's guide to contributing to Servo
https://air.mozilla.org/servo-the-parallel-web-browser-and-you/
|
Daniel Stenberg: 2015 curl user poll analysis |
My full 30 page document with all details and analyses of the curl user poll 2015 is now available. It shows details of all the questions, most of them with a comparison with last year’s survey. The write-ins are also full of good advice, wisdom and some signs of ignorance or unawareness.
I hope all curl hackers and others generally interested in the project can use my “report” to learn something about our users and our user’s view of the project and our products.
Let’s use this to guide us going forward.
http://daniel.haxx.se/blog/2015/05/26/2015-curl-user-poll-analysis/
|
Byron Jones: happy bmo push day! |
the following changes have been pushed to bugzilla.mozilla.org:
discuss these changes on mozilla.tools.bmo.
https://globau.wordpress.com/2015/05/26/happy-bmo-push-day-142/
|
David Ascher: Not Technologism, Alchemy. |
A couple of years ago, I was part of a panel with the remarkable Evgeny Morozov, at an event hosted by the Museum of Vancouver. The event wasn’t remarkable, except that I ended up in a somewhat high-energy debate with Mr. Morozov, without particularly understanding why. He ascribed to me beliefs I didn’t hold, which made a rigorous intellectual argument (which I generally enjoy) quite elusive and baffling.
It took a follow-up discussion with my political theorist brother to elucidate it. In particular, he helped me realize that while for decades I’ve described myself as a technologist, depending on your definition of that word, I was misrepresenting myself. Starting with my first job in my mid teens, my career (modulo an academic side-trip) has essentially been to bring technological skills to bear on a situation. Using the word technologist to describe myself felt right, without much analysis. As my brother pointed out, using an academic lexicon, the word technologist can be used to mean “someone who thinks technology is the answer”. Using that definition, capital is to capitalist as technology is to technologist. Once I understood that, I realized why Mr. Morozov was arguing with me. He thought I believed in technologism, much like the way the New Yorker describes Marc Andreesen (I’m no Andreesen in many ways, but I do think he’d have been a better foil for Morozov). It also made me realize that he either didn’t understand what Mozilla is trying to do, or didn’t believe me/us.
Using that definition, I am not a technologist any more than I am a capitalist or a regulator[ist?]. I resist absolutes, as it seems to me blatantly obvious (and probably boring) that except for rhetorical/marketing purposes (such as Morozov’s), the choices which one should make when building or changing a system, at every scale from the individual to the society, must be thoughtfully balanced. This balance is hard to articulate and even harder to maintain, in a political environment which blurs subtlety and a network environment which amplifies differences.
It is in this balance that lies evolutionary progress. I have been re-re-watching The Wire, thinking about Baltimore. In season 3, one of the district commanders, sick of the status quo, tries to create a “free zone” for unimpeded drug dealing, an Amsterdam-in-Baltimore, in order to draw many of the associated social ills away from the rest of the district. In doing this, he uses his authority (and fearlessness, thanks to his impending retirement), and combines management techniques, marketing, and positive and negative incentives, to try fix a systemic social problem. I want more stories like that (especially less fictional ones).
I don’t believe that technology is “the answer,” just like police vans aren’t the answer. That said, ignoring the impact that technology can have on societal (or business!) challenges is just as silly as saying that technology holds the answer. Yes, technology choices are often political, and that’s just fine, especially if we invite non-techies to help make those political decisions. When it comes to driving behavioral change, tech is a tool like many others, from empathy and consumer marketing to capital and incentives. Let’s understand and use all of these tools.
Human psychology explains why marketing works, and marketing has definitely been used for silly reasons in the past. Still, if part of your goal involves getting people to do something, refusing to use human psychology to further your well-intentioned outcome is cutting your nose to spite your face. Similarly, it’s unarguable that those who wield gigantic capital have had outsize influence in our society, and some of them are sociopaths. Still, refusing to consider how one could use capital and incentives to drive behavior is an equally flawed limit. Lastly, obviously, technology can be dehumanizing. But technology can also, if wielded thoughtfully, be liberating. Each has power, and power isn’t intrinsically evil.
Tech companies of the last decade have shown the outsize impact that these three disciplines, when wielded in coordinated fashion, can have on the world. Uber’s success isn’t due to smart deployment of tech, psychology or capital. Uber’s success is due to a brilliant combination of all three (and more). I’ll leave it history to figure out whether Uber’s impact will be net positive or negative based on metrics that I care about, but the magical quality that combination unleashed is awe inspiring.
This effective combination of disciplines is a critical step which I think eludes many people and organizations, due to specialization without coordination. It is relatively clear how to become a better technologist or marketer. The ladder of capitalist success is equally straightforward. But figuring out how to blend those disciplines and unlock magic is elusive, both within a career path and within organizations.
I wonder if it’s possible to label this pursuit, in a gang-signal sort of way. Venture capitalists, marketers, and technologists all gain a lot by simply affiliating with these fields. I find any one of these dimensions deeply boring, and the combinations so much more provocative. Who’s with me and what do you call yourselves? Combinatorists? Alchemists?
|
Aki Sasaki: introducing scriptharness |
I found myself missing mozharness at various points over the past 10 months. Several things kept me from using it at my then-new job:
mozharness.base.*
largely non-Mozilla-specific, the mozharness clone-and-run model meant there was a lot of Mozilla-specific code that came along with it.
I had wanted to address these issues for years, but never had time to devote fully to harness-specific development.
Now I do.
Introducing scriptharness 0.1.0:
I'm proud of this. I'm also aware it's not mature [yet], and it's currently missing some functionality.
There are some ideas I'd love to explore before 1.0.0:
--add-action clobber --no-upload
structure, or play with --actions +clobber -upload
or something. (The - before the upload in the latter might cause argparse issues?)
I already have 0.2.0 on the brain. I'd love any feedback or patches.
|