microsoft / MixedRealityToolkit-Unity

This repository is for the legacy Mixed Reality Toolkit (MRTK) v2. For the latest version of the MRTK please visit https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity
https://aka.ms/mrtkdocs
MIT License
6k stars 2.12k forks source link

[Plan of Record] Improve MRTK ease of use: system facades, registrar interface, config ux #3545

Closed david-c-kline closed 5 years ago

david-c-kline commented 5 years ago

Plan of Record: Support Service Specific Scene Presence

Microsoft Mixed Reality Toolkit v2

This document describes a design change for the Microsoft Mixed Reality Toolkit v2 concerning how developer customers can choose the MRTK and its services.

The Issue: Usability

The MRTK team has received feedback from multiple sources that the current, single object presence in the application scene is difficult to use with regards to feature discovery and modularization. Multiple customers, both internal and external, have requested an alternative to beta 2’s MixedRealityToolkit object in the form of system specific locator components (ex: MixedRealityInputLocator) that can be additively included.

One piece of feedback, heard from multiple sources, points out the promise of additive vs. subtractive consumption of MRTK. The comments largely center around two themes:

  1. It is not easy, at a glance, to see if a scene is using a specific MRTK service. Many developers from whom we heard desire an individual service presence in the scene hierarchy.
  2. The root Mixed Reality Toolkit configuration profile makes it appear that all services are present in the application, even when disabled. There is a strong desire for scoping the profile inspector to show only installed and active services.

Solution: Enable Support for Individual Services to have Scene Presence

The solution defines the following changes:

  1. Provide service registration interfaces to enable customers to create a custom service locator and/or fully stand-alone service components
  2. Provide support for exposing active services and their configuration settings in the scene hierarchy at edit time via service facades
  3. Enable customers to create hybrid application architectures, if desired, that use any number of service locators in conjunction with any number of stand-alone services
  4. Create a light-weight service registry that maps service interfaces with the concrete type that manages service registration
  5. An updated scene hierarchy to contain the service registry, service facades, etc
  6. Modified MRTK project configuration flow to provide enhanced flexibility for customers when setting up their projects

Please see the Solution Details section of this document for information the described changes.

Goals

  1. Respond to direct customer feedback
  2. Provide customers with a choice of how they consume MRTK services
  3. Minimize required client code changes
  4. Preserve as much of the MRTK service locator functionality as possible (anticipating 90% or greater equivalence)

Non-Goals

  1. Removal of the service locator pattern
  2. Require developers to change how they wish to work

Solution Details

Service Registration Interfaces

To enable developers to create custom service locators and/or extend an existing service locator to add support for MRTK services, a set of interfaces will be created to support the registration and retrieval of service instances.

It is anticipated that there will either be one or three interfaces that will be created. The following sections describe the pros and cons of each implementation.

Single Registrar Interface

In the single interface approach, the MRTK will define IMixedRealityServiceRegistrar. This interface would define explicit methods for supporting objects implementing the following service types (listed by interface):

Each method (Register, Unregister, Get, CheckRegistration) will have a version that is type safe to the listed interfaces.

Pros Cons
Only one interface to implement Implementors may be required to implement stub methods
Can provide a single base class supporting all service types

Multiple Registrar Interfaces

In the multiple interface design, each type of service would have a corresponding registrar interface:

This approach would allow customers to support only the specific types of services necessary to build their component.

Pros Cons
Developers are free to implement only the required service type support Potentially mutltiple interfaces to implement
Develipers do not have to implement stub methods Cannot consume individual interface base class implementations (C# limitations)

Base Class Implementations

As with much of the MRTK, base classes will be provided to provide robust, reusable implementations of the registrar interface(s).

Providing the Registrar Instance to Services

When the registrar instantiates a service instance, it will provide itself as a constructor argument. The following example shows the parameter to be added to each service constructor.

public ServiceClass(IMixedRealityRegistrar registrar, ...);

A similar pattern will occur for data providers.

When a service requests registration of a data provider, it calls RegisterDataProvider, handing a reference to itself.

registrar.RegisterDataProvider<IMixedRealitySpatialObserver, IMixedRealitySpatialAwarenessSystem>(IMixedRealitySpatialAwarenessSystem system, Type observerType, ...);

The data provider's constructor is passed the provided reference in its constructor.

public SpatialObserver(IMixedRealitySpatialAwarenessSystem system, ...);

Service Facades

Service facades are an editor only monobehavior that exists in the application scene to give customers and easy, at-a-glance representation of the active services in the scene. When selected, the facade will display the service specific profile inspector and allow for easy configuration.

Backing these facades will be added to the scene and backed by the MRTK service locator. Developers not wishing these facades to be in their scene will be able to disable them in the MixedRealityToolkitConfiguration profile.

Hybrid Application Architecture

Hybrid applications architecture is a term intended to describe an application which utilizes any number of service locators and/or stand-alone service implementations.

To support hybrid architectures, MRTK will add a light-weight service registry that enables client code easy access to concrete service implementations.

Service Registry

The service registry in MRTK is an optional component that client code can use to acquire an instance of a desired service.

The registry can be thought of as a table that maps service interfaces to the object that manages the concrete implementation(s) .

The following table illustrates an example registry:

Registrar Interface
MixedRealityToolkitServiceLocator IBoundarySystem
CustomServiceLocator ISpatialAwarenessSystem
StandaloneInputSystem IInputSystem

The component managing the service registry can be attached to client script(s) or developers can choose to bypass the registry and hard-code references to the object managing service registration.

For example:

IServiceInterface service = MixedRealityToolkit.Instance.GetService<IServiceInterface>();

Scene Hierarchy

To help keep the scene hierarchy uncluttered, the default MRTK configuration process will create a Mixed Reality Toolkit parent object. This object will be the parent for the service locator and any enabled facades.

It is recommended that this object be the parent of objects created by registered services (ex: spatial awareness mesh objects).

The following image illustrates the default hierarchy when the MRTK service locator is used with the input and spatial awareness system facades enabled.

Hierarchy With Facades

Project Configuration UX

To make it easy and intuitive for customers to configure MRTK to suit their application's requirements, the Mixed Reality Toolkit menu's Configure item will display a selection dialog similar to the following illustration.

Configuration Dialog

StephenHodgson commented 5 years ago

How do we know this docx doesn't contain a malware macro ;)

But seriously, could we get these in a better format that's readable from a browser window?

david-c-kline commented 5 years ago

I can reformat to .md but it will take time

david-c-kline commented 5 years ago

GitHub does not appear to support attaching .md files.... Sorry about the length of this comment.

Proposal: Support Individual Service Locators

Microsoft Mixed Reality Toolkit v2

This document describes a design change proposal for the Microsoft Mixed Reality Toolkit v2 concerning how developer customers consume the MRTK and its system services.

The Issue: Usability

The MRTK team has received feedback from multiple sources that the current, single object presence in the application scene is difficult to use with regards to feature discovery and modularization. Multiple customers, both internal and external, have requested an alternative to beta 2’s MixedRealityToolkit object in the form of system specific locator components (ex: MixedRealityInputLocator) that can be additively included.

One piece of feedback, heard from multiple sources, points out the promise of additive vs. subtractive consumption of MRTK. The comments largely center around two themes:

  1. It is not possible, at a glance, to see if a scene is using a specific MRTK system. Many developers from whom we heard desire an individual system presence in the scene hierarchy.
  2. The root Mixed Reality Toolkit configuration profile makes it appear that all systems are present in the application, even when disabled. There is a strong desire for scoping the profile inspector to show only installed and active systems.

Proposed Solution

The proposed solution will provide support for both a single, global service locator component (MixedRealityToolkit) and for individual service locator components out of the box in MRTK.

This proposal will also enable developer customers to provide their own service locator implementations that can support custom functionality and/or support for a customized collection of pre-existing services.

Core Scene Component Refactor and Creation of System Serivce Locator Components

The proposal is to create a set of interfaces and base classes that that the MixedRealityToolkit object and other service locator objects can be built upon.

The MRTK would then provide additional service locators for:

• Camera • Boundary • Diagnostics • Input • Locomotion (aka Teleportation) • Spatial Awareness

Configuration Profile UI Changes

As part of this work, the configuration profile inspectors will be updated to reduce the complexity and to enable “one stop” modification of settings.

This proposal does not mandate merging related profiles, nor does it eliminate profile specific inspectors.

Data Provider Registration

As of beta 2, all data providers are registered in the Additional Service Providers profile.

With this proposal, all data providers will be registered in the profile of the relevant system and loaded / managed by the user's selected service locator, which is potentially the service itself. The additional providers profile will be reserved for extension systems and services.

For example, the Windows Mixed Reality Device Manager and Open VR Device Manager components will be registered as data providers with the Input System locator.

Details

The following sections describe architectural details for this proposal. As the proposal is implemented, some details may change.

IMixedRealityServiceLocator

The IMixedRealityServiceLocator interface will define the core requirements for all service locator implementations.

Note: It is under consideration as to whether or not this interface will be subdivided by service type to allow some locator implementations to be simpler and to reduce the number of required methods.

Each locator is responsible for loading supported services. The global locator will continue to support loading all currently defined as well as customer created systems and services (implementing IMixedRealityService). The following APIs are the minimum set that will be required.

/// <summary>
/// Registers a service with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service to be registered (ex: IMixedRealityBoundarySystem.
/// <param name="serviceInstance">Instance of the service class.</param>
/// <returns>True if the service was successfully registered, false otherwise.</returns>
bool RegisterService<T>(
    IMixedRealityService serviceInstance) where T : IMixedRealityService;
/// <summary>
/// Registers a service with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service to be registered (ex: IMixedRealityBoundarySystem).
/// <param name="concreteType">The concrete type to instantiate.</param>
/// <param name="supportedPlatforms">The platform(s) on which the service is supported.</param>
/// <param name="args">Optional arguments used when instantiating the concrete type.</param>
/// <returns>True if the service was successfully registered, false otherwise.</returns>
bool RegisterService<T>(
    Type concreteType, 
    SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1),
    params object[] args = null) where T : IMixedRealityService;
