Fertogo / Pebble-workout-timer

Easily create Pebble-guided workouts from phone or computer
12 stars 6 forks source link

Check size limits #91

Closed Fertogo closed 8 years ago

Fertogo commented 8 years ago

Currently workout titles and names are limited to 40 bytes. This number was chosen arbitrarily. I need to make sure I pick a number that makes sense (based on current workouts) and enforce it on the frontend. Hopefully I can pick a number such that no mass migration of longer titles will be necessary.

Fertogo commented 8 years ago

I'll find the size limits in this issue and enforce them in #94

Fertogo commented 8 years ago

I wrote some teribly inefficient code to get information about lengths of data currently in the system. I used this information to justify my choices on max move and workout names. In both cases, values were chosen such that they would affect less than 1% of moves/workouts.

Move Data

Longest MoveNameLength: 196
Average Length: 8.401683537559936
Standard Deviation: 6.199660854834687
======= Max Value: 10 ========
Moves Affected: 26667(28.414491209376664%)
======= Max Value: 20 ========
Moves Affected: 4986(5.312733084709643%)
======= Max Value: 30 ========
Moves Affected: 1242(1.3233883857218967%)
======= Max Value: 40 ========
Moves Affected: 470(0.500799147575919%)
======= Max Value: 50 ========
Moves Affected: 206(0.2194992008524241%)
======= Max Value: 60 ========
Moves Affected: 94(0.10015982951518382%)
======= Max Value: 70 ========
Moves Affected: 28(0.029834842834310073%)

Note that with the current formatting of long moves, the Pebble can show moves of length of to 57 characters. As such, the current MOVE_NAME_SIZE of 40 is acceptable and will only affect 0.5% of moves.

Workout Data

=============================================
Longest WorkoutTitleLength: 92
Average Workout Length: 9.726221674117467
Standard Deviaton: 6.073642024226595
======= Max Value: 10 ========
Workouts Affected: 2746(42.33081547710806%)
======= Max Value: 20 ========
Workouts Affected: 396(6.10451672575921%)
======= Max Value: 30 ========
Workouts Affected: 52(0.8016032064128256%)
======= Max Value: 40 ========
Workouts Affected: 12(0.1849853553260367%)
======= Max Value: 50 ========
Workouts Affected: 6(0.09249267766301834%)
======= Max Value: 60 ========
Workouts Affected: 3(0.04624633883150917%)
======= Max Value: 70 ========
Workouts Affected: 3(0.04624633883150917%)

Note that a PebbleMenu is able to display at most 13 characters before running out of space. As such the current MAX_TITLE_SIZE of 30 is sufficient and will only affect 0.8% of moves.


In case I ever need to do this again, here is my inneficient code.

function getAverageMoveNameLength() {
    mongoose.model("User").find({}, function(err, users){
        var longestMove = "",totalMoves = 0,totalMoveLength = 0,moveLengths = [];
        var longestWorkout = "", totalWorkouts = 0, totalWorkoutLength = 0, workoutLengths = [];
        var i,j,x;
        for (i in users) {
            user = users[i];
            for (j in user.workouts) {
                workout = user.workouts[j];
                if (workout.title){
                    if (workout.title.length > longestWorkout.length) longestWorkout = workout.title;
                    totalWorkouts++;
                    totalWorkoutLength += workout.title.length;
                    workoutLengths.push(workout.title.length);
                }
                for (x in workout.moves) {
                    move = workout.moves[x];
                    if (move.name) {
                        if (move.name.length > longestMove.length) longestMove = move.name;
                        totalMoves ++;
                        totalMoveLength += move.name.length
                        moveLengths.push(move.name.length);
                    }
                }
            }
        }
        console.log("===================")
        console.log("Longest Move: " + longestMove);
        console.log("Length: " + longestMove.length);
        console.log("Average Length: " + totalMoveLength/totalMoves);
        console.log("Standard Deviaton: " + standardDeviation(moveLengths));
        console.log("Total Moves " + totalMoves);

        var testPoints = [10,20,30,40,50,60,70]
        for (i in testPoints) {
            point = testPoints[i]
            console.log("======= Max Value: "+ point + " ========")

            var movesAffected = moveLengths.filter(function(x){return x >= point}).length
            console.log("Moves Affected: " + movesAffected + "(" + (movesAffected/totalMoves)*100 + "%)")
        }

        console.log("=============================================")
        console.log("Longest Workout: " + longestWorkout);
        console.log("Length: " + longestWorkout.length);
        console.log("Average Workout Length: " + totalWorkoutLength/totalWorkouts);
        console.log("Standard Deviaton: " + standardDeviation(workoutLengths));
        console.log("Total workouts: " + totalWorkouts)

        var testPoints = [10,20,30,40,50,60,70]
        for (i in testPoints) {
            point = testPoints[i]
            console.log("======= Max Value: "+ point + " ========")
            var workoutsAffected = workoutLengths.filter(function(x){return x >= point}).length
            console.log("Workouts Affected: " + workoutsAffected + "(" + (workoutsAffected/totalWorkouts)*100 + "%)")
        }

    });
    function standardDeviation(values){
      var avg = average(values);

      var squareDiffs = values.map(function(value){
        var diff = value - avg;
        var sqrDiff = diff * diff;
        return sqrDiff;
      });

      var avgSquareDiff = average(squareDiffs);

      var stdDev = Math.sqrt(avgSquareDiff);
      return stdDev;
    }

    function average(data){
      var sum = data.reduce(function(sum, value){
        return sum + value;
      }, 0);

      var avg = sum / data.length;
      return avg;
    }
}