CedarvilleCS / CedarLogic

CedarLogic: Free, Open Source Digital Logic Simulator
GNU General Public License v3.0
31 stars 19 forks source link

Decouple GUI & Logic #43

Open JoeHCQ1 opened 2 years ago

JoeHCQ1 commented 2 years ago

Is your feature request related to a problem? Please describe. It is difficult to test or modify (especially swap out) components that are tightly coupled. It's harder to test (speaking generally) because you have to create extensive mock-outs of the larger system to test a given component. The State of Devops reports have documented just how crippling tight coupling is to innovation and I'd refer readers to those reports starting with Accelerate. Also, I'd imagine most contributors (such as a senior design team) would prefer to focus on either the logic or the GUI, not both. So the ability to modify one largely independent of the other would be good.

Describe the solution you'd like I think, this is stretching my design skills, the first step would be to create a smaller interface between the GUI and the Logic. The particular interface I have in mind is message-based, where a message is an immutable struct, and a pair of message queues, one queue logic -> GUI and the other GUI -> logic. The Application would then maintain ownership of the queues and the GUI and Logic would each run in their own thread with no shared memory, each responding to messages and creating messages as they go. This is three threads in total. Taking a page from GoLang's design philosophy (I wish I could find the article I'm remembering), I'd prefer to communicate by sharing values rather than by sharing memory. Also related to GoLang, I prefer composition over inheritance but I don't know how much that applies to this code-base.

With a message-based interface, both sides can be easily tested and should be easier to modify without ripple effects. I expect that each side, since they maintain now separate instances of each gate, would just need to know what the ID of their gate is in the other one's world and this would be provided in the messages.

A message-based interface seems to me to also decrease the ability for someone to implicitly rely on an implementation detail that's accidentally been exposed through the interface, tightly coupling their usage of that function to the functions implementation instead of its signature.

Since queues are processed FIFO both ways, we should get much the same behavior as we do right now with a single-threaded(?) implementation. That is, I don't think this would cause any out-of-order executions because we don't have a network layer that can lose messages the way we would if these were web services.

Describe alternatives you've considered I wonder if my Design Patterns book has anything in it for me here. I own it but haven't read it much yet.

Additional context This idea is spawned by the difficulty I'm encountering trying to swap strings (which are effectively untyped and unscoped) out for class enums and other means of value transfer that can be compile-time checked and can only contain valid values (or at least the set of possible values is closer to the set of valid values). I'd also like them to work in a switch statement (requires ints or enums) instead of massive if/else-if/else {exception} blocks.

I don't like the way strings make it impossible to know if my function is logically complete (hence the else {exception} at the end) and to know what my potential values are I have to track down everywhere those strings come from and mentally simulate the program execution to know what values they can have. Enum classes I expect are going to be the solution in most cases. Anyway, if I put a message interface between the GUI and the logic, I can define the enums with the message structs, binding both GUI and logic to one header, and not requiring them to have knowledge of the other. Further, since it appears the GUI is responsible for most of the initial string usage, if there are illegal strings headed into logic we can at least make the exception rise in the GUI library so it's easier to debug instead of passing it into logic.

Also, if I didn't already mention it, if we had a message-based interface a senior design team could develop and extensively test a new (Qt?) GUI while employing existing tests to guide their development and ideally not requiring or being as inclined to make changes to the logic. This reduces the number of changes they'd need to validate. If an interface change is required, I think it'd be easier to evaluate at the message level than in the heart of the logic core. It'd also allow us to compile one version with the new GUI and one with the old.

@kshomper, didn't entirely mean to write quite so much but whenever you have time I'd be interested in your thoughts. I expect it'd be good experience to attempt this even if it doesn't work. I'd wait to merge anything along these lines until I've built quite a bit out and tested thoroughly. It's too big a change to hand-wave over and say "I think it still works :)". I can try to find the articles I've read on GoLang which are influencing my design approach.

JoeHCQ1 commented 2 years ago

As I keep thinking about this I think the first step would be to create a diagram/design that details the components to be, their comms, and once that's in hand I may be able to find a way to incrementally make the changes.

JoeHCQ1 commented 2 years ago

Right now I'm imagining four boxes, File I/O (for circuit in/out), Application (which polices the queues and simulation speed to avoid backups among other administrative tasks), GUI and Logic.

kshomper commented 2 years ago

@JoeHCQ1 we have a potential target of opportunity: this semester one of the original CedarLogic developers Ben Sprague at Cedarville as a visiting professor. Ben likely doesn't have the time to contribute to the project, but it may be profitable to run this issues comments by him to see if he has any feedback. In particular, I had thought the original division of CedarLogic into the GUI and logic components included a message-passing mechanism between the components to reduce coupling. It is possible that the simplicity of the mechanism was damaged by development by subsequent senior design teams. Ben may be willing to comment on this intent and your proposal. Do you mind if I ask him to look over your comments?

JoeHCQ1 commented 2 years ago

@kshomper yes! Please do! And you're right, I found at least some of the message passing Saturday. Never the less, some GUI code has a direct ptr to the circuit and is calling its methods instead of using klsMessage.

I will need to study the current implementation more to get a better feel for how/where to draw boundary lines and ideally I'd clarify the ones that already exist.

Also, there are some impressive bits of code in here.

JoeHCQ1 commented 2 years ago

I'll handle this objective in branch dev-v2.4. I've gotten a fair amount of the logic library rebuilt with unit testing, more to build, and more tests to write. I am building from a blank slate to help me get a better grasp of the problem we're solving, I'll see how much I just replace the existing logic code and how much I, having proven out a concept I'm interested in, just re-integrate my discoveries into the existing code base. In general, the more I discover the gotchas, the more my code looks remarkably like the code that exists.

kshomper commented 2 years ago

I spoke to Ben Sprague last week and he would be happy to take some time to talk over your work, answer any original design questions, and be a sounding board for your ideas. Also, a few months ago Ben ran some pen tests on the code base and I believe he found some vulnerabilities that he might want to discuss with you. Could you give me a few day/times over the next two weeks so I can put together a meeting to discuss these things. FYI, Ben is teaching a class for Cedarville at 3PM MWF and also labs at 9AM and 11AM on F, so meetings near those times would be more difficult. I have classes MWF at 9AM, 11AM, 1PM, and 3PM, so a TR meeting would definitely be easier for me to schedule. Finally, with both Ben and I at Cedarville it would be more convenient for you to come to us, rather than us to you (if possible). However, if that's not convenient for you, we can discuss other locations. I'm even open for a brunch or lunch meeting on TR, if that's desirable.

JoeHCQ1 commented 2 years ago

That would be fun, I'll respond more via email.