/// <summary>
/// Unregisters a service from the service locator.
/// </summary>
/// <param name="name">The name of the service to unregister.</param>
/// <returns>True if the service was successfully unregistered, false otherwise.</returns>
bool UnregisterService(string name);
/// <summary>
/// Unregisters a service from the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service to be unregistered (ex: IMixedRealityBoundarySystem).
/// <param name="name">The name of the service to unregister.</param>
/// <returns>True if the service was successfully unregistered, false otherwise.</returns>
/// <remarks>If the name argument is not specified, the first instance will be unregistered</remarks>
bool UnregisterService<T>(
    string name = null) where T : IMixedRealityService;
/// <summary>
/// Unregisters a service from the service locator.
/// </summary>
/// <param name="service">The specific service instance to unregister.</param>
/// <returns>True if the service was successfully unregistered, false otherwise.</returns>
bool UnregisterService(IMixedRealityService serviceInstance);
/// <summary>
/// Unregisters all services from the service locator.
/// </summary>
void UnregisterServices();
/// <summary>
/// Unregisters all services from the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the services to be unregistered (ex: IMixedRealityBoundarySystem).
void UnregisterServices<T>() where T : IMixedRealityService;
/// <summary>
/// Checks to see if a service has been registered with the service locator.
/// </summary>
/// <param name="name">The name of the service.</param>
/// <returns>True if the service is registered, false otherwise.</returns>
bool IsRegistered(string name);
/// <summary>
/// Checks to see if a service has been registered with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service (ex: IMixedRealityBoundarySystem).
/// <param name="name">The name of the service.</param>
/// <returns>True if the service is registered, false otherwise.</returns>
bool IsRegistered<T>(string name == null) where T : IMixedRealityService;
/// <summary>
/// Gets the instance of the registered service.
/// </summary>
/// <param name="name">The name of the service.</param>
/// <returns>The registered service instance, as IMixedRealityService.</returns>
IMixedRealityService GetService(string name);
/// <summary>
/// Gets the instance of the registered service.
/// </summary>
/// <typeparam name="T">The interface type of the service (ex: IMixedRealityBoundarySystem).
/// <param name="name">The name of the service.</param>
/// <returns>The registered service instance as the requested type.</returns>
T GetService<T>(string name) where T : IMixedRealityService;
/// <summary>
/// Gets the collection of the registered service instances matching the requested type.
/// </summary>
/// <returns>Read-only collection of the service instances, as IMixedRealityService.</returns>
IReadOnlyList<IMixedRealityService> GetServices();
/// <summary>
/// Gets the collection of the registered service instances matching the requested type.
/// </summary>
/// <typeparam name="T">The interface type of the service (ex: IMixedRealityBoundarySystem).
/// <returns>Read-only collection of the service instances, as type requested type.</returns>
IReadOnlyList<T> GetServices<T>() where T : IMixedRealityService;

IMixedRealityExtensionServicelocator

The IMixedRealityServicelocator can manage any service that implements IMixedRealityService and the IMixedRealityExtensionService is defined as extending this interface.

The IMixedRealityExtensionServicelocator interface is an optional interface that provides methods that can be implemented to limit management to implementations of IMixedRealityExtensionService.

/// <summary>
/// Registers an extension service with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service to be registered.
/// <param name="serviceInstance">Instance of the service class.</param>
/// <returns>True if the service was successfully registered, false otherwise.</returns>
bool RegisterExtensionService<T>(
    IMixedRealityExtensionService serviceInstance) where T : IMixedRealityExtensionService;
/// <summary>
/// Registers an extension service with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service to be registered.
/// <returns>True if the service was successfully registered, false otherwise.</returns>
bool RegisterExtensionService<T>(
    Type concreteType, 
    SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1),     
    params object[] args = null) where T : IMixedRealityExtensionService;
