2

Please feel free to suggest a better name or way of explaining this question - I wasn't quite sure what to call it.

The situation is one that may just come under the heading of "be organized" but I often find myself passing around either big blobs of data or many smaller sub-blobs (blob in the non-technical meaning of the word =o), to be used in various parts of my web apps.

For example, building a small task manager that allows someone to create a task that ends up being represented like this:

  • With a title, initial date, user, client, etc. (simple attributes).
  • Zero or more temporal expressions that represent "schedules" for when the task must be done - periodically, by day of week, by day of month, etc.
  • A tree-list of sub-tasks that can be nested to any level.

This is all easy enough to represent in the database with a few tables.

It's also easy enough to pack into a series of arrays and pass around (for example, passing an array of a task template, subtasks, and schedule data via JSON to a jQuery object that will build a tasklist on the client side.

Between creating, updating, displaying, etc., the tasks, tasklists, etc., there are any number of places where I might find myself passing a big collection of data from one place to another (especially working with AJAX with much client-side processing), and it often looks pretty much the same - just a big array that says "here is the data for your task and related 'stuff'".

How do you (or would you) keep this organized? For example, below is an array that has been pulled out of a "Task Template" object, and will be passed via JSON to a JS object that will dynamically build and display a list of tasks on the client side.

I guess the question is whether and how you define the structure of such an 'object' outside the database, code, etc., and how you document it.

For example, while the nested subtasks are pretty explanatory (and duplicate data, available only for convenience), it's not readily apparent that the "SubTasks" array MUST have each subtask appear in the array AFTER (higher index than) it's parent subtask, and BEFORE (ie: with lower index than) any child subtasks, so that they arra can be processed in order with the assurance that each subtask can be appended to it's already existing parent subtask.

There are a number of rules like that here, and if a "relatively" similar array is used in 9 different places, documenting in comments/class documentation, etc sort of ends up sucking.

 [43] => Array
    (
        [Meta] => Array
            (
                [SubTaskCount] => 6
                [TemporalExpressionCount] => 3
                [NumInstances] => 0
                [OutOfSync] => 0
            )

        [Fields] => Array
            (
                [UserID] => 1
                [ClientID] => 1
                [StatusID] => 1
                [Title] => Keep Testing
                [Body] => How are you?  Because I am a potato.
                [UserName] => Wheatley
                [ClientName] => Wheatley Laboratories
                [BodyHTML] => Etc.
            )

        [Sched] => Array
            (
                [TemporalExpressions] => Array
                    (
                        [0] => Array // Every Monday every month
                            (
                                [type] => dw
                                [ExpressionID] => 1
                                [ord] => 0
                                [day] => 1
                                [month] => 0
                            )

                        [1] => Array  // Every Tuesday every month
                            (
                                [type] => dw
                                [ExpressionID] => 2
                                [ord] => 0
                                [day] => 3
                                [month] => 0
                            )

                        [2] => Array  // The last of every month
                            (
                                [type] => dm
                                [ExpressionID] => 3
                                [day] => -1
                                [month] => 0
                            )

                    )

                [TaskInstances] => Array
                    (
                       // This would have data on "complete" status of tasks by date...
                    )

                [InitialDate] => 2011-12-02
                [DueTime] => 14:55:00
                [SchedDates] => Array
                    (
                        [1322812800] => 2011-12-02
                        [1323072000] => 2011-12-05
                        [1323244800] => 2011-12-07
                        [1323417600] => 2011-12-09
                        [1323676800] => 2011-12-12
                        // ... List of dates between externally defined date range parameters...
                    )

            )

        [SubTasks] => Array
            (
                [1355] => Array
                    (
                        [SubTaskID] => 1355
                        [ParentST] => 
                        [RootT] => 43
                        [UserID] => 1
                        [Title] => New Subtask Title
                        [Body] => 
                        [DueDiff] => 0
                        [UserName] => Eli
                    )

                [1356] => Array
                    (
                        [SubTaskID] => 1356
                        [ParentST] => 1355
                        [RootT] => 43
                        [UserID] => 1
                        [Title] => New Subtask Title
                        [Body] => 
                        [DueDiff] => 0
                        [UserName] => Eli
                    )

                [1357] => Array
                    (
                        [SubTaskID] => 1357
                        [ParentST] => 1355
                        [RootT] => 43
                        [UserID] => 1
                        [Title] => New Subtask Title
                        [Body] => 
                        [DueDiff] => 0
                        [UserName] => Eli
                    )

                [1358] => Array
                    (
                        [SubTaskID] => 1358
                        [ParentST] => 1355
                        [RootT] => 43
                        [UserID] => 1
                        [Title] => New Subtask Title
                        [Body] => 
                        [DueDiff] => 0
                        [UserName] => Eli
                    )

                [1359] => Array
                    (
                        [SubTaskID] => 1359
                        [ParentST] => 
                        [RootT] => 43
                        [UserID] => 1
                        [Title] => New Subtask Title
                        [Body] => 
                        [DueDiff] => 0
                        [UserName] => Eli
                    )

                [1360] => Array
                    (
                        [SubTaskID] => 1360
                        [ParentST] => 
                        [RootT] => 43
                        [UserID] => 1
                        [Title] => New Subtask Title
                        [Body] => 
                        [DueDiff] => 0
                        [UserName] => Eli
                    )

            )

        [SubTasksNested] => Array
            (
                [1360] => Array
                    (
                        [SubTaskID] => 1360
                        [ParentST] => 
                        [RootT] => 43
                        [UserID] => 1
                        [Title] => New Subtask Title
                        [Body] => 
                        [DueDiff] => 0
                        [UserName] => Eli
                    )

                [1359] => Array
                    (
                        [SubTaskID] => 1359
                        [ParentST] => 
                        [RootT] => 43
                        [UserID] => 1
                        [Title] => New Subtask Title
                        [Body] => 
                        [DueDiff] => 0
                        [UserName] => Eli
                    )

                [1355] => Array
                    (
                        [SubTaskID] => 1355
                        [ParentST] => 
                        [RootT] => 43
                        [UserID] => 1
                        [Title] => New Subtask Title
                        [Body] => 
                        [DueDiff] => 0
                        [UserName] => Eli
                        [SubTasks] => Array
                            (
                                [1358] => Array
                                    (
                                        [SubTaskID] => 1358
                                        [ParentST] => 1355
                                        [RootT] => 43
                                        [UserID] => 1
                                        [Title] => New Subtask Title
                                        [Body] => 
                                        [DueDiff] => 0
                                        [UserName] => Eli
                                    )

                                [1357] => Array
                                    (
                                        [SubTaskID] => 1357
                                        [ParentST] => 1355
                                        [RootT] => 43
                                        [UserID] => 1
                                        [Title] => New Subtask Title
                                        [Body] => 
                                        [DueDiff] => 0
                                        [UserName] => Eli
                                    )

                                [1356] => Array
                                    (
                                        [SubTaskID] => 1356
                                        [ParentST] => 1355
                                        [RootT] => 43
                                        [UserID] => 1
                                        [Title] => New Subtask Title
                                        [Body] => 
                                        [DueDiff] => 0
                                        [UserName] => Eli
                                    )

                            )

                    )

            )

        [TemplateID] => 43
    )
