<!-- 
#Evalution, #BestPractices and #OpenProblems
- Experience of Using Web Components in Self-supporting Development of the Lively4 Environment
-->

## Discussion

Lively4 uses Web Components for all its UI. All tools such as the file editor and internal content browser are custom HTML elements. During this development we enjoyed the experience of being able to work with HTML elements and have a Lively Kernel like feedback at run-time. But we also encountered problems and developed best practices and insights for future work.

### Lively4 Development Experience

The Lively4 development environment^[The current Lively4 system is hosted under https://lively-kernel.org/lively4/lively4-core/start.html and used from there to directly work on its own GitHub project https://github.com/LivelyKernel/lively4-core/ in a self-supporting way.] is build using Web Component at its core. The figure @fig:ExampleLivelySync shows three windows: a browser/editor, an inspector, and the GitHub sync tool. The browser shows the source code of the sync tool's module. Editing and accepting code there will automatically update the open instance of the sync tool. Editing this `initialize` method to change to window title will also update the window title of the sync tool. This is possible because our migration approach takes care of also executing the initialization code, so that shared state that is not persisted will also update.

<!-- #Contribution -->

This inclusion of initialization code into the feedback loop is a major contribution compared with Smalltalk-like development approaches.

<!-- #OpenProblems, #BestPractices and #FutureWork -->

### Stale Code and Dangling Event Listeners

Changing code in a live system will often produce new behavior and new objects, but it also results in some objects, methods or reference to become obsolete. A good example for such *stale code* [@Burckhardt2013IAC] are dangling event listeners. A framework has to take care of not letting the old code and behavior get in the way of the new one. A developer team that used Lively4 to build an *Exposé* window management feature^[*Exposé* shows an overview of all windows side by side] run into such a problem. Their component registered itself for global key or mouse events, which resulted in problems when its new version registered handlers again. Their approach to deal with the issue was to fall back into a full page reload development workflow, taking no advantage of the faster feedback loop of run-time development. After this, we established a best practice to use an event registering mechanism that allows us to clean up and unregister old listeners automatically.

<!--  
#BestPractice vs. #EnforcedByLanguage
- We still do not enforce that use of this mechanism and it is more like a best practice to use it. 
```JS
   lively.addEventListener(domain, target, type, listener, options) {
     // domain is a custom symbol that defines the scope
     this.eventListeners.push({domain, target, type, listener, options});
     target.addEventListener(type, listener, options);
   }
```
-->

### JavaScript Objects and HTML Elements

The new abstraction mechanisms of Web Components allows us to maintain a cleaner, more domain-specific data structure, allowing us to push such structures and not JavaScript objects in the center of the programming of applications and tools in Lively4. We still use JavaScript objects, classes and modules to describe the behavior of tools and applications in Lively4, but, when developing the UI, they are second class citizens and they will not be persisted. We decided to use just HTML as the format to preserve the state of our tools and applications. Compared with Lively Kernel, we switched the double-sided coin of JavaScript objects and HTML Elements in favor of the HTML Elements. In Lively4, the JavaScript objects are second class citizens and we throw them away when we need to, relying on the fact that the HTML Element will persist the application state and preserve the context for development.

<!-- #BestPractices #FutureWork  -->

![ExampleLivelySync](../figures/example_lively_sync.png "Tools in Lively4: (A) code browser and editor, (B) Element and object inspector (C) Halo for direct manipluation, (D) GitHub version control tool")

### Losing Object Identity

<!-- #Patrick CLOS does this -->

In our current approach, we replace HTML elements with new versions of themselves, creating a new JavaScript reference in the process. We take care of updating some known JavaScript references, but we do not have full control over all aliases that could for example be bound in closures. As a best practice, we do not rely on object identity in our own programs and use names or IDs to look up elements at run-time. In future work, we plan to combine object mutation and migration, so that the JavaScript references stay intact.

<!--   ### DOM does not allow references
  - #Problem our main data structure / model has does not support arbitrary references  
  - only implicit parent child relation
  - #BestPractices working with `querySelector(id)`
   -->

### Dynamic Elements in Static Templates

A Web Component is not only defined through pure HTML template, but can contain arbitrary script tags or use an external JavaScript module (as shown in figure @fig:TemplateAndInstances). This allows the developers to use the very static element structure in the template to describe the static UI, and use JavaScript to generate more dynamic UI elements as needed. This is clearly not a unified way to describe UIs, but it seems to be a preferred way of many Web developers. This is not an issue of Lively4 since it does not set out to invent a new programming- or UI description language. Further, we do not often run into this issue since the major parts of the UI, that we developed for our tools and applications, were static. 
<!-- #FutureWork, find out how much of our actual UI is generated by code vs has a static representation... could be interesting research topic #Idea) 
-->

<!-- the individual parts used in the dynamic creation can be Web Components again (for example ComponentBin and ComponentBinItems) -->

### Level of Preserving Context

Our approach of using our custom HTML persistence for migrating Web Component instances to preserve the context while developing has a catch: the Web Component might not persist all its relevant state that the developers expects, yet. This is especially apparent because Lively4's white listing object persistence approach highly differs from the *serialize everything* and black list later approach in Lively Kernel and Smalltalk images. Our approach to deal with this issue is to develop the persistence (loading and saving behavior) of Web Components in parallel with other features.

### Changing of a JavaScript Module

Web Components may depend on JavaScript modules. Since those modules can affect custom HTML elements, it is not clear what happens when those modules change. We decided to treat such changes similar to changing the source of Web Components directly. In particular, tools check for dependencies and update all dependent Web Component instances. In rare cases, some core modules will affect the whole system and will trigger a complete migration of nearly all Web Components, causing the system to nearly fully reload. We experimented with maintaining a blacklist for modules that should not update all dependents, but opted for manually disable dynamic feedback as needed.

### Problems of Combined Run-Time- and Development Environments

Evolving a running system from inside can lead to some challenging situations, e.g. when trying to debug something that is used by the editing tools. We experimented with using Context-oriented Programming [@Lincke2011OIC] to scope the changes in development layers [@Lincke2014ETC], when we were working on JavaScript modules.

While working on Web Components, this approach was not enough. But we kept our environment working through making use of the per instance migration. This allowed us further to exclude special objects as needed. In the bootstrapping phase of developing the `lively-editor` and `lively-container` components, we excluded specially marked instances so making an error while working on the editor code would not break the whole system since there was still a working editor around that used an stable template. Later we disabled this because we seldom ran into such problem. If we did, we had a second system to fall back to, so we could fix the first one.


