MicrosoftDX / nether

Building blocks for gaming on Azure
MIT License
80 stars 47 forks source link

Streamlining Nether for usage scenarios #373

Closed krist00fer closed 6 years ago

krist00fer commented 7 years ago

Game Studios like what Nether bring to the table, but struggle somewhat to know how to start using Nether, how to extend Nether and how to get benefits from updates that are provided when Nether evolves. This is a write up on some observed problems and solutions to them.

Alternative 1 – The contributor

Clone the Nether repository and start hacking away on-top of it. This approach would be beneficial for a Game Studio that want to go “all in” on what Nether has to offer and/or want to contribute to the development of Nether. You would get a working solution of Nether that is tested by someone else and that is developed and driven by the community. As Nether evolves you will get new features (that potentially could be configured to not be used) as they are incorporated and merged down your branch. If you are willing to follow the flow and just use what is there, then this approach would be good. This is currently the approach that exists in Nether. Benefits: • Full power to all source code of Nether Drawbacks: • Updates are hard • You have to use the exact tool chain that Nether is built with • No or very limited way of extending without changing the original code

Alternative 2 – Extending Nether with your logic

(not implemented) If you do like what Nether has to offer and are starting from beginning, you might be considering using Nether “as is” but extending it with plugins/mods to fit your need. This is a very good option for a Game Studio that is starting from the beginning and has no or little knowledge on selecting hosting options for a game backend. In a way, it would be very similar to Alternative 1, with a “working” solution of Nether updated by the community with updates that would be “simple” to incorporate by merging newer versions with your cloned version. Nether would have to expose extension points that could then be pluggable with little or no configuration. Conventions would be preferable to using configuration in such a scenario making it easy to extend the service by “just adding new game service logic”. Nether could expose easy extension points through interfaces that could be implemented and exposed as .NET Core Libraries (DLLs) that are later dropped into a Plugins folder. At startup Nether services would have list files in that folder and look for implemented Plugins. .NET Core provides this infrastructure with MEF 2 (Microsoft Extensibility Framework), but has not yet implemented all functionality in MEF 1. This means that the resolving of Assembly dependencies need to be handled manually. AssemblyLoadContext is the new file in .NET Core that provides similar capabilities to AppDomains in .NET (except for the isolation capabilities) and could be used to load assemblies dynamically. ` [ImportMany] public static IEnumerable< Nether.Analytics.IGameEventsHandler > GameEventHandlers { get; set; }

static void Setup() { var files = Directory.GetFiles(path, "*.dll", searchOption); var assemblyNames = files.Select(AssemblyLoadContext.GetAssemblyName); var assemblies = assemblyNames .Select(AssemblyLoadContext.Default.LoadFromAssemblyName) .ToList();

config = configuration.WithAssemblies(assemblies, conventions); using (var container = config.CreateContainer()) { GameEventHandlers = container.GetExports(); } } ` The above sample code doesn’t include code to resolve dependencies of loaded assemblies, something that can be handled by catching the Resolving Event on the AssemblyLoadContext instance. For this alternative to work, Nether would have to expose “most” of its code as pluggable by defining interfaces for almost every part. If no plugin is found that replaces or extends an interface, Nether should fall back to the native implementation, thereby also providing the same benefits as alternative 1 above. In this alternative Nether could be distributed as precompiled binaries. Benefits: • Easy ability to extend Nether with custom logic • Updates to Nether will be “easy” to consume. Drawbacks: • Need to have a working environment to compile and/or run Nether, since it’s provided as is with extension points. • If you have your own backend, want to host additional services or host the backend in a way not supported out of the box then you may run into trouble and need to tweak source code and will have issues with updates later on. • Nether Developers need to think about extensibility points while developing Nether.

Alternative 3 – Extending your game services with Nether

(not implemented) If you already started development of your backend or have somewhat different demands on the hosting alternatives provided by Nether, then you would want to extend your own backend with Nether, rather than the other way around. In the .NET Community the most obvious way of doing this would be by using NuGet Packages together with a flexible and pluggable implementation of Nether. To start with, this alternative would be the most flexible but could also be combined with Alternative 2 (and thereby 1) above, providing both an out of the box experience, but also the ability to cherry-pick features in Nether that provide value to you. Consider the following scenario: • Game Studio have started working on an API for their game and have currently implemented login and user management to save state of their players. • They want to have an API for leaderboards and a solution for Analytics and like what Nether has to offer. • Picks correct ARM template to deloy infrastructure for Nether.API.Leaderboard and deploys • They already have a ASP.NET Web API and executes: o install-package Nether.API.Leaderboard • In their Startup.cs, they include code similar to: services.AddNetherLeaderboard(… configuration …)

