EmberConf 2024 - Standardizing Autotracking Via TC39 Signals with Daniel Ehrenberg
Watch on YouTubeVideo summary
Daniel Ehrenberg, a representative from Bloomberg's JavaScript infrastructure team and Vice President of ECMA TC39, presented his vision for standardizing autotracking mechanisms through TC39 Signals. Drawing on Bloomberg Terminal's long history as a continuously evolving Electron-based application built with Chromium, he emphasized the critical need to maintain robust codebases over decades by investing in fundamental web technologies like JavaScript. The core argument of his talk is that modern UI frameworks are converging toward similar reactive models; just as different species independently evolved crab-like bodies through convergent evolution, various libraries have arrived at nearly identical solutions for reactivity using signals and tracked cells to ensure views remain synchronized with underlying data without manual dependency declarations.
The technical foundation of this standardization relies on a unified API where "signals" act as atomic state holders that can be read or written synchronously, automatically constructing a dependency graph in the background. Ehrenberg explained two primary algorithms for handling updates: a lazy approach using clock numbers to determine staleness and an eager approach marking fields as dirty immediately upon mutation before recalculating them later in topological order. While different frameworks like Ember, Preact, and Vue may implement these concepts with varying degrees of granularity—some re-rendering entire components while others update only specific parts—the observable behavior remains consistent across the ecosystem because they all solve the same fundamental problem of keeping the DOM updated efficiently when data changes.
Standardizing this functionality through TC39 aims to create a common reference point that allows different frameworks and micro-frontends to interoperate seamlessly, much like how Promises A+ unified disparate promise libraries into native JavaScript features. The proposal currently sits at Stage One in the standardization process, with other related features like decorators already further along or standardized; however, adoption requires community effort rather than immediate browser implementation. Ehrenberg highlighted that while a polyfill library exists for experimentation and early integration is happening within development branches of frameworks like Glimmer Next, there are still performance bugs to fix and extensive testing needed before the feature can be safely shipped in production environments across all JavaScript engines.
To move this initiative forward from concept to reality, Ehrenberg called on the broader developer community to contribute by improving polyfills, writing tests for edge cases, integrating signals into their own applications, or even joining TC39 directly via consensus-based voting processes that prioritize compatibility and conservative defaults. He noted that significant work has already been done collaboratively across multiple frameworks including SolidJS, Vue, and Preact, with representatives from each ecosystem taking responsibility to refine the proposal together. Ultimately, the goal is not just to add a new language feature but to establish an interoperable foundation for reactivity that benefits the entire web development landscape through shared semantics and improved debugging capabilities in developer tools.
Read the full video transcript
hi thanks thanks everyone I'm very very
happy to be here it's my first Ember
conf and it's great to meet so many
people who I've interacted with online
before and uh so I'm little Den I work
at Bloomberg uh previously at at uh
other companies but working right now on
the JavaScript infrastructure and tools
team which supports the Bloomberg
terminal Bloomberg terminal is a
platform for uh viewing and analyzing
financial information so I've been
contributing to tc9 since 2016 I've
worked on features like big in and the
hashtag based private fields and methods
uh I'm currently vice president of ecma
that's like less impressive than it
sounds it's it's more like a board
position and I I mean it's still it's a
small board I live so I live here in in
New York uh I used to live in the coast
of Catalonia which you could see here
the town has like very tiny Coastline
kind of funnel shaped uh and that's sort
of the whole Coast the town's all Inland
uh
so yeah I mentioned that Bloomberg's
main product is the terminal you've
probably heard of Bloomberg News but the
the biggest product is this financial
information terminal and this is
basically a big electron app actually
it's our own build of chromium together
with some native code especially for uh
Network and
processing and we have so many problems
that are in common with web applications
because it is it is built on web
Technologies and that's why we've been
investing in fundamental Technologies
like JavaScript and CSS so Matthew is
asking me uh just yesterday at dinner
why is it that Bloomberg invests all
this and
really the only difference from other
other companies is because we've been
around for 4 years because we've been
maintaining this continuously available
system and evolving it over time
incrementally we really see the see the
need to make sure that in five years we
have a good basis that continues the the
life of our code
so um pretty aligned with what we've
been hearing about Ember Evolution I
think so we're we're talking about UI
Frameworks that's why we're all here and
I think the key job of UI Frameworks is
is to keep the Dom up to date with the
data or in another terms the view is a
pure function of the model and words
like View and model they're kind of
considered obsolete that's like 90s o
but it's just referring to the same
Concepts that we're all getting at right
now the view being what's on the screen
and the model being the underlying
data um so in embra this works out
really well we have our templating
syntax and we have our our JavaScript so
the JavaScript is able to represent with
Ember autot tracking it's able to
represent the this language and then
when the language changes it might
change with this update language which
is based on the the
select then the greeting will change and
this gets somehow rendered on the screen
automatically so even if you have the
same name uh the the greeting will
change and Ember is smart enough to only
update the part that actually
changed so this is due to fine Grand
pull-based reactivity so you
consistently update only what's needed
only if it's needed and autot tracking
means there's no need to declare
dependencies so that that works based on
when Ember is rendering it just watches
for whenever you read something this
attracts fields and then takes note of
those and then it kind of builds a graph
so that when you need to uh so that when
some data changes it can kind of Follow
That graph in the reverse Direction and
figure out what needs to be written back
again to the
screen actually it doesn't work like
that it works in this opposite way so
Ember ember's autot tracking is based on
these clocks so there's a current
revision number of
what um like how up toate the data is
and Ember uses this this mechanism to
pull that and update when needed but
saving work because of kind of smart
ways of maintaining those numbers this
is described really well in a series of
blog posts by uh by Christen hu Garrett
um who's formerly you know working a lot
on Ember and another algorithm is more
similar to what I described it's kind of
you could call it like the push
dirtiness pull values algorithm so in
either case when you update a signal
the not calculation is done immediately
so imagine you have a as a tracked field
and then maybe B and C are other cached
Getters eventually f is like another
cached getter when you change a how does
that lead to updates happening later one
way is that you increment the you know
you take a new clock number and then uh
when you read F then it will uh see okay
yeah F's clock numberers lower than a is
so I'd better go back and and calculate
things that's completely lazy the semi
laaz way is when you write to a then you
get into this first part where you dirty
B and C you color them red and then when
you read F later then it starts to go
through these later stages of okay uh
I'm sort sorting things in topological
order uh it's a slightly complicated
algorithm but it's not that complicated
uh the whole point is to make sure that
we have consistent calculations when
sometimes this is referred to as the
glitch-free
property and although there are multiple
algorithms they have the same observable
behavior when I say observable I mean uh
the JavaScript program that's running
you know your application can't tell
whether it's using the clock algorithm
or the dirtiness pushing algorithm
because they just do the same thing
and we so to me this reminds me a little
bit of uh this process of carcinization
so many different crustations have
independently evolved to have a crab
shaped body because it turns out that
just works out well for some Lifestyles
so
uh you know porcelain crabs pictured
here have came back to that to that same
idea even though they're not very
closely related to Common
crabs and okay here's my heterodox
opinion to be analogous to what Yuda
said I think all the Frameworks are
becoming pretty similar they're becoming
the same and that's a good thing because
really how complicated can reactive
rendering really be we're just we're
just kind of figuring out the answer uh
so this a mix of convergent evolution
like the crabs and sharing ideas
directly there there's sort of both
happening uh convergent evolution really
was a you know demonstrably a part of
this because over the past 10 years you
could see as different Frameworks
updated their reactivity model they got
different parts of the answer right at
different times it's not like solid came
up with signals and then everyone
figured out how to copy them and they
took time to come around I mean Ember
was coming up with this stuff at the
same time just with different algorithms
and some of the things emper got right
earlier like about signals computed
signals being garbage collectible but um
don't have time to get into that right
now so a signal been using a word
without defining it is basically a
tracked cell
so uh this is like when you have a a
class in Ember and you have a field
that's
tracked it it did take some time to to
figure out but all these different
Frameworks ended up coming to basically
the same conclusion now we're trying to
share our common answer
answer so here's how
we here's how we put it into an API
that's now proposed for standardization
in
tc39 this is you know pseudo type
scripts because you can't do class
signal. state but whatever
uh there's a class that's just a signal
so this is just like a trct field and
you can have an initial value and you
can get and set it and computer which is
like a cashed getter which takes as an
argument a call back uh which doesn't
take any arguments and you can you can
get it there's a number of other apis
that we ended up needing uh this is the
subtle part so when when you're
programming you're usually either making
a track field or making a a getter which
might or might not be
cashed but Frameworks need some more
subtle things to be able to integrate
this and into their rendering to figure
out when to render and which parts are
the the relevant parts so we have some
of apis for for that purpose that we're
iterating on trying to be
minimal so to to visualize you know the
app developer will use maybe some nicer
skin over the computed and state
apis then for when things render into
the Dom or when other side effects are
supposed to happen
uh Frameworks would provide some effect
API or some template syntax that would
end up using these other subtle
apis and this allows us to build
framework independent reactive
models so you know kind of not going
with exactly what Yehuda said before
what you know I like classes but if we
want to present this to the whole rest
of the world we have to we have to live
with you know we can do this with
objects also this works
uh this is actually how yehud and I
together with Json from from the Google
whiz team were presenting signals to
tc39 if you have a little data structure
which might have Getters for um so
imagine this is a counter and you have a
button to increment the counter and you
could also see what the current value is
and whether it's even or odd so this
gives you an object that represents that
with signals for this reactivity
this could be used for example in
preactor view this isn't this isn't
Ember code but it it looks so similar I
mean you just have a template you have
things filled into the template you have
an event handler
um
and they both you know this template is
where kind of effects come
in so when when
the when preact is is rendering this it
will call this function which will you
know read parody. count and that'll
access this state so that'll be you know
autot
tracked it'll also call parody which
calls these even and uh and parody
computed causing them to be
evaluated uh initially they're they're
uninitialized so this is represented as
kind of red but then once they uh once
they all evaluate which Happ happens you
know immediately when they're read
everything about signals is synchronous
uh then they um they have this
dependency graph that they're able to
construct and they have their
values when you click on the button the
counter increments its state so now
these these diagrams are colored more
according to the solid algorithm than
the Ember algorithm it's kind of easier
to
visualize um so
um pract can see and it sees this in
kind of an atomic way in the pract case
because it it ends up having to
reevaluate the whole show counter
function because of how it uses the
standard jsx transform anyway it sees
okay last time I ran show counter I was
reading counter. count and counter.
parity and those are
both
uh stale so
so counter becomes uh stale and then
walking the dependency graph backwards
uh all those other things become stale
and then so you have more than enough
reason to render show
counter
uh but then it can re-evaluate them all
and and get to a steady
state but a cool thing about this is
that invalidation can be
granular uh so this because of the way
rendering Works in preact it doesn't
actually allow the re-rendering to be
granular but it does allow us to not
have to calculate this super expensive
turnery operator so in this case uh you
know you click plus two so these things
all become red uh but
the um I guess we kind of skipped some
steps but uh is even in parody because
it looks like they're stale but then
when we get to calculate is even it gets
the same answer again so then there's no
particular reason then parody can become
revalidated by the
system and this actually works in Vue
just the same because view uses a
declarative template syntax like Ember
uh it's able to break this down further
and only rerun the the individual parts
that um that change so imagine that
count or are passed into some helpers it
would only have to rerun those helpers
if uh if it's relating to the the the
part that changed so when you do plus
two becomes initially it looks like it's
invalid but then you know it didn't
really have to do the parody
again so let's talk about why it bother
with
standardization or what does
standardization even mean so at a at a
social level what we want this to have
an impact on the the ecosystem and this
really needs to start with the ecosystem
so one model from 10 years ago now is
the promises A+ project this was a
community-driven effort where several
different promise libraries uh got
together and said how can we unify our
apis and able enable them to be
compatible with each other so they came
up with a common then method and and
catch
and and Define what they should mean
this became integrated
eventually into the tc39 promises
standard and was added to Native
JavaScript uh so we want to take some
things from this but also learn from
some of the lessons uh the Ember communi
is and the only one that had trouble
upgrading fully to Native promises many
people did including inside of blumberg
uh and so we're trying
to what what we're really doing is
finding this common base of reactive
semantics but then enabling different
ergonomic skins on top of it from
different Frameworks uh the other thing
that we're doing is first very similar
to promises
A+ UniFi trying
to make sure that different actually
used libraries and Frameworks can adopt
this system before trying to standardize
it
um but because of this second part of
different systems having different skins
on top there's absolutely no changes
that applications need to do to adopt
signals so signals would be something
that underlies ember's reactivity
mechanisms but would not be necessarily
how you program in terms of it I mean of
course if it exists I'm sure people will
reach for it but there's uh there's
nicer ways programming models that I'll
that I'll get to soon that you can use
interoperability is a major thing so I
showed how this model can be reused and
maybe you even have a model that you use
in multiple ways on the same page
so um if you have a you know micr front
ends with a common data layer then maybe
they're accessing the same uh the same
structures and they they become
invalidated hopefully this could allow
embedding widgets inside of each other
and I think uh standards could give a
common reference point for this kind of
sharing one thing about autot tracking
in particular it relies on having a
global variable for what is the current
computed signal or what is the current
uh you know cach getter so that it can
track what the uses are and Associate
them to that cash getter and uh with
with the way the JavaScript ecosystem
works it's a little bit hard to compose
different things it could be nice to
have the JavaScript language be this
common reference point so that the so
that you can make sure you don't have
different Notions of what the current uh
computed signal is in different points
in the
program implementations that are native
to JavaScript engines might also be
higher
performance I don't expect this to be
magic they're not going to have
algorithmic differences I believe but
inside of C++ you can get a constant
Factor Improvement by using more
efficient data
structures uh and for now we're working
on an efficient polyfill in javascripts
or polyfill just an implementation it's
just a JavaScript library of signals and
um trying to make this
efficient not not there yet
though signals can also help us pull
effort on important things that span uh
multiple Frameworks for example Dev
tools with reactivity it can be hard to
debug kind of causality what what caused
what to happen uh the uis that you might
want to make in Dev tools are are kind
of complicated and right now each
framework has to come up with its own
way of visualizing this but really we're
all doing the same thing so it would be
great if we could work together on this
whether it's through an external Plug-In
or in Native Dev tools
so how does standardizing a JavaScript
Feature work this is done through ecma
tc39 so Emma International this Geneva
um organization it used to be the
European computer manufacturing
association but now it's like KFC it
doesn't stand for anything in
particular uh and tc39 which is
originally the 39 technical Committee of
Emma we have our our website we're
focusing on speci
javascripts and that's just another
website so the the standard for
JavaScript is just a a web page which we
develop in our um own kind of markdown
dialect called which we call E markup
and um it's just a very very long web
page don't print it out it would be over
a thousand pages long uh and it it
describes everything in JavaScript in in
thorough detail so it's unambiguous
actually um One engine author I don't
know if you've heard of lib Js from the
serenity OS Project a newer JavaScript
engine he was uh lenus grow my cooworker
at Bloomberg who who's um you know
worked a lot on lijs was saying that
compared to other language standards the
JavaScript one is really unambiguous
really tells you everything whereas with
python or Ruby it's not quite as much
the case anyway that uh that preceded me
there have been a lot of editors over
the years who have done a really great
job making the the standard
precise and we we work by a process
that's kind of similar to the Ember RFC
process uh we have our tc39 process and
there's actually been cross pollination
in both
directions uh the tc39 process was via
Yehuda inspired to take some elements
from the previous Ember RFC process and
then Ember had its reform of the RFC
process based on some of the things we
figured out in
tc39 and we have four stages for how
standards work at stage one an ideas
just brought brought on the table to be
under discussion at stage two we
collectively decide we want to do this
we have a first draft we have some
concrete ideas uh and as a committee we
agree that this is a good idea for the
language at stage three we have a pretty
final draft we have tests so that when
you implement it you can just run the
test to see if your implementation works
and we think it's kind of ready to go
maybe some browsers will ship it at this
point and at stage four we have multiple
implementations and at that point it's
standard uh when I say standard then we
land the pr it's in the editor's draft
and then it'll be in the next year's es
2025 whatever
addition so some examples of this
signals are currently at stage one ASN
context which is a a feature that I
think would be really useful to underly
things like the the Ember context
initiative um is at stage two decorators
as we saw in the the Ember data talk are
at stage three and uh private fields and
methods they're at stage four they're
already part of the standard so
decorators we have the complete spec
that's why they're shipping in
typescript um asent
context people people think it should
happen we have we have a strong idea but
signals they're just an idea hope
hopefully it'll happen I hope it'll
happen but uh we haven't yet agreed as a
committee that it's going to
happen and tc39 works by consensus we
don't votee on what the language should
be uh we try to work together to meet
everyone's goals so we ask for
objections to consensus and uh this this
really helps maintain a sense of
equality within the committee which is
important for our values
and it also helps maintain a
conservative default of we don't want to
add things that are not ready yet
because we have to maintain a very
strong sense of compatibility over time
also because there are many JavaScript
implementations and it's a lot of work
to implement something so we don't want
to ask implementers to do something
that's a bad
idea so uh couple months ago Yuda and I
together with with jatin from Google uh
presented signals for stage one at tc39
and we got consensus on stage one it is
on the table that's that's all we could
say at this
point from
here from here uh there's a lot of work
that we could do towards prototyping
signals I want to make sure that before
we consider adding signals to the
browser that we make sure that we're
doing the right thing and we could do
that by work at the ecosystem level in
particular at the framework
level so the first step is having an
implementation of the you know the
signal Library itself which uh I worked
on with some co-workers at at Bloomberg
uh Dolan Mew and Eric yans so we have
the the Bloomberg copyright header on
the the rapper but actually uh this is
just like a 200 some line wrapper around
angular signals angular and and whiz
were already doing the the right thing
so we were able to implement this just
by reusing their their thing I think
there are many signal implementations
that we could have
used so this is on npm you can use it
but it's not ready for production it has
it has bugs the API is going to change
but I encourage people to play around
with it if they're
interested but another thing is just
having these atomic
cells is not really the programming
model you want to be using all the time
and Ember and uh figured this out with
the track built-ins and track toolbox
and um also present in starbeam so noox
populi right here in the back uh ported
these to signals with signal utils which
include an at signal decorator which
because they're using stage three tc39
decorators you can use it even on a
private field
uh as well as signal object which is
like capped
objects so also on npm uh should get
that download count up it's had a spike
now almost nothing uh so integrating
signals into Frameworks is also good
again this is something to do in
development branches it's not time yet
to to ship all this stuff to production
but uh I'm really grateful that Alex
lifeart has uh done this sport on a
branch of glimmer next uh and found
immediately that the part of the code
that I wrote this Watcher unwatch method
is really really slow uh so if anybody
wants a contribution opportunity you can
PR PR is welcome to fix this uh also
found a bug where just some simple thing
crashes uh so thank you so much Alex for
filing these issues uh I'm also really
excited to work with Chris thurn on
uh integrating signals into warp drive
another possible contribution
opportunity uh so just want to thank the
the many contributors from the Ember
Community um
and um excited to continue working
together so if you're interested we
actually need need your help there's a
there's just a lot to do so please join
the effort we have a Discord we have uh
calls every couple weeks that you could
join if you want to chat with me and the
other signal co-champions that's what we
call the the people pushing forward the
effort I mentioned like 10 Frameworks
and there's basically somebody from each
of those who's you know taking
responsibility together for the proposal
happening so it wasn't wasn't just Ember
it was also people in solid
spelt
uh view everything working together to
make this happen uh
there are polyfill bugs you could write
tests there aren't enough tests
integrating signals into applications
would really help uh prove them out and
filing issues you could even join Emma
in tc39 so that's um please just get in
touch with me if you're interested in
doing any of those and U I'll I'll be
around afterwards also I'm on the Ember
Discord so you could just write me there
and uh thank you very much
than