/// <summary>
/// Unregisters an extension service from the service locator.
/// </summary>
/// <param name="name">The name of the service to unregister.</param>
/// <returns>True if the service was successfully unregistered, false otherwise.</returns>
bool UnregisterExtensionService(string name);
/// <summary>
/// Unregisters a service from the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service to be unregistered.
/// <param name="name">The name of the service to unregister.</param>
/// <returns>True if the service was successfully unregistered, false otherwise.</returns>
/// <remarks>If the name argument is not specified, the first instance will be unregistered</remarks>
bool UnregisterExtensionService<T>(string name == null) where T : IMixedRealityExtensionService;
/// <summary>
/// Unregisters an extension service from the service locator.
/// </summary>
/// <param name="service">The specific service instance to unregister.</param>
/// <returns>True if the service was successfully unregistered, false otherwise.</returns>
bool UnregisterExtensionService(IMixedRealityExtensionService serviceInstance);        
/// <summary>
/// Unregisters all extension services from the service locator.
/// </summary>
bool UnregisterExtensionServices();
/// <summary>
/// Unregisters all extension services from the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the services to be unregistered.
bool UnregisterExtensionServices<T>() where T: IMixedRealityExtensionService;
/// <summary>
/// Checks to see if an extension service has been registered with the service locator.
/// </summary>
/// <param name="name">The name of the service.</param>
/// <returns>True if the service is registered, false otherwise.</returns>
bool IsExtensionServiceRegistered(string name);
/// <summary>
/// Checks to see if an extension service has been registered with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service.
/// <param name="name">The name of the service.</param>
/// <returns>True if the service is registered, false otherwise.</returns>
bool IsExtensionServiceRegistered<T>(string name == null) where T : IMixedRealityExtensionService;
/// <summary>
/// Gets the instance of the registered extension service.
/// </summary>
/// <param name="name">The name of the service.</param>
/// <returns>The registered service instance, as IMixedRealityExtensionService.</returns>
IMixedRealityExtensionService GetExtensionService(string name);
/// <summary>
/// Gets the instance of the registered extension service.
/// </summary>
/// <typeparam name="T">The interface type of the service (ex: IMixedRealityBoundarySystem).
/// <param name="name">The name of the service.</param>
/// <returns>The registered service instance as the requested type.</returns>
T GetExtensionService<T>(string name) where T : IMixedRealityExtensionService;
/// <summary>
/// Gets the collection of the registered extension service instances matching the requested type.
/// </summary>
/// <returns>Read-only collection of the service instances, as IMixedRealityService.</returns>
IReadOnlyList<IMixedRealityExtensionService> GetExtensionServices();
/// <summary>
/// Gets the collection of the registered extension service instances matching the requested type.
/// </summary>
/// <typeparam name="T">The interface type of the service (ex: IMixedRealityBoundarySystem).
/// <returns>Read-only collection of the service instances, as tye requested type.</returns>
IReadOnlyList<T> GetExtensionServices<T>() where T: IMixedRealityExtensionService;

IMixedRealityDataProviderlocator

As with extension services, the IMixedRealityServicelocator can also manage data providers that implement the IMixedRealityDataProvider interface. Similarly, the IMixedRealityExtensionServicelocator supports management of IMixedRealityDataProvider implementations.

The IMixedRealityDataProviderlocator interface is an optional interface that provides methods that can be implemented to limit management to implementations of IMixedRealityDataProvider.

/// <summary>
/// Registers a data provider with the data provider locator.
/// </summary>
/// <typeparam name="T">The interface type of the data provider to be registered.
/// <param name="dataProviderInstance">Instance of the data provider class.</param>
/// <returns>True if the data provider was successfully registered, false otherwise.</returns>
bool RegisterDataProvider<T>(
    IMixedRealityDataProvider dataProviderInstance) where T : IMixedRealityDataProvider;
/// <summary>
/// Registers a data provider with the data provider locator.
/// </summary>
/// <typeparam name="T">The interface type of the data provider to be registered.
/// <returns>True if the data provider was successfully registered, false otherwise.</returns>
bool RegisterDataProvider<T>(
    Type concreteType, 
    SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1),
    params object[] args = null) where T : IMixedRealityDataProvider;
/// <summary>
/// Unregisters a data provider from the data provider locator.
/// </summary>
/// <param name="name">The name of the data provider to unregister.</param>
/// <returns>True if the data provider was successfully unregistered, false otherwise.</returns>
bool UnregisterDataProvider(string name);
/// <summary>
/// Unregisters a data provider from the data provider locator.
/// </summary>
/// <typeparam name="T">The interface type of the data provider to be unregistered.
/// <param name="name">The name of the data provider to unregister.</param>
/// <returns>True if the data provider was successfully unregistered, false otherwise.</returns>
/// <remarks>If the name argument is not specified, the first instance will be unregistered</remarks>
bool UnregisterDataProvider<T>(string name == null) where T : IMixedRealityDataProvider;       
/// <summary>
/// Unregisters a data provider from the service locator.
/// </summary>
/// <param name="service">The specific data provider instance to unregister.</param>
/// <returns>True if the data provider was successfully unregistered, false otherwise.</returns>
bool UnregisterDataProviderService(IMixedRealityDataProvider dataProviderInstance);
/// <summary>
/// Unregisters all data providers from the data provider locator.
/// </summary>
bool UnregisterDataProviders();
/// <summary>
/// Unregisters all data providers from the data provider locator.
/// </summary>
/// <typeparam name="T">The interface type of the data providers to be unregistered.
bool UnregisterDataProviders<T>() where T: IMixedRealityDataProvider;
/// <summary>
/// Checks to see if a data provider has been registered with the service locator.
/// </summary>
/// <param name="name">The name of the data provider.</param>
/// <returns>True if the data provider is registered, false otherwise.</returns>
bool IsDataProviderRegistered(string name);
/// <summary>
/// Checks to see if a data provider has been registered with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the data provider.
/// <param name="name">The name of the data provider.</param>
/// <returns>True if the data provider is registered, false otherwise.</returns>
bool IsDataProviderRegistered<T>(string name == null) where T : IMixedRealityDataProvider;
/// <summary>
/// Gets the instance of the registered data provider.
/// </summary>
/// <param name="name">The name of the data provider.</param>
/// <returns>The registered data provider instance, as IMixedRealityDataProvider.</returns>
IMixedRealityDataProvider GetDataProvider(string name);
/// <summary>
/// Gets the instance of the registered data provider.
/// </summary>
/// <typeparam name="T">The interface type of the data provider.
/// <param name="name">The name of the data provider.</param>
/// <returns>The registered data provider instance as the requested type.</returns>
T GetDataProvider<T>(string name) where T : IMixedRealityDataProvider;
/// <summary>
/// Gets the collection of the registered data provider instances matching the requested type.
/// </summary
/// <returns>Read-only collection of the data provider instances, as IMixedRealitydata provider.</returns>
IReadOnlyList<IMixedRealityDataProvider> GetDataProviders();
/// <summary>
/// Gets the collection of the registered data provider instances matching the requested type.
/// </summary>
/// <typeparam name="T">The interface type of the data provider.
/// <returns>Read-only collection of the data provider instances, as tye requested type.</returns>
IReadOnlyList<T> GetDataProviders<T>() where T: IMixedRealityDataProvider;

MixedRealityServicelocatorBase