3
  • What language is this? With something like Django, at least the data is encapsulated in classes within the application itself. Or is the problem you're getting at the loss of encapsulation at the presentation layer (the JavaScript, JQuery, AJAX...)? Commented Dec 2, 2011 at 0:21
  • On the server side, it's a PHP array pulled from a 'task' class, on the client side it's a js data object (part of one) read by a list interface (js/jQuery). It really could be any language or set of languages, though.
    – Eli
    Commented Dec 2, 2011 at 0:28
  • "sort of ends up sucking" Unhelpful. What's wrong with what you've got? Multiple representation of data are a long-standing, standard, common ubiquitous problem. Saying "blob in the non-technical meaning of the word =o" isn't helpful. It doesn't clarify your problem, or what would constitute a "solution" to the unstated problem. What can't you do? There are numerous -- perhaps innumerable -- equivalent representations for the same data. What is your actual problem?
    – S.Lott
    Commented Dec 2, 2011 at 1:27

1 Answer 1

1

Object-oriented classes are the answer. Classes' fields are strongly defined (i.e. a Foo instance must have bar, baz fields) and class code can enforce (and indirectly document) data constraints (i.e. the constructor can refuse bad construction parameters).

Often, serialization is then harder, but that's an unavoidable trade-off; associative arrays are trivially serializable because of their simplicity; OO-style classes often cannot be trivially serialized.

4
  • What's an 'OO-oriented class'? What other types of classes are there?
    – herby
    Commented Dec 2, 2011 at 12:38
  • Your question answers itself if you write it as "what other classes of classes are there?" :-p Granted, I know no other meaning in CS, but I wanted to stress OO, as, for instance, C-style structs do not allow easy construction-time restriction enforcement.
    – alex
    Commented Dec 2, 2011 at 13:17
  • Form: What I wanted to stress out is that someone who uses term 'OO-oriented classes' looks like a 13-year-old kid who just read his first book about OO and now wants to evangelize the rest of the world (not that you are be one, but the term is suggesting that way). Content: I'd oppose that objects (and restriction-enforcing constructors) are the answer. It can be answer in a monolithic environment. But if you pass data around between client written in JS and server written in PHP or whatever, and it can pass it along to something else, you need data, not the constructors for each language.
    – herby
    Commented Dec 2, 2011 at 13:44
  • This doesn't seem like it really addresses the question...
    – Eli
    Commented Dec 2, 2011 at 14:59

Not the answer you're looking for? Browse other questions tagged or ask your own question.