For a high-level overview of what The Pool Cloud is, check out this blog post. It’s an app that lets pool-care enthusiasts create their own “recipes” for pool maintenance and share them with the world. This is a technical assessment of a few problems encountered when designing such an app. Read at your own risk:
Chemical calculations for swimming pools are tricky, and there are several different balancing methods for calculating the necessary chemicals and their dosages. In “The Pool Cloud”, I am attempting to create a framework where passionate pool owners can create their own recipes for pool care and share them with the world.
Each method involves taking several chemical readings (Free Chlorine, pH, Total Alkalinity, Cyanuric Acid, etc…) and then, based on those readings, applying several chemical treatments to the water (x ounces of 67% calcium hypochlorite, y ounces of sodium bicarbonate, z ounces of cyanuric acid).
This yields an interesting design problem regarding the structure of these custom methods. I’ve made some slightly less-ambitious attempts to solve this problem in the past by writing the calculations myself, but it simply does not scale, and the result is a remarkably mediocre compromise. Perhaps the most interesting aspect of this approach was storing “effect” objects in the database.
Effect objects were important because some chemical treatments affect multiple chemical readings. For instance, adding “sodium carbonate” to a swimming pool will raise BOTH the Total Alkalinity and the pH, and it will raise them by different amounts. So, the “sodium carbonate” treatment object has 2 effect objects (1 for TA and 1 for pH). I have attempted to store these effects in a very simple object, with a single numerical value representing the amount of chemical treatment necessary to raise the associated reading by “1” in a 10,000 gallon pool. This multiplier is a useful abstraction, but it is not entirely correct.
The “multiplier” approach has 2 fundamental flaws: it assumes that all effects are linear, and it does not take into account how different readings affect the performance of the treatment. Through a series of compromises, I addressed these problems in an informal way in the design of Pool Doctor. This approach made a lot of sense when I was writing 100% of the calculations myself. However, there will be no such compromises in The Pool Cloud. I want to empower other people to describe their own solutions to this problem, and the problems themselves are complicated. So, I will not hold them to my simplified mathematical model; I need to allow them the maximum amount of flexibility to solve their problems as they choose.
The design of The Pool Cloud is simple: power-users will be able to create their own “recipe” for pool care. This recipe includes information about how often to treat the pool and several formulas for chemical calculations. The recipe will define a list of readings to take, and the formulas will assume all the readings have been taken. The recipe will then have a list of EVERY POSSIBLE chemical treatment necessary, and an associated formula for calculating the amount of each treatment. If no treatment is necessary, the formula should simply return 0.
This still isn’t a perfect solution for several reasons. It’s more complex for the power-users to figure all that out, but only a very small minority of human beings care enough to try and create their own recipe, and the ones that do will want complete control and don’t mind a learning curve.
It also does not allow for chemical substitutions (for instance, if the recipe was for 67% calcium hypochlorite, but the pool owner has 60% calcium hypochlorite or a completely different chemical). In order to account for that type of problem, I would need to create very, very complex “effect” objects that were related to multiple readings and essentially stored formulas of their own based on different readings. That would quickly become unmaintainable and create another decision for the normal users (which chemicals are you using?). Of course, with my proposed method, it’s inconvenient that the app requires a new recipe for different concentrations of the same chemical, but it’s also much easier for the normal users when the app just says “do this.” I’m not entirely convinced that this is the correct approach here, but for the sake of ever actually developing this app, I’m going to move forward with the decision and revisit it later.
Lastly, this fails when it comes to investigative readings. For instance, you might want to say “If the free chlorine is waaaaaay off, then take these other 2 readings as well.” With this system, you would have to either take the other 2 readings every time or none of the time. It’s also worth pointing out that sometimes, people will take basic readings several times per day and then, maybe once a day or every other day, they will take a more exhaustive list of readings. This will require several formulas to be written for each treatment for each possible list of readings, which is not ideal by any means, but… whatever.
This solution is not perfect, and it involves many trade-offs. However, it forces recipes to be very actionable for normal users, and it gives the recipe creators maximum control. This is just one small piece of the overall framework, but it is the lifeblood of the app, and it’s never been attempted before (not like this). The implementation of recipes is absolutely crucial to the success of The Pool Cloud.