The MixedRealityServicelocatorBase class will provide a default implementation of the IMixedRealityServicelocator interface and will be leveraged by MixedRealityExtensionServicelocatorBase and MixedRealityDataProviderlocatorBase.

Custom service locator implementations are encouraged to inherit from MixedRealityServicelocatorBase and customize behaviors as needed to avoid the need to implement duplicate code.

MixedRealityExtensionServicelocatorBase

The MixedRealityExtensionServicelocatorBase class will use MixedRealityServicelocatorBase to handle core service management functionality and add a layer of type checking to ensure that all managed services implement IMixedRealityExtensionService.

MixedRealityDataProviderlocatorBase

The MixedRealityDataProviderlocatorBase class will use MixedRealityServiceExtensionlocatorBase to handle core service management functionality and add a layer of type checking to ensure that all managed services implement IMixedRealityDataProvider.

MixedRealityToolkit Class Refactor

As part of the interface and base class definition and implementation process, the MixedRealityToolkit class will be refactored with common and reusable code moving into the base class.

System locators

locators for each of the systems listed previously will be created leveraging the base classes and interfaces. Not all system locators will require all features (ex: the Spatial Awareness system does not use a profile) and each will implement the minimum set of interfaces necessary.

System Implementation Changes

As the systems will no longer be able to expect the concrete MixedRealityToolkit class to be managing them, the current system implementations will need to be updated. These changes will involve requesting data from the locator via interface contracts.

Data Providers

With this proposal, each system will bear the responsibility for Unloading and managing registered data providers. The system implementations will call into the system locator to Unload, Unregister and request data about the registered data providers.

Scene Presence

To better support a wide variety of developers and applications, while maintaining the goal if MRTK being minimally intrusive in the scene hierarchy, the scene presence will be modified to add a Mixed Reality Toolkit top level GameObject which will contain the MRTK’s system locator(s).

The following images illustrate the single, global locator and individual component locator options.

For customers wishing to use the current, global system locator, the hierarchy now nests the MixedRealityToolkit object in a parent of the same name (exact name TBD).

Single, Global locator

Customers that prefer to explicitly add individual system locators will see each added under the MixedRealityToolkit parent object.

Individual locators

Each of the previous illustrations show the hierarchy that will appear when using the Mixed Reality Toolkit > Configure menu. Customers are free to manually modify / build the MRTK presence in their scene(s) manually if desired.

For reference, the scene hierarchy in beta 2 is shown in the following illustration.

MRTK v2 Beta 2 locator

While the above is arguably somewhat cleaner, collapsing the new MixedRealityToolkit parent object presents a similar appearance. Additionally, adding a parent object allows for better containment of scene components added and managed by MRTK, for example spatial mesh objects.

Configuration Menu

The Mixed Reality Toolkit menu’s Configure item will be expanded to support configuring for the global system locator or individual component locators. The following image illustrates early thinking of the configuration UI.

Configuration Dialog Concept

Configuration Profiles

Existing system configuration profiles will continue to be used by the systems regardless of the chosen locator. It is expected that some minor modifications to the user interface / navigation may be required to best provide a delightful customer experience.

Examples

The following sections describe examples of how locators and services will be discovered and referenced in code.

• locator Access in Services • Service Discovery in Application Code • Data Provider Access in Application Code

locator Access in Services

When a locator loads a service, the constructor will be passed an instance of IMixedRealityServicelocator to provide access to an equivalent of beta 2’s MixedRealityToolkit.Instance property.

Data Provider Management

Through the IMixedRealityServicelocator instance, services will be able to request data provider management (register, unregister, etc.). Service Discovery in Application Code

There are two proposals for providing service access to application code to replace beta 2’s direct MixedRealityToolkit calls. For example (ex: MixedRealityToolkit.Instance.InputSystem).

Proposal 1: GetServicelocator()

One possible solution is to provide a script that is attached to the MixedRealityToolkit parent object that iterates through the scene and builds a table of locator objects and which services the manage. This table would be created by locators registering themselves at startup. Application code would then request the appropriate locator for their service(s) of interest.

Proposal 2: Script Registration of Service locator

Another proposed solution involves customers dragging the instance of the locator to a script in the inspector.

The MixedRealityToolkit would provide a generic solution that can be used or extended by customer projects. This solution would provide a mapping of service interface to locator instance. For example:

Service Interface Service locator
IMixedRealityBoundarySystem MixedRealityBoundarySystemlocator
IMixedRealityInputSystem ContosoInputSystemlocator
IMixedRealitySpatialAwarenessSystem MixedRealityToolkit
IMixedRealityTeleportSystem MixedRealityToolkit

Data Provider Access in Application Code

Access to data provider instances should be provided by the service which consumes the provider. This allows most application code to avoid needing knowledge of the locator and allows services to control when data providers are registered and unregistered.

The current (beta 2) Spatial Awareness system implementation demonstrates this pattern:

/// <summary>
/// Gets the collection of registered <see cref="IMixedRealitySpatialAwarenessObserver"/> data providers.
/// </summary>
/// <returns>
/// Read only copy of the list of registered observers.
/// </returns>
IReadOnlyList<IMixedRealitySpatialAwarenessObserver> GetObservers();
/// <summary>
/// Get the collection of registered observers of the specified type.
/// </summary>
/// <typeparam name="T">The desired spatial awareness observer type (ex: <see cref="IMixedRealitySpatialAwarenessMeshObserver"/>)</typeparam>
/// <returns>
/// Readonly copy of the list of registered observers that implement the specified type.
/// </returns>
IReadOnlyList<T> GetObservers<T>() where T : IMixedRealitySpatialAwarenessObserver;
/// <summary>
/// Get the <see cref="IMixedRealitySpatialAwarenessObserver"/> that is registered under the specified name.
/// </summary>
/// <param name="name">The friendly name of the observer.</param>
/// <returns>
/// The requested observer, or null if one cannot be found.
/// </returns>
/// <remarks>
/// If more than one observer is registered under the specified name, the first will be returned.
/// </remarks>
IMixedRealitySpatialAwarenessObserver GetObserver(string name);
/// <summary>
/// Get the observer that is registered under the specified name matching the specified type.
/// </summary>
/// <typeparam name="T">The desired spatial awareness observer type (ex: <see cref="IMixedRealitySpatialAwarenessMeshObserver"/>)</typeparam>
/// <param name="name">The friendly name of the observer.</param>
/// <returns>
/// The requested observer, or null if one cannot be found.
/// </returns>
/// <remarks>
/// If more than one observer is registered under the specified name, the first will be returned.
/// </remarks>
T GetObserver<T>(string name) where T : IMixedRealitySpatialAwarenessObserver;

After calling one of the GetObserver methods, applications are able to modify properties and control the activity of the spatial awareness observers.

hridpath commented 5 years ago

@davidkline-ms I am always causious when un-known text is used as identifiers for object recognition. Using the Friendly Name as an index into a list of objects can cause errors due to name collisions.

I would like to see if the usage of Namespaces can be impemented in the when registering and un-regestering services by name or type. This would allow for multiple implementations of a service to be alive but unique. For example having multiple controllers available to be used at the same time.

