-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Split EDDI project into EddiCore and EddiApp #1781
Comments
I started splitting the DLLs.
Probably not the right moment, but this whole work would be a no brainer if we had a Dependency Injection framework in place. |
Fair points.
|
About the monitor vs responder for updating the UI, are you implying that other parts of the application do read the state from the (e.g.) squadron tab of the app UI? My assumption was that some monitor (journal?) would get the original event, hand it to the EDDI object, and then all the responders would get notified and do whatever they need to do. I also assumed that any other part of the app would get any necessary state from the EDDI object, not from the app UI. |
No. Global state is as you see it in EDDI.cs. It's not tangled up in the front end UI thank goodness. I'm referring to the private async void OnEvent(Event @event)
{
// We send the event to all monitors to ensure that their info is up-to-date
// All changes to state must be handled here, so this must be synchronous
passToMonitorPreHandlers(@event);
// Now we pass the data to the responders to process asynchronously, waiting for all to complete
// Responders must not change global states.
await passToRespondersAsync(@event);
// We also pass the event to all active monitors in case they have asynchronous follow-on work, waiting for all to complete
await passToMonitorPostHandlersAsync(@event);
} In the case of squadrons, there is a global state variable in EDDI.cs called "SquadronStarSystem". I think it would be appropriate to update that variable with a PreHandler from a Monitor, before the value is passed to responders like the Speech Responder or the VoiceAttack Responder. |
Apologies I wasn't clear :) I was referring to code like the following (line 2241-> 2249 from EDDI.cs) // Update the squadron UI data
Application.Current?.Dispatcher?.Invoke(() =>
{
if (Application.Current?.MainWindow != null)
{
((MainWindow)Application.Current.MainWindow).eddiSquadronNameText.Text = theEvent.name;
((MainWindow)Application.Current.MainWindow).squadronRankDropDown.SelectedItem = rank.localizedName;
}
}); The code above is sandwiched between other instructions that do update the EDDI state, while this appears to me to be just updating the UI and could be handled by having a responder in the MainWindow code. I am aware I have very little knowledge of the codebase, so I'd appreciate if you could point out what I am missing 😃 |
Agreed, the highlighted code ought to be moved. The section immediately below the section you highlighted // Update the commander object, if it exists
if (Cmdr != null)
{
Cmdr.squadronname = theEvent.name;
Cmdr.squadronrank = rank;
} updates a global state. Since updating global states needs to happen before responders act on those global states, I think that it would be appropriate to consider a "Commander Monitor", with the UI for the commander tab being updated from that monitor, rather than a "Commander Responder". |
It occurs to me that there may be a simpler approach. We could set up two way bindings between the UI elements you identified and the |
WRT the Monitor/Responder dichotomy, my understanding was that monitors wait on external events (e.g. new journal entries) and create internal events, while responders act on internal events and perform application actions. About the 2-way bindings, is it implemented by the following functions (from CargoMonitor)? public void EnableConfigBinding(MainWindow configWindow)
{
configWindow.Dispatcher.Invoke(() => { BindingOperations.EnableCollectionSynchronization(inventory, inventoryLock); });
}
public void DisableConfigBinding(MainWindow configWindow)
{
configWindow.Dispatcher.Invoke(() => { BindingOperations.DisableCollectionSynchronization(inventory); });
} |
Yes, As for Monitors and Responders... your understanding is generally correct... new data typically comes in through either a monitor rather than through a responder. Many monitors, however, also play a critical role in managing state data (e.g. the Cargo monitor, the Shipyard monitor, the Material monitor). Both monitors and responders act on events and the timing of those actions is important. Monitors act first to pre-handle events and set states. Then responders then act to handle events referencing those global states. Finally, monitors post-handle the events as required. Example:
|
So, if I get this correctly, Monitors and Responders are quite a different concept from Producers and Consumers of events. They actually represent stages of event processing: Monitor:PreHandle --> Responder:Handle --> Monitor:PostHandle. |
Correct. A monitor can be a producer but isn't necessarily so. |
Erroneously closed. |
Certainly my first impression with this codebase is that two large libraries 'Utilities' and 'DataDefinitions' have a whole host of sub dependencies/requirements such as RollBar UI and Mathlib. Breaking these large libraries into smaller chunks would then mean that consuming code projects are not encumbered by the restrictions of those 3rd part externals. ie. anything that wants DataDefintions needs MathLib when only one class 'StarClass' uses that library. My experience is that libraries with vauge names involving words like core/common/util often contain a hodge-podge of functionaility often unrelated to each other. Also separating the XAML code from functional code is a good idea. |
'Utilities' and 'DataDefinitions' are stable, well-defined and have low churn. We are happy with the structure there and that they represent a sensible separation of concerns for our use case. Everything is going to depend on RollBar because it is our crash and logging telemetry. Everything is going to depend on MathLib because, well, we need to do math. Thank you for the input but we are not going to restructure a well-working project based on purely doctrinal principles. |
I propose to split the "EDDI" project into:
Rationale:
This re-jig allows "EddiApp" to depend upon all code-generating projects, so that having "EddiApp" as the startup project means that good old F5 once again works to build everything necessary before debugging.
Code impact:
The text was updated successfully, but these errors were encountered: