Looking for a solution to "Dishwasher At Work" - resource-management

I am looking for an algorithm to apply to the "dishwasher at work" problem.
While it is great to be able to put dirty coffee cups etc. in it, you quickly run into the "what is the state of the dishes?" dilemma. If you walk up to the kitchen, can you take dishes from the dishwasher because they are clean and just not put away? Can you put a dirty dish in the dishwasher or will that invalidate the clean dishes in it?
It seems like a problem that must have a programming equivalent. You have a shared process that is triggered asynchronously and moves objects from one state to another. You need to be able to know the state of the objects at any given time. What algorithms can be applied?
My starting option is to create a flip flag on the dishwasher of "clean" and "dirty". When the dishwasher is emptied, it must be switched to "dirty", when it is run it must be switched to "clean". Are there problems with that algorithm? Is there a better/less error prone one?
Note: No algorithms that utilizes a polling schedule, please...

The main issue in your problem occurs when a User thread wants to place a dirty Dish in an otherwise clean dishwasher.
The solution is simple. Create another Dishwasher object.
One Dishwasher holds the dirty dishes, awaiting to clean them, the other holds the recently cleaned dishes.
When the Dishwasher holding the clean dishes is empty, start cleaning the dirty dishes in the other Dishwasher.
At this point, User threads can now put dirty dishes in what used to be the clean Dishwasher (which is now empty).
Continue alternating the roles of the two Dishwashers indefinitely. User threads can always drop off a dirty dish without the need for a KitchenCounterBuffer.
Note: This solution does not solve the cup-starvation problem. User threads still might block awaiting for a dishwasher to finish cleaning.
Note2: In constrained environments where Dishwasher is a singleton, provide a KitchenCounterBuffer as well as a DishwasherOperator to put away dishes and place dirty dishes from the KitchenCounterBuffer to the Dishwasher. The KitchenCounterBuffer then takes the role of the dirty Dishwasher in the algorithm above. However, this might cause User threads to throw exceptions or die.

Not programming related but it may help answer your logic question... My dishwasher has a "Clean" light that comes on when you run the washer. The light stays on if you just open the door for a short time (i.e. to take out a clean cup) but goes off if you keep the door open for a longer time (enough time to empty the washer.)
It's not perfect, but it's much more reliable than a flag on the front that must be flipped by a (somewhat forgetful) human.

I am assuming that all the objects in the dishwasher must be clean or dirty, but not mix and match. The solution below enforces that property. If not, you analogy wasn't quite right.
Just a few mutexes should do the trick.
You have four states.
Dishwasher empty, you can put dirty dishes
Dishwasher dirty, you can put dirty dishes
Dishwasher running, you cannot put dirty dishes or remove clean ones.
Dishwasher clean, you cannot put dirty dishes and can remove clean ones.
You can further collapse empty and dirty together, since you do not care about the difference.
When a you want to insert something, you wait on DirtyMutex
When you want to start washing, you wait on DirtyMutex so that you don't waste water ;)
When washing is over, you signal CleanMutex
When you want to empty the dishwasher, you wait on CleanMutex
When the dishwasher is empty, you signal DirtyMutex
This assumes you can know when the dishwasher is empty, if not, you'll need a counting semaphore for ElementsInDishwasher that you wait on before signaling DirtyMutex.

I like your analogy, but the underlying problem worries me. In my experience, a well-designed system always knows (usually implicitly) the kind of state that you're referring to. For example, a resource in a shared resource queue is available for use by other processes -- if it weren't, it wouldn't be in the queue. Or, a resource being modified by a worker thread is in whatever state the thread's processing says it's in -- more importantly, no other thread needs to know whether it's "clean" or "dirty".
There's a mind-boggling number of valid design patterns that I haven't encountered (or invented :-) yet, but what you're describing has the hint of a design smell (or dirty dishes) rather than a valid pattern.

Maybe Finite State Machine fits the problem you want to solve?

just make a rule to always remove the clean dishes from the dishwasher, so anything that is in = dirty and you can add more

See, this is the problem with procedural thinking. It turns everything into a batch process, and that doesn't play well in an asynchronous, event-driven world. You need to start worrying about state, threading, race conditions, persistence, etc.
A solution that avoids these issues would be to make all dishes immutable. If you need a dirty dish, you would simply create a new instance with dirt in it.
If getting a clean copy of a dish was a common operation (which sounds like the case in your situation), you could add an .AsClean() method to your Dish object, which would automatically return a clean clone for you. If performance became a bottleneck, this could be optimized by returning this if the instance was already clean.
Of course, this assumes that you're in an environment with reasonable heap space and automatic garbage collection.

I've seen commercial dishwashers that send dishes on a conveyor through a tunnel. You put dirty dishes into the racks on the left. You take clean dishes from the racks on the right. The clean / dirty state of an individual dish corresponds to its physical location within the machine.
This is a completely different architecture. With a standard dishwasher you think of "clean / dirty" as an attribute of the dishwasher. "Clean" means "contains no dirty dishes." With the conveyor dishwasher, "clean / dirty" is not an attribute of the dishwasher.
You may not want to switch to this architecture, but if you do, consider a series of processing objects connected by concurrent blocking queues. A dish goes into the pre-rinser, comes out, goes into the washer, comes out, goes into the dryer, and comes out the end.

You only need a single flag, as you indicated (clean/dirty). Dishwashers generally provide this mechanism already: a (physical) lock.
Dishwasher starts empty, unlocked
Dishwasher is unlocked, so dirty dishes may be put into it
Before running the dishwasher, it is locked
After running, it is still locked, indicating everything inside is dirty
If you remove something from it, and it's not the last item, you relock it
In a software sense, the lock is only on being able to put dishes into the dishwasher -- you'd know if a dish being removed is clean or dirty based on whether it's locked or not, but can only put a dish in if it's unlocked. If you take the last dish, you unlock it.

A simple solution to this is maintaining invariants that are always true. An example of such a set of invariants can be:
If the dishwasher is empty/not completely full - all the dishes are dirty
If the dishwasher is full - then all the dishes are clean.
It is the job of the object which interact with the dishwasher to keep these invariants in order. If someone adds a cup to the dishwasher and that makes it full, he must also turn it on so that the next person who comes around will find that the dishwasher is full and all the cups are clean.

Can you have the dishwasher eject its dishes automatically, at the end of its wash-cycle?
This is similar to Mark Lutton's idea, amd analogous to pushing cleaned dishes onto a (perhaps temporary) queue of known-clean dishes, from which they can be dequeued.

It's a design problem resulted from the use of a decaying technology - By updating a part of your design, to a more advanced form, you can get rid of the entire problem and save time, water and energy.
Use eatable plates?

Simple solution to this is maintaining invariants that are always true. An example of such a set of invariants can be:
If the dishwasher is empty/not completely full - all the dishes are dirty
If the dishwasher is full - then all the dishes are clean.
It is the job of the object which interact with the dishwasher to keep these invariants in order. If someone adds a cup to the dishwasher and that makes it full, he must also turn it on so that the next person who comes around will find that the dishwasher is full and all the cups are clean.

Related

What's the best way to code an app in which objects must interact with each other in complicated ways?

I am interested in a general approach, not a particular library or framework.
I am trying to avoid spaghetti-code-ish conditionals when possible. It may be that I'm thinking of these apps in totally the wrong way, but I can't seem to find anything online that's helpful.
The problems arise when there are multiple sorts of states that all affect each other. Here's an example:
Image a Person that has these abilities:
Walk.
Run.
Sit.
I make a command pattern with Walk.execute(), Run.execute() and Sit.execute(). These commands are triggered by user input or whatever. What's great about this, of course, is that if running needs to be debugged or amended, it's easy to know where to look in the code base.
Now I'm asked to add a dog. The dog can...
Walk.
Run.
Sleep.
If the person is walking and the dog is running, the dog (being on a leash) will run slower than he will if he's running on his own. And if the dog is sleeping, the person will sit for longer than he normally does. In other words, the dog and the person are affected by each other.
Then I'm asked to add a refrigerator with food in it. The fridge affects the dog and person, because the amount they eat affects their energy for running, etc.
I am continually asked to tweak this system. "Please make the dog run sleep more, but only if he and the person have been walking and the fridge is almost empty." And then, later: "Please change it so that the amount the person has run has walked has no affect on the dog's sleep."
I want to avoid packing DogSleep with tons of conditionals, and I also want to avoid DogSleepIfDogAndManHaveBeenWalkingAndFridgeIsAlmostEmpty. That's not scalable.
At any time, we might want to rip the fridge out of the system. Or we might want to change it in some fundamental or subtle ways.
A more real-life example is a media player that can be displayed as a compact player, an expanded player (say one that takes up half of your screen) and a full-screen player. So there are those three screen states.
Meanwhile, the player could be displaying an image, video or text.
If it's displaying a video, that video could be playing, paused, completed, etc.
The state of the video affects the way the different screen states render. The type of media also affects the rendering. And the screen state affects things the other objects (e.g. maybe, for whatever reason, you're supposed to be able to pause a video when the player is compact but not when it's expanded or in full screen).
What is the best way to make multiple state systems interact with each other when those interactions are complex and flow in both (or multiple) directions? How can one organize such code so that it's easiest to debug and scale?
The primary way to manage complexity in complex systems is to find analogies and concepts in the real world upon which you can base your design and implementation. So, when you talk about people, dogs and refrigerators interacting in some system you base methods of interaction on the way these entries interact in the real world - which is largely autonomously based on sensed inputs and internal interests/goals/needs. When you talk about media players and images and text then finding the analogies is more difficult but just as important.

In Pacman do the ghosts choose paths independently for finding pacman?

So I have been playing a lot of pacman on my cell lately and am wondering how do the ghosts seem to work independent of each other. I was thinking about how it would have been programmed.
One option that I thought of was threads. All 4 ghosts are running in their own threads and somehow find pacman's position. But it seems a bit to much to have four threads working and syncing would be hard. Also, google wrote pacman in Javascript which doesn't support threads, so it can be done without threads and there has to be an easier way.
My second thought was event handlers. I just wire the 'directionChanged' event that pacman will fire to 4 event handlers, one for each ghost. Each ghost then decides what path to take to get to pacman. This I think is more likely what is happening. But it can get slow if the event handlers are synchronously executed, because paths will have to be calculated sequentially and the 4th ghost will take time to change direction and this might create a visible lag (probably). Also, the ghosts would fire an event themselves when they hit a wall and their event handlers would change the ghosts direction. But given the frequency with which pacman changes directions and the four ghosts respond, event handlers also seem a bit too much.
I am saying the above ideas would be a bit too much because remember the game was written 30 years ago when cpu time and memory were scarce, so I think there has to be a much easier way.
Also, it seems that the ghosts are following different paths even when pacman is still. Do all the ghosts use completely different or differently optimized path finding algorithms?
I am more interested in finding out how all the ghosts seem to work for themselves simultaneously than the path finding algorithms they use. Thoughts?
There's a lot of great information about how pacman works here including some detailed write ups about the ghosts behavior.
**Note I found this information from Pathfinding Algorithm For Pacman a while ago.
EDIT:
This blog post has even more information about the ghosts.
You're drastically over-thinking this.
Threads and event-handlers are terribly slow by video game standards. Multi-threaded game engines are a relatively new invention, literally decades after Pacman was released. Pacman's meager logic will occur inside a single fairly tight loop, something like this very simplified pseudocode:
while (!pacman_dead) {
foreach ghost {
if (ghost has hit a wall) {
if (pacman to left) turn left
if (pacman to right) turn right
} else {
go straight
if (ghost touched pacman) {
pacman_dead = true
}
}
}
handle_input();
move_pacman();
draw_screen();
}
This is a fairly common pattern in gaming, and it gives the appearance of concurrence. Typically a game will run in a single loop, which advances the game state by some tiny increment in the space between screen redraws. This is why performance is still very important in game development: Your game must iterate over every in-game object which needs to do something or make some decision (AI-controlled opponents, moving platforms, simple animations, etc) and update their state at least 30 times per second.
Before rendering each frame, I would loop over the ghosts. No events, threads, or async issues that way. Each ghost probably has a very crude heuristic for scoring its moves and making up its mind (turning left or right, no action, whatev).
Here's an implementation you could check out. :)

Is "You break it, you buy it" the best policy?

There is a subtle reason why it might not be good: Sometimes, the blame for breaking something really should be placed on the individual who wrote fragile code without automated tests, not the one who broke their code by making a should-be-unrelated change somewhere else.
One imaginable example is when someone programs against an interface in a way that assumes behavior specific to the implementation du jour, but not guaranteed by existing contracts. Then someone else makes a change to the implementation that fits in the contract, but breaks the depended-on code. No tests fail because no tests are written for the depended-on code. Who's really to blame?
The purpose of this isn't to blame people, but to understand responsibilities, and if "You break it, you buy it" is really such a good policy.
EDIT: I really worded this poorly. I meant it to be about how to write correct software with respect to dependencies, including hidden dependencies. I meant this to be a question of what a programmer's responsibility is to avoid bugs, not what to do when a surprise bug is found. BUT, since so many answers have been given already, I'll let the question stand as-is and indicate an answer accordingly.
I think you have nothing to gain and everything to lose by promoting an atmosphere of blaming and finger pointing. When something is broken, you should assign it to the best person to fix the problem, whether that is the last person to touch that area because he or she knows the area, or to the person who wrote it first so knows the design philosophy best, or even just the person without anything more pressing to do.
"You break it, you buy it" makes sense in terms of breaking builds, not more serious problems.
If you put the build into a state where it can't compile, or run basic tests, you are blocking other people's work. If you can't see a quick and simple fix (because you introduced a quick and simple bug) then just roll back your changes (perhaps with local copies of what you'd worked on in the meantime) and commit.
If the fact that you broke the build is ultimately due to a wider issue, then deal with that wider issue, whether by fixing it, reporting it, or assigning it.
Short term, the person who made the code-base unworkable quickly makes it workable again. Long term, the best person for the job (balancing different factors) does the job.
Fixing it is the purpose not laying the blame. Suppose the orginal author of the fragile code has moved on, who would own the problem? Suppose he or she is simply assigned to another project? The person who ran into the problem needs to be the one who owns it until it is fixed, he or she is the person currently there and currently assigned to the task of making changes to the application.
Now if you know the code was created with a problem that should be avoided in the future and the orginal developer is still there, it would be a good thing to let him or her know about the issue and why it caused a problem, but ultimately the person who ran into the problem is the one who will need to fix it to get his new code to work.
I would say that assigning ownership to the disaster prone may not always be the most productive strategy. It is likely its own reward.
The last person to touch it should be at fault, Refactoring is a large part of software development, if somebody touched the code and did not properly document, write and test the code than that is on them. As part of the estimate, the time to properly put the code in better shape than it was found should be included.
That being said, if something does not work, the whole team should take the fall.
In an environment where people have to work together, cooperation should be of greater importance than placing blame. If someone`s module is fragile and if his/her peers agree that something should be done about it, a good team-player would fix the problem; that is, he would write unit tests .etc
In any case, a programmer's own code is ultimately their responsibility, and if they can't handle the responsibility of making their code cooperate with that of others, then they rightfully must take the blame. But not before giving them a chance or two to clean up their act.

What are some techniques for understanding object interaction

When starting a new application what are some ways to decide what objects you will need, what they should do, and how they should interact with each other?
Is this a job for a white board, or is it easier to just start coding and move stuff around as needed?
CRC Cards, or Class-Responsibility-Collaboration Cards, are a good way to do this - see the Wikipedia page.
They're a good way to brainstorm (as a team or just by yourself) which classes you'll needed, what each class will be responsible for, and how they'll interact with each other.
You might want to try:
CRC Cards
The cards will help define the object, its responsibilities, and its collaborations.
There's an entire process that you go through when creating the CRC cards. That process defines the rules that help make each class concise and really only perform the operations it needs.
This should fall more or less 'naturally' from the requirements.
Do you have a solid understanding of what the app is supposed to do, its scope, et al?
It really depends on what the size of the project is you're talking about: the approach and rigor one must apply is different for a team building commercial software than a personal project.
That said, some general tips are:
1) On your medium of choice (I like whiteboards) start enumerating the use cases or user stories. Keep going until you feel like you've gotten the most important/encompassing 80% covered.
2) When you're satisfied that you have the "WHAT" (use cases) succinctly and more-or-less sufficiently defined, you can start working out the "HOW" (objects, algorithms, et al). I would suggest a bias towards less complexity: you do not want a complicated and multi-layered object hierarchy unless you really, really need it (and even then, you probably don't).
3) I tend to enforce a "no-coding" rule until #1 and #2 are done, throw-away prototypes or explorations of particular approaches notwithstanding. It's very very easy to start slinging code and discover you're "trapped" by the object model you came up with before you fully understood what it is you're building.
4) Once you're done with your requirements gathering you can use any # of approaches to start breaking out functional units/objects/roles/etc. CRC cards are one approach; I've also had success with UML class & sequence diagrams.
I personally like to do lots of whiteboarding in UML; I take pictures with a digital camera frequently to archive thinking/approaches. These are much better than nothing when it comes to poor-man's documentation or answering the question "why did/didn't we..." 2 months down the road.
I think the answer depends on a couple of factors:
what is the size of the project? For a small project it's fairly easy to have a good idea of the three or four objects that might be required and just start coding. For bigger projects it's important to start listing them beforehand so that you can develop good object names and hierarchy.
how many people are on the project? If there is more than just you, you should sit down and plan who is going to be working on what and that requires a list of the classes that are going to be needed.
For anything bigger than a small (one or two day) project, it's worth putting some time into design before you start coding. White boards are fine for this but make sure you take a picture when you're done!
Sequence and class diagrams. These go a long way when your in design. The last thing you want to do, unless you aren't constrained in terms of time & resources, is just start coding.
Probably best to start on a whiteboard or some design overview. It all depends on what your application needs to do really. Figure out what actions your application needs to do. Associate objects accordingly with the methods you come up after breaking your application down into appropriate pieces.

What is the "Fountain Development Model"?

It is mentioned on the Systems Development Life Cycle page on Wikipedia:
To manage this, a number of system development life cycle (SDLC) models have been created: waterfall, fountain, spiral, build and fix, rapid prototyping, incremental, and synchronize and stabilize.
I found a few things on Google, but I felt that they were vague and they just didn't click for me. Perhaps an explanation from someone here might be more clear.
Fountain: Stand in a circle and throw some patterns and key words in the air to see where they land. Pick up only the ones that land inside the circle. Repeat until cancelled.
Waterfall: Wrangle everyone into a boat, then yell "Geronimo!" while going over Niagra Falls. Pick up the shattered pieces then rinse and repeat. Make sure it's well documented what part of the boat each individual should be sitting in, what they should be holding on to, how loud to yell, and exactly where they should land. See form 3684-B for additional instructions.
Spiral: Pick one team member and have everyone else spin them around in circles until dizy.
Build and Fix: Just throw it against the wall to see what sticks. If something falls off add some duct tape. Used gum may also work. Any part that won't stay stuck, just throw away.
Rapid Prototyping: Do exactly what the client asked for. Repeat until they figure out what they want.
Incremental: Only build the parts you want to, and only when you want to do it. An alternate version is to only build the parts they scream loudest for, and only when they are actually standing at your desk waiting for it.
Synchronize and Stabilize: Like Spiral except only one person at a time spins the unlucky team member. When their turn is over, stop the spinning for a moment.
Waterfall is a model that enforces control and avoids parallelism; every requirement for a task has to be fulfilled before starting the task. Fountain says that a new task can be started before all requirements are met, because not all requirements are necessary at the start of the task.
Think of this: Super Mario Game,
Waterfall: first, design everything, then get hardware done (Hardware Team), then create some test sprites, then code the engine, then create artwork, then music and finish.
Fountain: while the hardware team is doing its job, artwork starts conceptual work, and coding starts some prototyping on preexisting hw. When artists and hw finishes, coders integrate these onto their code and continue 'til finishing the game...
As I understand it, they essentially contain the same steps but a fountain approach is much more iterative, with less focus on initial design and more on analysis.
You basically bodge your way through things. See what needs to happen, and improve it. See what needs to happen. Improve it.
It's more agile but at the cost of project stability. Waterfall is a lot better for large projects.