Scenario: When a student is running an application in WHMD or HoloLens an instructor may want to show the Student where to click or point them in a direction to assit in thier learning. The students could be using the Motion Controllers and the Instructor could be using an XBox One controller. Different Cursors and interaction can be defined for visuals.

i.e bool RegisterService(string "name", string "nameSpace) bool Un-RegisterService(string "name", string "nameSpace)

bool RegisterService\<T>(string "name", string "nameSpace) where\<T> = baseClass or interface bool Un-RegisterService\<T>(string "name", string "nameSpace)

bool RegisterService<T>(Type typeWithNamspace) bool Un-RegisterService\<T>(Type typeWithNamespace)

david-c-kline commented 5 years ago

@hridpath, thanks for the feedback!

StephenHodgson commented 5 years ago

I think everyone is overthinking a lot of this stuff, and there's a focus on "Scene" objects, when the fact of the matter is, none of this stuff exists in the scene.

We're working with POCO objects. Classes and structures that should (in theory) be independent from Unity as much as possible. (Let's not even talk about how adding additional GameObjects that don't really do much of anything, could impact performance).

I think taking a bigger focus on educating people how to understand and use the system would help.

Yes, this new way of doing things is very different to traditional unity developers, but I think it's counterproductive to give into the pressure of such feedback without attempting to educate people.

A bit nitpicky here with the terminology, but didn't we agree (months and months ago) that the term manager implied a single instance of something (and we ended up with system). Adding manager to the end of anything with System seems redundant, less descriptive, and more confusing.

radicalad commented 5 years ago

Just want to give a little extra context. This feedback is coming directly from partners building production HoloLens applications with MRTK.

In fact many Microsoft employees close to MRTK worked directly with them to educate and guide them. The general feedback has been services and profiles are confusing, the system feels heavy and the MRTK Singleton is very aggressive. The feedback isn’t around POCO and decoupling services from MonoBehaviors.

We’re in beta, we’ve received legitimate feedback, we shouldn’t brush it off, we should figure out how to make MRTK work better. Education/documentation is only part of the solution.

Ecnassianer commented 5 years ago

I'm a huge fan of the increased scene presence. This will help me teach the folks I work with about how MRTK works.

Railboy commented 5 years ago

Big fan of this proposal. Directly addresses some of the loudest criticism / chatter I've been hearing from folks using the toolkit. I've been an advocate of the existing approach for a while but there's no shame in accepting that it didn't get the traction we'd hoped for. Like @radicalad says, we're in beta - now's the time.

@StephenHodgson agreed that educating people should be our goal - and the best way to teach someone about a new system is to present in familiar terms. Increased scene presence for services is a win regardless of (frankly minimal) perf costs. Nobody likes to be told their ignorance is the reason something is hard to use, and who can blame them?

@davidkline-ms This is just nitpicking but I do find the names hard to look at. I feel like there's got to be a better suffix than Manager - ServiceExecutor? ServiceLocator? ServiceHandler?

david-c-kline commented 5 years ago

@davidkline-ms This is just nitpicking but I do find the names hard to look at. I feel like there's got to be a better suffix than Manager - ServiceExecutor? ServiceLocator? ServiceHandler?

While I can see that, the intent of these interfaces is to manage (load, unload, enumerate, etc) services. I'll give the interface names / service controllers (would that work?) some thought and get consensus from others before submitting any code. Hopefully the proposal's use of "manager" doesn't distract from the goal.

Also, please note that the proposal does not include removing the current approach, just augmenting it with the ability to add a system specific scene presence as well as the ability for others to easily add support for MRTK systems in their own components.

Railboy commented 5 years ago

@davidkline-ms Agreed, the names are not a dealbreaker.

StephenHodgson commented 5 years ago

The general feedback has been services and profiles are confusing, the system feels heavy and the MRTK Singleton is very aggressive.

Could we elaborate on this? There isn't much substantial objective criteria here to formulate an appropriate response.

Nobody likes to be told their ignorance is the reason something is hard to use, and who can blame them?

💯% agree, and that wasn't exactly what I was trying to say, just that I think we should give people time to get familiar with it before deciding to fundamentally change the way it all works.

It'll be interesting to see how much workflows will continue change once Unity finishes up with ECS and DOTS. Traditional Unity development pipelines are going to be fundamentally changing a lot here in the near future.

Overall I think this is a step backwards, not forwards.

david-c-kline commented 5 years ago

before deciding to fundamentally change the way it all works.

The existing MixedRealityToolkit object will remain an option. This is about providing options based on customer feedback.

paseb commented 5 years ago

The general feedback has been services and profiles are confusing, the system feels heavy and the MRTK Singleton is very aggressive.

Could we elaborate on this? There isn't much substantial objective criteria here to formulate an appropriate response.

I can very much elaborate on this one. We have an unwieldy and over-engineered set of nested profiles and a frustratingly restrictive architecture. Which basically leads to the inability for anyone to incorporate MRTK in an existing project. If I used it in a new project I would quickly run into an inflexible set of requirements that kill iteration times. In general quality in products is a function of evolutionary or iteration time steps. Ideally everything should be easily extensible and able to function as a standalone service in whatever structure a developer wants to incorporate it. Case study, use the toolkit with others at a game jam or hackathon and observe.

💯% agree, and that wasn't exactly what I was trying to say, just that I think we should give people time to get familiar with it before deciding to fundamentally change the way it all works. It'll be interesting to see how much workflows will continue change once Unity finishes up with ECS and DOTS. Traditional Unity development pipelines are going to be fundamentally changing a lot here in the near future. Overall I think this is a step backwards, not forwards.

I couldn't disagree more. The phrase "give people time to get familiar" is an indicator that it's not intuitive. It's like a level designer saying that someone is "playing it wrong" only because they designed it for their golden path. Regardless of Unity's structural changes and features, if you rely on what their "new" infrastructures are you will always be on some shaky ground until they are proven and solidified. The step to having more namespaces than the library of congress and one ring to rule them all was a larger step backwards IMO.

thanks, -pat

Railboy commented 5 years ago

@StephenHodgson If your predictions about Unity's workflow are true then maybe this is just a case of a system being slightly ahead of its time. In which case it would be best to wait for Unity to boil the frog a bit longer and revisit the issue when devs are more receptive. You can't surf a wave that's still underwater.

StephenHodgson commented 5 years ago

Option 2 adds a layer of complexity to satisfy design views of developers but doesn't degrade the overall functioning of the project.

Agreed, that's my biggest fear with this proposal.

The phrase "give people time to get familiar" is an indicator that it's not intuitive. It's like a level designer saying that someone is "playing it wrong" only because they designed it for their golden path.

Ouch, yup. You're absolutely right 🤣

StephenHodgson commented 5 years ago

One thing that I'd like to note with the service locator object, it that it's really just a manifest for all of the services that are running. It doesn't really do much of anything else, besides doing some scene setup with the event system, and camera.

I'm curious to know how this impacts everyone's thoughts on why it feels heavy handed and unweildy. The biggest problem it was trying to solve was ensuring that the object lifetimes were handled appropriately and MonoBehaviour events forwarded.

Ideally everything should be easily extensible and able to function as a standalone service in whatever structure a developer wants to incorporate it