• Game Studio also have a background processing job (perhaps hosted in Service Fabric) that would be perfect to consume GameEvents for the analytics pipeline. In that project they execute:

o install-package Nether.Analytics.GameEventProcessor • In their Program.cs (or similar) they would create and start the Nether Game Event Processor using code similar to ` var netherHost = new NetherAnalyticsHost(… configuration…); netherHost.ResolveEventType += ResolveEventType; netherHost.UnknownEventType += HandleUnknownEventType; netherHost.RunAndBlock();

` • NetherHost class would then provide Events and/or abstract methods to catch and/or override in order to extend and tweak the default behavior. • Even plugin support could be used to tweak the default behavior of NetherHost by implementing interfaces that defines plugins and handing them over to the NetherHost, either by configuration or by convention. Any updated done to Nether would then come as updates on NuGet.

• Done! Their backend has now been enriched with a Leaderboard API. In order to develop Nether we would have to have an implementation of such a WebAPI with all provided features, that is basically what already exists and will give the same benefits as Alternative 1 above. Benefits: • You start with your backend and can customize everything • Updates to Nether will be easy to consume since they are distributed as NuGet packages • Extensible. I can extend anything very much like I use other libraries out there. • I don’t need a working environment to compile or run Nether. Everything runs in my own environment. • Possible for Nether to support more than one platform (both .NET Framework and .NET Core, etc.) • Done right you could also have alternative 1 and alternative 2 included in this, since Nether development still need a working environment to test everything “as is”. • Nether falls into the normal usage pattern for using other’s framework in .NET development Drawbacks: • Limited or no drawback to end user. • Nether Developers need to think about extensibility points while developing Nether.

stuartleeks commented 7 years ago

@krist00fer - these are proposed solutions, but I'm not sure I fully understand the problem/requirements. What are the outcomes that we want to enable? What aspects should be customisable and how? (e.g. adding new reports, adding validation logic for scores, ...)

krist00fer commented 7 years ago

@stuartleeks Preferably anything should be customizable, but let’s start with analytics as a starting point. The partners we’ve been talking to all think they’ll send other kind of events that are outside of the GameEvents that we’ve designed. Also, they’ve talked about “enriching” the events differently than the way we do and perhaps putting the result somewhere differently. Some others want to ignore some events or parts of the analytics pipeline and leave that out of the equation. So for EventProcessor we are talking about:

Analytics and customizations

Feedback is that user of Nether might not understand exactly what information they want or need from the game client up front and that it might change over time. So the need to tweak the analytics pipeline (without losing the value of Nether) is very much needed. Continuing down the Analytics Pipeline, we’ll need to think about a very customizable solution where Nether provides reports/output for “known event types” handled the “normal way”, but also expect that users of Nether will have a lot of custom solutions on top of this. For example, ADF might by default register a few jobs, that creates the default output for the “known event types” but we should support and encourage custom implementations side by side. Some outputs are valuable for almost everyone, some outputs only computable if the correct events are sent and some events and/or outputs doesn’t make sense at all for some games. So “big data jobs” need to be very selectively deployed and expect other “jobs” to be around.

Other Nether API and customizations

Going to the other APIs that we provide we know that almost no game will use Nether as is. There is always the need to add one more API or just see Nether as another API that we wanted to add to something that already exists. Yes, we could see this as a Micro Service Architecture where Nether is just one (or many) Micro Services. But what if Nether is almost all that I want, if it just had one more feature. Or what if I already have all that I want if I could just have Leaderboards and what if I’ve already decided on an architecture go with and what if… As soon as you start tweaking the direct source code of Nether you get into those problems that I described before. So, some examples for the Nether APIs that would be lovely to have (all taken from real life):

A lot of above could be fixed with additional configuration and conditions in Nether, but a pluggable architecture and/or a solution where Nether could be adapted to an existing solution seems like the way forward.

None of the examples or solutions provided above are in anyway prioritized or investigated how hard they would be to implement, which is something that need to be done. Sample “spike solutions” has been made for some of the suggested solutions though.