Javascript – How to explore a deeply nested object structure more easily

javascript

An example to show what I mean exploring a deeply nested object structure.

This is a real code I deal with today (it is vue but that is irrelevant to my question)

data() { 
    return {
        customer: {},
        settings: [],
        task: {},
        ...
        }
}

I read the code several times to find out the customer is created by spread operator to combine some objects returned from 2 REST api calls!!! The same goes to task & settings.

Object Literal and spread operator makes creating deeply nested object very easy. But from time to time I have to read the code several times to find out "where did I get that property" or "why nobody tells me this object has such such property (normally deeply nested)". So is there anyway to help me explore what properties customer has when I see customer: {} ?

Requiring the original author to write a thorough document is much easier to say than done. The same goes to setting a hard rule like no more than 3 nested levels.

BTW, my question is not about how to access deeply nest object and avoid the error "Cannot read property 'foo' of undefined"

Using an example from "Accessing Nested Objects in JavaScript").

user = {
    id: 101,
    email: 'jack@dev.com',
    personalInfo: {
        name: 'Jack',
        address: {
            line1: 'westwish st',
            city: 'wallas',
            state: 'WX'
        }
    }

After all there are some best practices to access the nested object, e.g. How can I access and process nested objects, arrays or JSON? or I can use lodash get

So my question is is there any recommended way(s) to make working with deeply nested object less painful, in general and javascript in particular?

——– update ——–

When I said "Requiring the original author to write a thorough document is much easier to say than done." There are couple of reasons except for the obvious one that the original author may not have time/resource/energy to do that.

The other reasons (happen to me a lot) include, the original author has quit the job or there are more than one designers to this data structure and the latecomers added something that turned to be totally unnecessary because they didn't understand the original design in the first place. I am sure anyone who inherits a legacy system can relate to that.

And in javascript world a legacy system can mean something developed in 2018!

Best Answer

Several comments mostly touch on this answer, but I believe it is a complete answer to the question and I am posting it as such.

Complexity isn't always avoidable

Object Literal and spread operator makes creating deeply nested object very easy. But from time to time I have to read the code several times to find out "where did I get that property" or "why nobody tells me this object has such such property (normally deeply nested)"

To some degree, this is a problem of your own making. You've nested a lot of separate objects, and now you're struggling to juggle all these objects and keep track of their overall structure.
Note that by "you", I am assuming I'm talking to the designer of the structure. The next chapter addresses what to do when you are not the designer of the structure.

You need to strike a balance in how much you separate your data in different objects. On either extreme, it becomes problematic. When not separated enough, objects become a big blob of properties which leads to a bulky dataset lacking in logical categorization. When overly separated, the excessive categorization created a mind maze of the nested levels you must traverse to find your figurative pot of gold at the end.

Like with most things, the best solution is found in the middle, where you try to minimize both issues as best as you can. But in some cases, it's just not possible to sufficiently avoid both issues at the same time.

Taking a personal example of a customer who wanted to perform one web request once every 6 months, which would contain the entire logistical planning for the entire company's workforce for the coming 6 months, including custom logic patterns per order and full staff scheduling, there is simply no way to design an input JSON file that is not massive or convoluted. The posed scenario (one request to solve it all) made it impossible to avoid.

Similarly, you may be in a situation where the complexity is inherent to the posed use case, and then you can't really avoid it.


Consumers rely on designers

Requiring the original author to write a thorough document is much easier to say than done.

If you are consuming a structure developed by someone else, without them having documented it, you are essentially at the mercy of how they chose to design the structure.
This can indeed become a guessing game which sometimes throws you curve balls, but there is no efficient way for you to solve this, other than spurring on the original creator to document their creation.


Strong typing

So my question is is there any recommended way(s) to make working with deeply nested object less painful, in general and javascript in particular?

Object Literal and spread operator makes creating deeply nested object very easy. But from time to time I have to [..] to find out [..] "why nobody tells me this object has such such property (normally deeply nested)"

The main language feature you're looking for that helps drive down the complexity of development is called strong typing. Javascript is a weakly typed language by design.

Having a strongly typed language makes it easier for the IDE to fact-check your code and confirm that you are accessing properties and methods that actually exist. This also expands the abilities of your Intellisense, which is a tremendous help in ensuring that you reference the correct properties/methods and don't need to remember their exact spelling by heart.

Some IDEs have an Intellisense which can still judge the usage of a given Javascript variable to infer which properties can reasonably be expected to exist; but it's an estimate which doesn't always account for all fringe cases and is wholly incapable of inferring structures beyond its scope (e.g. JSON received from an external source).

The easiest way to alleviate your problems is to switch over to Typescript. Technically, Typescript doesn't actually provide strong typing, but it does provide static typing and a more robust OOP system (classes/interfaces), both of which will lead to a much improved experience in terms of knowing which properties/methods you can find on any given variable.
Typescript will get compiled into Javascript, which means your application can run in the exact same environment as if you'd been developing in JS directly. You can think of Typescript as a "typesafe space" for development.

Related Topic