The first part I believe to already be true, but if you could elaborate on the other structures?

Case study, use the toolkit with others at a game jam or hackathon and observe.

I wish I could have attended some, it would have been very interesting to see and learn from.

The mrtk was supposed to handle 90% of the needs, while letting the developer get that last 10%

For example: You only have 48 hours, and you'd like to create an app that does x feature.

  1. Import the mrtk.
  2. Press configure

    By this point everything should just work out of the box. No additional setup needed.

  3. Devs register their own custom service in the additional service provider profile, and iterate on that.
  4. Devs setup their scene and UI (can be done in parallel with 3)

Is there something above I missed?

StephenHodgson commented 5 years ago

I would like to see if the usage of Namespaces can be impemented in the when registering and un-regestering services by name or type. This would allow for multiple implementations of a service to be alive but unique.

Love this idea @hridpath

Cameron-Micka commented 5 years ago

The TL;DR I'm for this proposal and anything that makes our "mangers" system more Unity-like and scene accessible.

I 💯% agree for the need of system presence in the scene hierarchy. One of the reasons I believe Unity has become successful, especially among people new to game/3D development, is the accessibility of inspecting your app's state at runtime via the scene view. As it stands currently I can't really tell what state my systems are in and/or which ones are enabled without stepping though a debugger or plunging though profiles.

I also agree with @Railboy about

present in familiar terms.

A value I take into consideration when building new features in Unity is "does something akin to this featue already exist, and how can I make my feature behave as similar as possible to the way it's currently done?" When doing this you provided your users with familiarity and reduce friction when stepping into your new feature. The real win is when users can be productive right out of the gate because they have used a similar feature before.

Ecnassianer commented 5 years ago

Unity has become successful [because of] the accessibility of inspecting your app's state at runtime via the scene view. As it stands currently I can't really tell what state my systems are in and/or which ones are enabled without stepping though a debugger or plunging though profiles.

^ This

StephenHodgson commented 5 years ago

Having a visual representation of the currently running systems is good feedback, but I'm not entirely convinced that we should use the scene as a representation of said information. The scene is only for UX/UI. It's a single layer of the application that should be reactive to the business level app logic.

What about if we had another way to represent them without putting them in the scene? These services/managers don't exist in the scene in any way, nor should they (they're purely c#). I'm open to making a window that looks very similar to the scene window, with a hierarchy that shows the relationships between services, and their data models.

Let's call it the service graph

StephenHodgson commented 5 years ago

TL;DR the whole point of the re-architecture was to get away from the dependency of the MonoBehavour and the scene

These “Components” are intended to be attached to GameObjects which live in the project’s various scenes. However, this has the unfortunate side effect of making traditional patterns like MVC or MVVM impossible to use in the Unity development environment, out of the box. Instead, many developers closely couple application logic with the UI / UX logic — a practice frowned upon by many professional software engineers.

Ecnassianer commented 5 years ago

I'm open to making a window that looks very similar to the scene window, with a hierarchy that shows the relationships between services, and their data models.

That's missing the point. I'm a Unity dev, and I have an incredibly powerful debugging tool that's constantly maintained and improved by one of the most accomplished game engine development teams in the world. Let me use that tool. Don't make me go without. Don't make me use Visual Studio. Don't make me use a home brewed version of that tool that only exists in MRTK.

Ecnassianer commented 5 years ago

TL;DR the whole point of the re-architecture was to get away from the dependency of the MonoBehavour and the scene

I read that article when it came out. It felt like petting the cat backwards at the time, but I gave it a chance. I taught it to other people. I enforced it in code reviews. I wrote my own code to be in line with it.

I now believe we've pushed that philosophy too far. We have been "very aggressive" in pursuing it, as Addison said. Feedback from numerous projects has been clear. That principle cannot be our only guiding light.

Cameron-Micka commented 5 years ago

A "service graph inspector" is an interesting idea. But, I agree with @Ecnassianer why should we reinvent something that is already robust and used by many? Purely C# managers/systems don't really fit into Unity's data driven design, but I do agree they should be separate from your normal app layer/state.

In the past I've done this by keeping managers in a separate scene. This is also Unity's general guidance at the bottom of this page.

Railboy commented 5 years ago

What about if we had another way to represent them without putting them in the scene? These services/managers don't exist in the scene in any way, nor should they (they're purely c#). I'm open to making a window that looks very similar to the scene window, with a hierarchy that shows the relationships between services, and their data models.

Then your challenge is persuade us that the best response to feedback that the system is unfamiliar and unintuitive is to avoid leveraging a familiar, intuitive system that already exists. And that we ought to then duplicate parts of the existing system. And that this extra work and redundancy is necessary because representing pure C# objects as scene objects violates some kind of unstated aesthetic principle.

Not saying it's impossible but that's a tough sell.

david-c-kline commented 5 years ago

Now last question @davidkline-ms , in judging this proposal do we push back the RC for the MRTK until this is ratified and implemented (along with other likely breaking changes needed to stabilise it) or are we planning this for a RC 1.1?

The RC timing includes time much of this work. It is something the team has been discussing options on for some time.

We are definitely planning additional release candidates before we v2.final to ensure quality, stability, customer feedback and educational materials..

david-c-kline commented 5 years ago

The mrtk was supposed to handle 90% of the needs, while letting the developer get that last 10%

It does this very well for simple green field projects. What the team has learned in the past several months is that it is difficult to adapt MRTK to existing projects.

The intent here is to expand the usability and flexibility of MRTK to accommodate a wide range of projects and development styles.

StephenHodgson commented 5 years ago

Not saying it's impossible but that's a tough sell.

Indeed. Part of the problem was that it wasn't finished, nor ready for adoption, and undocumented. I know there was the pressure to have something for the HL2 launch, but I think maybe it was too much too fast.

I understand that it's a completely new way of developing and it does take some time to adjust to. I too am a Unity developer, been using it for 15 years, and I've had some very frustrating and painful learning curves along the way. The pattern is essentially a culmination of all the things I've learned along the way, and an attempt to address those pitfalls I think the engine has.

Let me pose a few questions. Consider a "drag and drop" approach where the user just takes a prefab and puts it in the scene:

There are more scenarios that that maybe I didn't think about?


Here's a reply from other MVPs that were a thoughtful responses: (I'm unable to reply to the email thread because of technical difficulties)

James:

I basically loathe the way people write Unity code. Coming from C# line-of-business development, it’s clearly a disaster. A lot of it is because of the heavy dependence on MonoBehaviour classes, which aren’t even spelled correctly, which are slow as molasses and screws up the whole object life cycle – but mostly it’s because Unity coders are horrible at writing reusable, resilient code. Unity has lots of built-in hooks to make everything accessible and it’s the wild west where all code has public accessors and anything can call anything at anytime. It’s a set of coding practices that invites abuse (actually, probably even requires it) and makes “clean code” principles almost impossible. Not to mention the horror of using coroutines instead of a nice async await pattern and calling it “threaded”. Or the prevalence of Singleton patterns that aren’t even implemented correctly. And a lot of these poor practices are ultimately built around all of these “Manager” classes that are faux singletons and accessible from anybody anywhere.

In C#, we have the notion of a service locator, which is an implementation of IoC that works well in Unity and happens to be the foundation of the new MRTK.

If you are used to having managers that you can drop into a scene in order to provide HoloLens functionality, then you may not like it as much.

But if you come from the C# app dev world and didn’t start in Unity thrown things at the wall and see what compiles and don’t worry about maintainability, then seeing traditional design patterns should come as a relief.

Dwight:

Coming from the same point of view as James, it appears in my experience that Managers are easier to use if you are a newbie to development. When teaching how to just build a MR application, there is demo code, POC/Pilot code – this is how you get it done type code, and then there is Reusable, patterns, production – secure, performant ready code. I find the later longer to develop, longer to explain, and basically for experienced developers who understand more than the game loop.

Being on a couple of projects similar to what James has expressed, I can attest to code in Unity almost infers or better yet implies Demo/POC code patterns because it’s quick, fast, compilable and easy to use, and the original MRTK was built with this in mind in my opinion. We were all learning it and it got us past Demo Code. Heck I would even say the HL was a demo product, where as HL v2 would be the true production, reliable, secure, performant product. So we must promote our learnings to production ready code now.

When explaining MR development to new developers, the steps were plop a manager in your scene, set some properties (without fully understanding them) and then watch everything work.

At the end of the day the pattern is meant to be production ready.

david-c-kline commented 5 years ago

I'm open to making a window that looks very similar to the scene window, with a hierarchy that shows the relationships between services, and their data models.

While this is a cool idea, it would present another learning curve and an additional custom window that they are required to use.

david-c-kline commented 5 years ago

this has the unfortunate side effect of making traditional patterns like MVC or MVVM impossible to use in the Unity development environment

It is the choice of the developer which patterns to use in a project. MRTK should be flexible and not limit a developer's choice of pattern.

SimonDarksideJ commented 5 years ago

Let's wind this back a little and ask the question :

what is it we are solving and what are we actually asking for?

As I'm seeing a lot of mixed metaphors used in this discussion.

From what I can see, we need:

