Remote 1: Action Models#453
Conversation
| // Created by Bill Gestrich on 12/25/22. | ||
| // Copyright © 2022 LoopKit Authors. All rights reserved. | ||
| // | ||
|
|
There was a problem hiding this comment.
Similar to RemoteCommand. But the associated types are specific to each command. This is in LoopKit as these models will be shared by Caregiver.
| public var description: String { | ||
| return "\(actionName) \(actionDetails)" | ||
| } | ||
|
|
There was a problem hiding this comment.
These are not used yet but helpful for Remote 2.0
| } | ||
| } | ||
|
|
||
| extension RemoteBolusAction { |
There was a problem hiding this comment.
Putting the validation logic needed to enact an action, in the action itself. I wrestled with keeping this logic in Loop instead, but I kind of like keeping the validation logic with the model.
There was a problem hiding this comment.
Why are these in LoopKit at all? If it's for sharing types with plugins, maybe that would be necessary. If it's for sharing types between Loop and LCG, maybe pause on that for now, and keep them separate. Human input validation (LCG-only concern), network decoding and validation, and Loop's other validation concerns (like max bolus, max temp), are all separate things. Guessing there might be other differences in concerns between them that might make the types different too. Maybe Loop wants to have a received time?
There was a problem hiding this comment.
If these types are strictly for representing a Swift version of the network encoding of these actions, then I guess that could be a shared concern.
There was a problem hiding this comment.
I think I'm following the suggested separation here. These models are to include all the information needed to enact an action in Loop. For remote 2.0, they will be used for the network encoding/decoding both from the plugins and Caregiver.
I can move the validation pieces out of here and put into the Loop target. That does leave the question of where to put these things to keep them unit testable as they are. Making an extension, like here, keeps it testable without involving the DeviceDataManager test setup or dedicated validation structures for each action (i.e. RemoteBolusValidator..). My inclination is to move the extensions to the actions to the Loop target to provide some separation. But I can consider a validator or wrapping these actions into Loop domain actions if something more dedicated is desired. Note that in remote 2.0, the plan is for a RemoteCommand to hold onto a RemoteAction and other things like the RemoteCommandState.
There was a problem hiding this comment.
For context, here is where I was planning to take things in remote 2.0 wrt actions. The RemoteCommand holds onto the action. Everything else in the RemoteCommand is specific to command management and lifecycle.
Rather than juggling a separate hook to the service that generated the command, the RemoteCommand itself has methods to interact with its service internally.. ex: RemoteCommand.markSuccess() rather than service.markSuccess(command)
public protocol RemoteCommand {
var id: String {get}
var action: RemoteAction {get}
var status: RemoteCommandStatus {get}
/*
TODO: Should we support "future" commands?
TODO: Should the expiration date be in here?
TODO: Should creationDate be in here?
*/
func checkValidity() throws
func markInProgress() async throws
func markError(_ error: Error) async throws
func markSuccess() async throws
}
There was a problem hiding this comment.
I think moving them to Loop sounds good. Yes, you will have a similar type in LCG, with similar fields, but I think this is one case where it's ok to avoid DRY. The responsibilities and things you will do with those types are going to be different.
Thanks for the context on eventual plans of wrapping RemoteAction with RemoteCommand. What do you think about RemoteAction -> Action? If a RemoteCommand has an action, the "remote" part can be implicit (if "actions" are things that could theoretically be triggered locally, by, say, a siri command), or could be namespaced by RemoteCommand (if they are not things that could be reused locally).
There was a problem hiding this comment.
I think making the Actions decoupled from the remote aspect makes sense. I've dropped the Remote verbiage from actions for now.
9b6d5a1 to
335082e
Compare
| var actionName: String { | ||
| switch self { | ||
| case .carbsEntry: | ||
| return "Carb Entry" |
There was a problem hiding this comment.
Are these user displayed names? Localization?
| } | ||
| } | ||
|
|
||
| extension RemoteBolusAction { |
There was a problem hiding this comment.
Why are these in LoopKit at all? If it's for sharing types with plugins, maybe that would be necessary. If it's for sharing types between Loop and LCG, maybe pause on that for now, and keep them separate. Human input validation (LCG-only concern), network decoding and validation, and Loop's other validation concerns (like max bolus, max temp), are all separate things. Guessing there might be other differences in concerns between them that might make the types different too. Maybe Loop wants to have a received time?
| } | ||
| } | ||
|
|
||
| extension RemoteBolusAction { |
There was a problem hiding this comment.
If these types are strictly for representing a Swift version of the network encoding of these actions, then I guess that could be a shared concern.
| switch self { | ||
| case .carbsEntry: | ||
| return "Carb Entry" | ||
| return NSLocalizedString("Carb Entry", comment: "Carb entry action name") |
There was a problem hiding this comment.
So this will lookup the string in the app bundle, not the LoopKit bundle. LocalizedString exists to let you look up strings in LoopKit. Not an issue if this moves into Loop. Also, I think I saw that this string is being combined with other (non-localized) strings?
There was a problem hiding this comment.
I ended up dropping these strings for now in these pull requests but will keep these comments in mind in the future PRs where I may add back.
|
Updates done - I think I responded to all the feedback but let me know if other questions. |
…t#453) * extended bolus automatic to DoseActivationSource * naming update * refactor
|
I still feel like sharing a model here is not great. There are going to be (at least) the following representations of these models:
Decisions like whether to use I know if probably feels like a violation of DRY to be repeating these models in two places, but it does seem to me like they are separate domains, that if not already, will sometime have different concerns, or want some flexibility. This is just my opinion, and I needed to share it, I don't think this change will hurt Loop in a big way, and will not block on this if you really think it's the right way, or you really want to go this route for some reason. |
|
@ps2 I can understand the concerns about reusing these models in Remote 2.0 for decoding the payload. I'll keep that in mind for the upcoming Remote 2.0 PRs that introduce decoding. Let me add a 5th item to the list that seems important to put in context with all of this:
While I added this as a 5th item, I feel this actually should be a further description on number 1 and should not be replicated, as this feels like the same domain (unlike decoding and such). I think my RemoteActions in this PR serve that role. I think the upcoming PRs will add a lot of clarity when we get to domains 2-4. |
|
Yes, the Loop <-> Plugin interface is a shared domain, for sure and LoopKit is currently that kind of thing lives, so I'll merge this. Thanks! |
|
@ps2 Thanks - The next one I suggest reviewing/merging is this one here for the Loop repo LoopKit/Loop#1930 |
This will migrate away from the RemoteCommand type to the RemoteAction type.
See Loop PR for more details LoopKit/Loop#1930
Unit Tests
I added new unit tests to check that action validation is enforced.