Ensuring that blank-state has been handled in UIs?

Hi Everyone, In most user-interfaces we need special-treatment for blank states (zero-item state). For example: * In case there are no customers, don't show an empty table, instead show the message "You seem to have no customers, why not start by creating one..." * In case there are no bookings, don't show an empty table, instead show the message, "No bookings here. Want to create one?" * In case there are no search results, don't show an empty table, instead show the message, "No items found. Undo your last filter?" In some cases, the one-item case also needs special treatment, but I'm unable to come with relatable examples at the moment. A lot of times the dev simply forgets about the blank state, and it is caught during QA, which results in a quick-fix on the following lines: if length item > 0 then displayTable else showBlankState if Data.Map.Strict.size map > 0 then displayTable else showBlankState if Data.Set.Ordered.size set > 0 then displayTable else showBlankState Is there a way to prevent this bug from the get-go? Can we use the type-system (or anything else) to enforce the dev to at least _think_ about the blank state? Obviously, the type system can't help us with _what_ needs to be done with the blank state, but at least it can _remind_ the dev at compile-time about handling blank states. -- Saurabh.

Make your 'displayTable' function take a 'NonEmpty a' instead of a List
(eg. [a] or Vector a). That at least ensures that you won't ever be showing
an empty table. I don't think there is a Map/Set-equivalent of NonEmpty.
But you will have to convert a Map/Set into a list at some point, and
that's where you can again use NonEmpty.
https://downloads.haskell.org/~ghc/8.0.1/docs/html/libraries/base-4.9.0.0/Da...
On Sun, Apr 16, 2017 at 1:54 PM Saurabh Nanda
Hi Everyone,
In most user-interfaces we need special-treatment for blank states (zero-item state). For example:
* In case there are no customers, don't show an empty table, instead show the message "You seem to have no customers, why not start by creating one..." * In case there are no bookings, don't show an empty table, instead show the message, "No bookings here. Want to create one?" * In case there are no search results, don't show an empty table, instead show the message, "No items found. Undo your last filter?"
In some cases, the one-item case also needs special treatment, but I'm unable to come with relatable examples at the moment.
A lot of times the dev simply forgets about the blank state, and it is caught during QA, which results in a quick-fix on the following lines:
if length item > 0 then displayTable else showBlankState if Data.Map.Strict.size map > 0 then displayTable else showBlankState if Data.Set.Ordered.size set > 0 then displayTable else showBlankState
Is there a way to prevent this bug from the get-go? Can we use the type-system (or anything else) to enforce the dev to at least _think_ about the blank state? Obviously, the type system can't help us with _what_ needs to be done with the blank state, but at least it can _remind_ the dev at compile-time about handling blank states.
-- Saurabh. _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

On 2017-04-16 13:51, Saurabh Nanda wrote:
Can we use the type-system (or anything else) to enforce the dev to at least _think_ about the blank state?
That is an interesting problem. But I'd say the solution depends highly on your architecture. Tomas' suggestion to use NonEmpty could be one solution, and one you could try to build upon to track more details in the types. Alternatively, you could add a typeclass that just handles the zero-element-case. That way your constraints remind the developer to at least copy-paste a default implementation. showItemTable :: (HasZeroItemPresentation (presenter item)) => presenter item -> [item] -> Table item But maybe there's a much simpler solution: Create a datatype that stores the normal presentation function, a zero-case presentation function, and optionally a one-item presentation function. Now whenever someone creates a new type of item, they need a new presentation adapter. data TablePresenter item = TablePresenter { showZeroItems :: Widget; showItem :: item -> Widget; showSingleItem :: Maybe (item -> Widget) } showItemTable :: TablePresenter item -> [item] -> Table item This should offer safety and code reuse, and it should be easy to integrate because you don't even have to start with types. Why be fancy when the simple solutions work? Cheers, MarLinn

I think you might find the RemoteData solution here relevant to your
problem:
http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html
I've been using it successfully for a lot of UI work. Even if you have a
default handler function that gives a sane-ish default value for the
context you'll be using it in (I.e "Loading..." in UI), I've found it helps
keep interfaces sane even when you "forget" you actually care about the
empty state.
On Sun, 16 Apr 2017 at 15:07, MarLinn
On 2017-04-16 13:51, Saurabh Nanda wrote:
Can we use the type-system (or anything else) to enforce the dev to at least _think_ about the blank state?
That is an interesting problem. But I'd say the solution depends highly on your architecture. Tomas' suggestion to use NonEmpty could be one solution, and one you could try to build upon to track more details in the types. Alternatively, you could add a typeclass that just handles the zero-element-case. That way your constraints remind the developer to at least copy-paste a default implementation.
showItemTable :: (HasZeroItemPresentation (presenter item)) => presenter item -> [item] -> Table item
But maybe there's a much simpler solution: Create a datatype that stores the normal presentation function, a zero-case presentation function, and optionally a one-item presentation function. Now whenever someone creates a new type of item, they need a new presentation adapter.
data TablePresenter item = TablePresenter { showZeroItems :: Widget; showItem :: item -> Widget; showSingleItem :: Maybe (item -> Widget) }
showItemTable :: TablePresenter item -> [item] -> Table item
This should offer safety and code reuse, and it should be easy to integrate because you don't even have to start with types. Why be fancy when the simple solutions work?
Cheers, MarLinn _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
-- - Mario
participants (4)
-
Mario Rogic
-
MarLinn
-
Saurabh Nanda
-
Tomas Carnecky