Something which is highly performant at runtime, carving the best performance or of Unity and the .NET runtime (currently the existing architecture does this in spades ( Something I can easily inspect at design time and use familiar tools to debug / build with (which sadly the existing architecture hides due to it's focus on delivery)

Now we have to balance this with development vs runtime. In the lifetime of the project, it's going to get RUN a lot more than it's getting developed (although granted I know a lot of developers woud argue against this, but in that case you would need to ask why that is the case as it's not profitable)

So it becomes a means test against what can be introduced to assist in the design / develop cycle that doesn't impinge on the performance we've gained in the architecture.

This can be achieve by either:

There can't be a one size fits all (although option two in my list) does come close. as any design requirements should no (and should never) impact or reduce the performance of a build solution (this one one of those core reasons we went with a new architecture to solve the problems introduced by the legacy behaviour of previous Unity developments, USING unity's own advice).

So can we simply FIRST break this down to a requirements discussion before jumping headlong in to the discussion around a solution. As I've not seen enough detail on what has been asked first.

Although David's proposal does look sound from the outside, we need to understand the drivers behind that solution so we can all agree on a final approach. WHAT do we need, vs what sounds like a good idea (which has hurt us a lot in the past).

To put in to frame David's point

It is the choice of the developer which patterns to use in a project. MRTK should be flexible and not limit a developer's choice of pattern.

But that choice should not impede the ultimate goal of the solution, the delivery of a perfomant and easy to use end solution. Not to say the developers story is any less important, but it is a impactful choice and requires a developers answer on top of an architecture that works in the long run.

david-c-kline commented 5 years ago

Wouldn't shattering the service locator would essentially do the same thing?

This is not a shattering. The existing component will remain and behave the same way though some method names / signatures will likely change (ex: the name + namespace suggestion).

This is an additive change to enable developers who wish to have service specific scene objects and those who choose to add service support to existing objects.

SimonDarksideJ commented 5 years ago

@StephenHodgson has pointed out one thing, which makes sense.

It simple seems to be the ask to to make a DEVELOPER's life easier by adding another layer, which is fine. So long as in adding that we are not detracting away all the hard work to make the FINAL solution as fast as it can be

In the same way, Unity has now bent to C# as the best development solution but using IL2CPP to craft the final solution, MRTK is our current answer (in code form) for IL2CPP

david-c-kline commented 5 years ago

So long as in adding that we are not detracting away all the hard work to make the FINAL solution as fast as it can be

There is no disagreement here. Developers will choose the strategy they wish to use based on ease of consumption and performance. Every project is different and requirements will vary.

The team has spent many many long hours profiling and tuning in the past several months and is very focused on performance.

cre8ivepark commented 5 years ago

@StephenHodgson @SimonDarksideJ As David mentioned, we have been intensively using MRTK vNext for various projects for the past several months, with both internal and external partners. I believe no one has used MRTK vNext this level in the product so far. The feedback and refactoring effort is coming as common voice from various teams and partners we've been working with who are also part of the external community. Just wanted to let you know this was not rushed conclusion or request from a few internal engineers. Definitely, the goal is to make MRTK vNext easy to use and best toolkit for MR development.

ryantrem commented 5 years ago

Personally, I just want a layered approach that lets me use as much or little as I want, and I'm fine with POCO being a layer. I don't want to have to use IMixedRealityExtensionServiceManager, or a super singleton with everything on it. I want it to be easy to consume just the input system (for example) and configure it (e.g. I can use just the input system related profiles independently, and there is no special initialization code from MixedRealityToolkit that I need to duplicate). If others want to use a higher level super-component that brings in everything and ties it all together to simplify their green field project, I have no opposition to that, I just want the ability to easily consume one MRTK component at a time in my existing app, and not bring in a bunch of stuff that I'm not ready to use.

StephenHodgson commented 5 years ago

I want it to be easy to consume just the input system (for example) and configure it (e.g. I can use just the input system related profiles independently, and there is no special initialization code from MixedRealityToolkit that I need to duplicate)

I'd argue that it's already possible to do this with any/all services. The service locator is just a way to manage the instances that are created.

For example, you could in theory, create a new instance of any service in any script. Then manually call any of the public methods on them.

using Microsoft.MixedReality.Toolkit.Core.Interfaces.InputSystem;
using Microsoft.MixedReality.Toolkit.Services.InputSystem;
using UnityEngine;

public class ExampleIndependentService : MonoBehaviour
{
    private IMixedRealityInputSystem InputSystem;

    private void Awake()
    {
        InputSystem = new MixedRealityInputSystem();
        InputSystem.Initialize();
    }

    private void OnEnable()
    {
        InputSystem.Enable();
    }

    private void Update()
    {
        InputSystem.Update();
    }

    private void OnDisable()
    {
        InputSystem.Disable();
    }

    private void OnDestroy()
    {
        InputSystem.Dispose();
    }
}
keveleigh commented 5 years ago

For example, you could in theory, create a new instance of any service in any script. Then manually call any of the public methods on them.

This sounds very much like what this proposal is looking to accomplish. The difference is that this is looking to provide scripts that automatically do the public method calls, etc, for each individual system, instead of pushing that work onto the developer. The bulk of this proposal is about defining what that layer looks like, and proposing how systems can interact with that layer when there are more options than MixedRealityToolkit.Instance.

StephenHodgson commented 5 years ago

This sounds very much like what this proposal is looking to accomplish

Sounds like an anti-pattern. There's nothing there in the proposal that you couldn't already do, not to mention you'll lose the performance benefits, as well as organization, and ease of use from a programming perspective.

david-c-kline commented 5 years ago

Currently, all systems make a direct call into MixedRealityToolkit.Instance to acquire profiles and load/unload/acquire data providers. Based on that, I believe the example above will not work as written.

This proposal is attempting to preserve centralization of service registration, etc and to keep the simple service implementation pattern that we currently have.

I don't want to have to use IMixedRealityExtensionServiceManager, or a super singleton with everything on it.

@ryantrem, do you see an issue with having a feature specific manager (ex: InputSytemManager)? Is there a desire for systems to manage their own data providers, for example?

david-c-kline commented 5 years ago

ease of use from a programming perspective.

We have been hearing quite the opposite, that MRTK is not easy to use. The proposal aims to simplify usage while maintaining existing functionality for customers who wish to use current behavior.

StephenHodgson commented 5 years ago

Is there a desire for systems to manage their own data providers, for example?

That was part of the changes I was trying to get in wayyy back when.

Railboy commented 5 years ago

Sounds like an anti-pattern. There's nothing there in the proposal that you couldn't already do

@StephenHodgson You seem to be forgetting that a) this is a lot of work, and b) a precondition of doing that work is more-or-less complete knowledge of the system.

Unless your input is meant to help us modify this proposal to better address the negative feedback we've gathered then I'm not sure how it helps us. We're trying to steer the conversation back to the real flesh-and-blood chorus of users offering this feedback. But you seem uninterested those developers, or maybe distrustful of their authenticity / credentials, and you keep steering it right back towards aesthetic principles.

I'm not saying that discussion is uninteresting. It's just not terribly useful. Maybe you can move it into a broader issue discussion?

StephenHodgson commented 5 years ago

But you seem uninterested those developers, or maybe distrustful of their authenticity / credentials, and you keep steering it right back towards aesthetic principles.

I'm sorry if it comes across this way. Not my intention at all. Part of any discussion or proposal like this is to consider many different perspectives of all parties involved.

JonathanPalmerGD commented 5 years ago

Profiles are great for configuring things, but the initial configurations often don't match everyone's use case.

Improving the visibility to end users is worth substantial costs if we want our users to adopt this workflow.

It would be entirely reasonable to have the scene objects display inspectors that aid discoverability.

[Mixed Reality Toolkit Root Object] --[Input System Representation] ----"This component exists to improve discovery and only forwards events. If you wish to change the behaviors of the Input system - [Button to Profile Configuration] or adjust [Name of a few related classes] or look into [Related Interface]" --[Teleport System Representation] etc.

As a developer, getting a breadcrumb like this would be hugely helpful and would help alleviate many of the common profile-related problems I encountered and other developers relying heavily on the profile system. We can even have the component objects on each of the 'Hey this represents a system running in the background' objects be largely just documentation and inspector controls that guide developers to where they actually want to look to adjust functionality.

It's a far simpler solution than building an entire other system like the Inspector and expending resources to teach it.

StephenHodgson commented 5 years ago

getting a breadcrumb like this would be hugely helpful and would help alleviate many of the common profile-related problems I encountered and other developers relying heavily on the profile system.

Best bit of feedback I've heard. I agree, this could definitely be better. Exposing a field on each inspector with the associated service would be very helpful I think, but I'm still not sold about tying it into the scene hierarchy.

Not trying to detract from the conversation, but I felt like it was beneficial to share more feedback.

Tamas:

This is a really interesting discussion, one I have given a lot of thought in the last 2-2.5 years of using Unity. Just as James (and then many others) said, the world of many Unity apps/code is horrid to someone who comes from an enterprise world – me included. Again, just as James said – the Unity run lifecycle makes it very easy to jump in, but just as easy to write unmaintainable messes. I will admit that most of my projects starting out in Unity followed the “bigger the project, bigger the spaghetti” motto.

It took me until now-ish, to see how probably best to implement “our” best practices while not going completely head-to-head against the Unity ways of doing things. I’m currently working on a project/framework that encompasses my ideas, and I’ll be excited to show that to this community when it gets to a demoable and feels-complete state. These are the areas where I see place for improvement:

  • Scenes depend on many things (usually sadly “managers”), this hinders scene- and concern-separation efforts
  • Eventing is either Unity or C# but the two don’t mix well, and also the UI support for it is bad
  • Keeping track of things, components, dependencies is hard & requires tie-ins to the “bad” Unity lifecycle patterns
  • As soon as you do something in an enterprise-y way, Unity UI often stops being helpful (e.g. it’s not easy to keep private things private)
  • All the above makes it very hard to test and experiment on new things in an isolated way… often you can’t just create an empty scene for a new feature because it’ll depend on many things. I want this limitation to go away.

And these are the tools I’m planning to use to solve (or at least improve on) the above:

  • ScriptableObjects are awesome. Minimal tie-in to the Unity lifecycle, can be saved/seen/used project-wise
  • Custom predictable loops, abstract away the not-so-nice parts of the lifecycle (this btw can also have performance improving effects https://blogs.unity3d.com/2015/12/23/1k-update-calls/ )
  • Write tons of custom UI elements (inspectors, windows etc…) – make it as easy, or even easier to work with the custom things as it is with the built-in ones
  • Encourage concern/context separation with scenes – just as in Xaml we’d have App -> Frame -> Page -> etc… we can have Scenes that have the same responsibilities and act similarly
  • Use the newer versions of unity to embrace nameof(), async/await, pattern matching and similar nice features of C# that can help avoid ugly patterns in Unity

Well said, and I think this really hits home all the points we were trying to cover with the new architecture.

david-c-kline commented 5 years ago

Thanks all, for the lively and illuminating discussion so far!

We will definitely update MRTK (regardless of the ultimate decision on this specific proposal) per @hridpath (name + namespace) as we currently have a far too easy opportunity for accidentally registering two services with exactly the same type and name.

The team is committed to reviewing all of the feedback received so far and applying ourselves to addressing / resolving to (hopefully) a good solution for all.

david-c-kline commented 5 years ago

Can we also spend a bit of time on a couple of smaller pieces of the proposal that I have not heard feedback on yet...

  1. Proposed configuration dialog layout / options (please ignore, for now, the option on manager selection) specifically: a. Does it feel intuitive b. Does it help reinforce the additive qualities of MRTK

  2. Proposed MRTK parent object in the scene hierarchy. Note: One of the goals for this is to provide an easily collapsible node that would contain any objects created and added by MRTK, to allow developers to focus on the scene objects of most interest to them (at design and runtime).

Thanks for the continued, open feedback. It is beyond valuable.

david-c-kline commented 5 years ago

Quick note: I'll be sure to post an FYI whenever the proposal contents change. It will be updated inline.

Thanks!