• Too Much PHP (unregistered)

    Smells like that backend service was implemented in PHP. Because of the dain-bramaged way PHP swirls arrays and hashes together into a single data structure that offers the worst of both worlds, any numerically-keyed "array" with a missing index will serialize to this.

  • Anonymous (unregistered) in reply to Too Much PHP

    Don't just blindly blame PHP for this. The backend can be PHP, but would still be poorly coded. That backend code has to do things to end up with arrays starting with an index of the string "1". Generally just fetching an array of orders from a database will not get you this type of "hashmap array".

  • Tim Ward (unregistered)

    Well, yes, a random gratuitous change to just one usage out of thousands of a particular data structure is going to get rejected, isn't it.

    Why TF did he think he was given the same code? Possibly because:

    (1) they knew it was so weird that he would work it out for himself (2) they wanted him to do what he was told.

    By now I hope he has worked out that the way to get a system-wide improvement touching hundreds of source files is to fill in a ticket and argue it through the prioritisation processes.

  • Tim Ward (unregistered) in reply to Tim Ward


  • (nodebb)

    Ahh, I see that the sample customer was the production company of Car Talk on NPR.

  • WilliamF (unregistered)

    Reminds me a bit of my first job out of university. I was working on a system using IBM UniData “post-relational” DB whose lineage was this total parallel universe to relational DBs and C-family languages. The “arrays” in that system were actually delimited strings. They had an index operator, but it was O(N). I wrote a lot of quadratic code before I figured it out. Had a knock-down drag-out argument with the lead programmer over the meaning of the word “array” in programming, which I did not win. But I did adjust my coding style to tokenize the strings correctly.

  • (nodebb)

    " write lots of weird while constructs to traverse the hash" - And thus violated DRY, SRP and a host of other design principles.... There should have been ONE implementation of code that worked around the "unusual" pattern (not to mention the problem that will ensue if the integers ever change to not be sequential and incrementing)

  • my name is missing (unregistered)

    I worked at a place with multiple implementations of linked lists (in C) all in the same codebase, and oddly enough they had hybridized into new ones as previous programmers mixed up the functions. Apparently there had originally been several cliques in the original team that refused to share code.

  • (nodebb)
            "**1**": "customer/55/orders/**1**",
            "**2**": "customer/55/orders/**2**",
            "**8**": "customer/55/orders/**12**"

    I'm very curious what's going on inside that ellipsis.

  • (nodebb) in reply to jkshapiro

    I'm very curious what's going on inside that ellipsis.

    I think that's obvious... five more orders with numbers between 2 and 12.

    My bigger question is "why return the REST API url of the order". The order should have simply been and order ID, order header data, entire order object, or some other bit of data that makes sense in the context of "an array of orders". The idea of how to retrieve those orders from the back-end should be part of some other service.

    I actually (sort of) understand embedding the url in the case where 500 customers are doing related calls. This way you can easily communicate when the API structure changes. But if you need to tell yourself this sort of thing, then something big is broken.

  • Airdrik (unregistered) in reply to jkshapiro

    I noticed that as well. My first thought with the whole "using hashes with numeric keys as arrays is an anti-pattern" is that I've seen recommendations for CRDTs which explicitly recommend doing this and reserving arrays for effectively immutable tuples; such that arrays are employed when you have a fixed sequence which is always transferred or updated in its entirety, while numeric-key hashes are employed for an array-like thing where you expect to be able to transfer or update subsets of the data. This allows you to update some subset using a PATCH (or patch-like) operation with e.g. {"234": {"new": "value", "for": "item": "at_index": 234}, "235": {...}, "237": {...}} to update just those keys without having to separately specify which keys or what subset of the array you're updating.

    However, the fact that the item at "index" "8" references something which looks like it has an id of 12 tampers with this theory and suggests that it really is just an array and that the hash keys don't really mean anything.
    Unless they do actually serve some other function; in which case (much like how an id represented as an integer may look like an integer but in practice should never be treated like an integer) it only looks superficially like an array being represented as a hash and really is actually a hash and should be treated like a hash and not an array.

    So, TRWTF here is that he's complaining about a design decision that he doesn't fully understand yet. Needs more context to really justify as a WTF. (well, there's also the whole: just follow the pattern; we're not explaining why that's necessary (because it's obvious - except it isn't, really))

  • Head Scratcher (unregistered)

    A reason for this type of a structure might be that they wanted to: 1) sequentially advance across sorted keys in O(n) instead of paying O(nlogn)/O(nk) to sort the keys. 2) Wanted to access known keys in O(1). 3) Really wild guess: wanted to be able to access proximate orders in O(1). 4) Needed to be able to print this all in JSON.

    But.... because all the keys are sequential then I guess it just boils down to using an array.

    The weird part is the enforcement of sequential IDs and yet missing numbers in the directory-style text. A simple example of a way this may be possible is: I make 8 orders. I update the 8th order 4 times. I've only got 8 orders, hence the 8 keys, but for posterity's sake, the previous versions have been stored in the wherever-that-link-goes-to place. Where things start to get messy is when you want to create a new order (order #9) and it gets labeled in the system as 13. So much for the neatness of each customer having their own set of IDs (vs global order IDs)!

  • The Shadow (doesn't) Knows (unregistered)

    So why is it "such an awkward way to iterate across an array"?

  • asdf (unregistered)

    If you like hash arrays, you're going to love Lua.

  • (nodebb) in reply to Nutster

    Man I loved that show. In fact, for a while I listened to its reruns without even realizing it was reruns, and it was after one of the brothers already passed away. It was definitely weird when I found out about the passing the same day I listened to another episode. Definitely the only worthy show on NPR in the history of all those stations.

  • (nodebb) in reply to Airdrik

    Guys, that snippet is a redacted version of the actual output. Obviously the ids and names were changed to protect the innocent. Thus, they're irrelevant to the conversation.

    The URLs are a WTF, and so is the hash array. I also don't like the naming scheme with underscores.

    Addendum 2021-07-19 12:59: Starting at 1 is another WTF.

  • (nodebb)

    They could replace the while loop with

    for (var i in cust.orders) {
      //do stuff with cust.orders[i]

    This will actually work properly for both arrays and objects, although JS experts avoid this syntax for arrays. Also Object.values(cust.orders).forEach(...) will work.

    Addendum 2021-07-19 13:01: Neither of these is dependent on the starting index being 0 or 1.

  • Anon (unregistered)

    I was going to say "oh this reeks of PHP" but looks like someone else beat me to it! Instead, I'm going to have to point out that part of the WTF here is that Javascript enables this, because "1" == 1.

  • (nodebb) in reply to Jaime

    My bigger question is "why return the REST API url of the order". The order should have simply been and order ID, order header data, entire order object, or some other bit of data that makes sense in the context of "an array of orders". The idea of how to retrieve those orders from the back-end should be part of some other service.

    Shipping the URL as part of the per-item summary data makes a load of sense (it's good REST style). Providing just the URL is very silly. Providing the other metadata in another “array” (or several) would also be very silly, and an indication that someone's really done something horrible.

  • Tanuj Rathore (unregistered)
    Comment held for moderation.
  • TAR86 (unregistered)

    Remy, I'm somewhat disappointed. Isn't "Orray" the better name (see https://stackoverflow.com/questions/51239521/what-is-the-name-of-the-anti-pattern-of-using-a-js-object-dictionary-map-to-impl), following your earlier "Arrject" (https://thedailywtf.com/articles/arrject)?

  • gnasher729 (unregistered)

    I encountered an API with a truly bizarre bug: To return a number of records, like “records 101 to 200”, it wouldn’t return an array, but managed to create a map with (as an example) the number of items ordered as the key. So if your records had 2, 7, 6, 2, 5 and 7 items ordered, one of the records with 2 and with 7 items ordered were dropped. A public API, so no chance to change it.

    Requesting 100 records was pointless because only maybe 20 would be returned. The numbers used were slightly larger so requesting 20 items usually ha a few duplicates and would return 16 or 17 records. To download all 10,000 records, I downloaded them in groups of 20, then figured out the missing records and download them individually.

  • fbartho (unregistered)
    Comment held for moderation.
  • Simon (unregistered) in reply to my name is missing
    Comment held for moderation.

Leave a comment on “The Hash Array”

Log In or post as a guest

Replying to comment #:

« Return to Article