briskml / brisk-reconciler

React.js-like reconciler implemented in OCaml/Reason
MIT License
131 stars 17 forks source link

"Time Travel" #23

Open bryphe opened 5 years ago

bryphe commented 5 years ago

Reading through #14 made me think about this - eventually, for Revery and beyond - I'd like to be able to have a 'time travel' development experience. Like Redux, but maybe without necessitating keeping a global app state.

I was curious if it'd be possible to hold on to past rendered trees, and call executeHostViewUpdates on old versions in order to rewind the tree to an earlier state.

The 'developer experience' I'm thinking about would be a sort of slider where you could rewind to any particular point in time, and see the UI in that 'rewound' state. I'm interested in this especially in the context of debugging animations (ie, frames where we hit a discontinuity). Implementation-wise, in debug mode, we'd record 'snapshots' of the rendered tree and hold them in memory for some amount of limit.

One challenge I see is that I'm not sure how 'effects' would play into this...

The nice thing about this developer experience - if it works with Brisk - is that this DX would apply to any brisk-reconciler powered app - which would be amazing πŸ˜„

I love the idea of this 'time travel' debugging experience, but it's always been finicky to set up and use - but I hypothesize the functional nature of Reason/Brisk would at least bring this closer to being a usable reality.

Would this be doable as-is with the current reconciler infrastruture, @wokalski ? Or do you see any deltas?

wokalski commented 5 years ago

effects are notoriously hard in such cases. I'm not a big fan of time travel (I consider it kind of a gimmick) because it's really hard to implement right. That said, I'd be open to accept/brainstorm/even implement a solution to this if we can come up with a sensible non-leaky abstraction. My immediate thought is that one should try to implement it in the user space and we could back port it to the reconciler when it's satisfying. You could for instance record insertNode/deleteNode operations and apply inverse but practically it's extremely hard because tracking all side effects is almost impossible. Let's say that not only do I add a view but also make it red. Tracking insertNode/deleteNode is easy, but tracking all "side effects" and allowing unrolling them is extremely hard. Also, it's very backend specific.

And lastly; what's time travel without runtime introspection? It's just a screencast. Implementing runtime introspection together with time travel seems like an interesting idea... for a PhD πŸ˜ƒ.

bryphe commented 5 years ago

I'm not a big fan of time travel (I consider it kind of a gimmick)

It's definitely gimmicky in all the environments I've tried it in. But I think there's a potential for a unique trifecta to improve development:

This trifecta is what I believe is enabled by the functional model for UI (and games), and where I believe a key value proposition is in this development environment vs incumbents. It's especially suited to real-time apps which are notoriously hard to debug transient issues, but would also be useful for less-real-time apps IMO

My immediate thought is that one should try to implement it in the user space and we could back port it to the reconciler when it's satisfying.

Sounds reasonable. I think there are different layers of abstraction for this - an alternate is to time-travel the 'state' of the app (the redux-style time-travel) - this is what I might start prototyping. Essentially it'd be 'above' the reconciler level and wouldn't track internal states, but I think this is a reasonable starting point - we can keep iterating from there.

Thanks @rauanmayemir and @wokalski for the thoughts!

wokalski commented 5 years ago

@bryphe I agree. If we have runtime introspection and working live code reloading it becomes ground breaking. It has to be general enough to be able to freely use it without some weird restriction but cannot be "general enough to break". What I mean by that, is that solving this truly in the general case would probably require a fair amount of compiler hacking. Maybe we'll get there one day but for now we have to come up with some constraints so that the solution is useful and solid. Also, as an intermediate step for this we should take a look at live code reloading.

wokalski commented 5 years ago

I'm not a big fan of time travel (I consider it kind of a gimmick)

btw, I take it back. I wanted to say

I'm not a big fan of existing time travel-like solutions. They are gimmicky. However, if you make it really good, it's easily a major DX improvement. In the reality where many people don't write tests (it's also hard with many UI apps) this can save a lot of time.