Moved from RemoteGuiProtocols
On the rare occasion I've been allowed to replace a web app with a rich client app, I still keep (most of) the data manipulation on the server, generally using SOAP/Web services. The user-facing application is still a regular binary with a regular interface and thus has all of the control that I need to provide the user with the features that they want. I don't pull the GUI definition from the server (although I guess I could, at least up to a point... hmmm...), and I absolutely don't pull application logic from there, but all data is sourced from and acted upon there. On the other hand, stuff like re-sorting a listbox doesn't take a round-trip and I do that totally on the client. A particular benefit of using a rich client is that it becomes reasonable to store much larger data sets in your client - don't try working with 5000 element lists in JavaScript. Just parsing the JS to build the list in the first place takes a noticable amount of time. -- ChrisMellon?
Sounds like a typical mid 90s client/server app. Not that old==bad. But a 5000-element display list perhaps may need a revisit. Nobody is going to read 5000 elements. Thus, perhaps some kind of QueryByExample should be explored. However, I agree that some customers just like giant lists from spreadsheet habits or whatever.
It's exactly like a client/server app, since that's what it is. The "modern" way of sticking everything on the web sucks, because the web wasn't designed for that sort of interactivity and it really contrains what is practical to do. Note that I didn't say a 5000 element *display* list, I said a 5000 element list. In the specific case, it was a find-as-you-type list of product codes. Round-trip query per keystroke is too slow to be practical. Loading entire dataset in JavaScript is impractical. Caching dataset in a compiled client application was very practical. -- ChrisMellon?
- Interestingly, 5000 element display lists happens to be quite trivial for GUIs these days; indeed, both Aqua and X11 rely on server-side data structures which typically contains many more than 5000 entities to visit. True, it might not be structured as a list, but even as a tree, that's a lot of nodes to visit. --Samuel A. Falvo II
- Agreed, the practical max seems to have increased since this was written. Our users got new dual-core machines, and things that used to be sluggish now hum right along. But use of mobile browsers (like iPhone) is also increasing, so using desktops as the benchmark may have issues. Sometimes its the lowest-common denominator that generate the most help-desk tickets.
In that case, I think I would opt for a pop-up window to help find the item using something more sophisticated than a single giant list. For example, alphabetic buttons that narrow down the choices to a given letter in the alphabet and/or QueryByExample. If it is used often, then perhaps you are right that it should be cached client-side somehow instead of loaded per lookup. Still, a singular list is often problematic beyond about 300 items from a user interface standpoint in my experience regardless of where it is stored. -- top
Subsequent arguments and misunderstanding removed for sake of clarity. Important outcomes follow:
- "...Live filtering against a large dataset ... is impractical in a web client." -- ChrisMellon?
- "...A web client, due to very reasonable limitations, makes many GUI features awkward to implement and use. Native ("real") applications don't have these problems." -- ChrisMellon?
Of course:
- "The amount of RAM available to a browser is about the same as that available to a C/S app. Loading giant lists to either one is YellowAlert either way. As a rough rule of thumb, it should generally only be done for commonly-used look-ups, such as more than once per average 5-minute interval per user, and perhaps less if the data is updated frequently. I assume that a parts list is not changed that often. Further, some kind of QueryByExample functionality should probably be included anyhow, because one may not always know the correct part number and need to search them by other factors on occasion, such as title and vendor." -- top
But:
- "This constrains your ability to present highly functional, rapidly responding interfaces. If you disagree with that, feel free to provide something useful. Suggesting less-functional workarounds is not a solution - I already know how to do workarounds. I don't like making workarounds, which is why I prefer to write client/server applications instead of web ones." -- ChrisMellon?
- QueryByExample is not a "work-around"; it is a user interface technique. Most people are not speed-readers and cannot visually scan 500+ items anyhow. I would rather let the computer do the reading instead my eyes. If you are the exception, you have to be careful not to assume that everybody else has fast eyes also. Type-ahead matching is fine, but I would not want it to be my only means to find stuff. I'll take QBE before I take type-ahead. Whether this reflects the preference of every user, I don't know.
In the end:
- We need some specific UseCases to get to the bottom of this. Otherwise there are too many factors to compare. -- top
- "It's a 100%, non-subjective fact that there are many things which you cannot do in a web browser environment, and many more which you can only do with greater effort." -- ChrisMellon?
- I disagree. Response-time and pleasantness aside, almost any user activity can be done via a web interface. -- top
Heated argument and insults deleted; feel free to restore via history, but they were mostly content-free. -- JoeOsborn
Factors in data caching include:
- Size of "list"
- The flexibility available to you in your target language will drastically affect how large of datasets you can reasonable store in X amount of memory - JavaScript is terribly memory-inefficent, "real" interperted languages like Python less so, and of course a basic C array about as efficent as you can hope to be [Baring even more extreme guru tricks like TwoPointersInOneWord].
- I am not sure raw memory is really the issue. Most modern OS's can use disk caching so in theory the list size can be the size of the available disk cache.
- Yes, raw memory usage really is an issue. ((Since disks are slower than RAM by... a lot.))
- If you're willing to embed a database engine in your client, you can massively increase the size of the list it's worthwhile caching (including values of list size that are larger than main memory) as you would then have the equivalent of a node of a distributed database a function-call (as opposed to a round-trip time) away. --MartinRudat
- Frequency of usage (per user)
- Frequency of updates to "list"
- How often you need to invalidate the cache, in other words. Another thing to consider is the expense of checking whether or not the cache is stale. Most CRUD-style data screens just use timestamps, especially if all you've got is HTTP. It's kinda too bad HTTP push never went anywhere, because without it you have to poll.
- Frequency of "non-key" searches (to judge need for things like QueryByExample)
- Caching of common queries doesn't preclude the ability for ad hoc ones, of course - make the common case cheap is a traditional optimization mantra
- Latency (let's assume a "medium" HTTP connection)
- I'd rephrase this as "expense of query" - latency being just one of the factors that can make it expensive.
- Please clarify
- A query which takes 40 seconds to run is an obvious candidate for caching, at any level. It's not just transactional latency that you need to consider.
- Good item. Perhaps we should devide this up into network latency and query latency.
- Usable or assumed max memory of browser or C/S app
- You have far more opportunities for optimzation (at all levels) in a client/server app than you do in a browser. Of course, that requires knowning and caring about low-level details like memory structures, which some people notoriously disdain as being too low-level and not part of their domain. A naive client/server app may not peform any better than a browser app, especially in memory usage, but you have a lot more places to go when you start optimizing.
- I know I will get chewed out for saying this, but using ExBase I didn't have to worry about writing low-level memory structures because table caching was generally automatic and indexes easy to create if needed. I would be happy to get into a speed shoot-out contest using FoxPro if you disagree. I don't claim it the fastest, but "usually good enough". Related: AreTablesGeneralPurposeStructures. -- top
- Violent exchange removed. -- JoeOsborn
- One other thing to consider is that although it is indeed technically possible to write a custom RAM structure optimized for a particular need, it is usually not cost-effective, or at least has a low likelihood of being approved by management, at least as far as custom software. This is one of the reasons why "higher-level" languages are usually used for custom business applications rather than C/C++. Most of the bottlenecks I have encountered (outside of outright bad coding) are due to multitudes of issues coming together at the same time rather than one particular look-up being slow. It thus could not be fixed by replacing one small portion with C/C++, but rather would require rewriting much or all of the application in C/C++, which is not an option. Usually there is a way to improve performance of such things with enough tweaking in the higher-level language. It may indeed be true that writing certain portions in C to begin with may have made things simpler in the end, but one often does not know ahead of time where the performance bottlenecks will be. It is felt that one still gets a net productivity improvement from high-level languages even if some portions do take longer to optimize.
- Experienced people using higher-level language know the no-no's that cause performance issues. A C/C++ rewrite is just a bandaid solution for poor techniques. They may make crap run faster such that it may get tolerable, but it is still crap. Bad coders would abuse C/C++ also, making it slow. Hell, they'd make slow assembler also.
CategoryUserInterface