(评论)
(comments)

原始链接: https://news.ycombinator.com/item?id=41336462

在这篇文章中,作者讨论了他们学习阅读和编写 Clojure 编程语言的经验。 最初,他们发现 Clojure 代码由于其独特的语法而难以阅读,尤其是大量使用括号。 然而,在花时间研究该语言之后,作者发现阅读 Clojure 与阅读任何其他代码类似。 提高作者阅读 Clojure 代码能力的一方面是学习构建他们的代码编辑环境。 他们提到,他们向 ChatGPT 和 Claude 等人工智能助手寻求帮助,以更好地理解 Clojure 代码的特定片段。 此外,他们还强调了 Clojure 简单数据模型的优势,使开发人员能够高效地解决问题,而无需过多的样板代码。 此外,作者将 Clojure 的方法与本机应用程序和 Web 应用程序进行了比较,指出虽然对本机外观的偏好最初可能是由用户熟悉程度驱动的,但今天的用户体验不太可能仅限于一种操作系统。 因此,模仿本机控制设计的重要性就减弱了。 相反,通过适当的标签、定位和控件行为来专注于创建直观的用户界面变得至关重要。 最后,作者谈到了某些技术(例如 Java)难以有效地模拟本机用户界面风格,从而导致用户失望。 尽管面临这一挑战,仍然可以通过利用 Skia 等直接渲染库来创建原生外观的应用程序,而不是仅仅依赖托管平台提供的原生 GUI 工具包。 总的来说,作者强调了投入时间学习新的编程语言和适应不同的编码环境对于个人成长和提高效率的重要性。

相关文章

原文


Clojure and Flatlaf [1] tick all the boxes for me. If I want declarative-ish UI, I can always throw in Seesaw [2]. Everything else I find cumbersome, pulls tons of unnecessary dependencies and (usually) ends up abandoned in a year or two. With Swing, I know it is well-documented and will work for the next 30 years. But YMMV and I'm hoping that HumbleUI could be an exception.

[1] https://www.formdev.com/flatlaf/

[2] https://github.com/clj-commons/seesaw



Having worked with Swing recently, I worry that it will not work well on the near-distant future, because it feels frozen in time at about 2005.

There are a lot of assumptions baked in that aren't holding up today.

For example, high density and multi monitor aren't well supported. There's a bunch of stuff hard-coded in the JDK that no longer makes sense and you have to hack around.



I'm sure Clojure is a great language for some tasks...

But, looking at the examples (picked the Wordle one since I know that game): https://github.com/HumbleUI/HumbleUI/blob/main/dev/examples/...

I find it extremely hard to read. Even small snippets, say line 56 to 74 which define this "color", "merge-colors" and "colors"... then the "field" one lines 76 to 117 is even harder.

is it more natural read for people familiar with writing functional programs? (am I permanently "broken" due to my familiarity with imperative programing?)

I wonder what the same Wordle example would look like in, say pure Flutter.

Also wonder how would that code look with external dependencies (say hitting a server to get the word of the day), and navigation (with maintaining state in between those pages)



"is it more natural read for people familiar with writing functional programs? (am I permanently "broken" due to my familiarity with imperative programing?)"

As just one person who has written a great deal of functional code, it reads well to me. I think because I am used to reading it "inside out"? Reading lisp-likes is probably helpful.

Take 'color' for example. It opens with a 'cond', with three branches. First branch is if the idx-th position in word is the same as letter, return green. Second branch is if the word includes the latter at all, yellow. Otherwise we're grey.

That took me a few seconds to grok. Just one anecdote for you. Don't think you're broken but reading/writing this kind of code even a little bit will change the way you see code IMO.



This is the function that confused the person you respond to, ported to Python:
    def color(word, letter, idx):
        if word[idx] == letter:
            return GREEN
        elif letter in word:
            return YELLOW
        else:
            return GREY
I know which one I'd prefer to grok at 2AM with alerts going off.


Kotlin time (since we're in the JVM context for Clojure)
    fun color(word: String, letter: Char, idx: Int) =
      when (letter) {
        word[idx] -> GREEN
        in word -> YELLOW
        else -> GRAY
      }


> I know which one I'd prefer to grok at 2AM with alerts going off.

At that time I'd just opt for sleep. Or sex. Or drink. Reading code doesn't belong to things one should do at 2AM.



No. We didn't. At least not we all.

That's just a myth spread by a few workaholic programmers. Luckily, there are enough 9-5 programmers to clean up the mess created by those 2AM committers.



Honestly both read about the same to me, and I'm largely unfamiliar with Clojure. The main difference appears to be the 3 `str` callouts, which appear extraneous as the following version works just the same:
    (defn color [word letter idx]
      (cond
        (= (nth word idx) letter) :green
        (str/includes? word letter) :yellow
        :else :gray))
Interesting that even with the `str` callouts removed, the function still appears to work on other datatypes such as:
    (def s (seq ("test1"))
A lazy sequence, but one Clojure still allows to be indexed over in O(1) time. That's probably what the `str` conversion was trying to speed up.

Python, meanwhile, fails on lazy input as it isn't indexable.

    word = (c for c in "test1")
I guess I'll be checking out Clojure this weekend.


I'm guessing that str allow it to work when the inputs are symbols? So that they are compared as strings rather than by identity. There could be more than one symbol named "foo"; if you want those to compare the same, you can't use regular symbol equality.

Or possibly the code even uses non-symbols for some of the arguments. Suppose that letter is sometimes the integer 1.



And here's what cond could look like in Python syntax:
    def color(word, letter, idx):
        cond:
            word[idx] == letter: return GREEN
            letter in word: return YELLOW
            True: return GREY


> I know which one I'd prefer to grok at 2AM with alerts going off.

I hate meaningless statements like this. This means nothing, other maybe that you know Python. 20 years ago people might have said that about Python - I even know many people today who would say that about Python.



I was in a "101" undergrad compsci class the first year the program used Java (1997, I think?) and so this asst prof was showing a simple example of some Java syntax.

I had been programming in C for a while, learning from K&R, to build ray tracing input files and that sort of thing so I was kind of disappointed but whatever, I was a mature student who had rediscovered computers a couple of years before (had a C64 in the 80s) and was just happy to be there.

Anyway, this guy in the back yells out "I could do that in 2 lines of Q-BASIC" or something to that effect (Q-BASIC was definitely part of his pithy one-liner). Little did I know he was representing so many of the people I would encounter over the next decades.



> It opens with a 'cond', with three branches. First branch is if the idx-th position in word is the same as letter, return green. Second branch is if the word includes the letter at all, yellow.

This is a tangent, but I've been thinking about how I feel when the conditions of an if-else ladder rely on the order they're listed in.

This is an example; if you swapped the order of those branches around, the coloration would become incorrect.

I'm a little happier when the conditions are described completely, such that swapping the order of the checks doesn't change which of them evaluate false or true, but it's also true that that can add quite a bit of complexity over an order-sensitive set of conditions.

Thoughts?



You could do something like this in Clojure:
    (first (filter identity
                   [(and (condition-three) (action-three))
                    (and (condition-one) (action-one))
                    (and (condition-four) (action-four))
                    (and (condition-two) (action-two))]))
And you could write a macro to do it with nice syntax. A bit more work and you could parallelize it.

You probably wouldn't want to most of the time, but if the conditions are slow to test but otherwise inexpensive, it might be a useful optimization.



Having the order matter and matching the first `true` branch makes for more readable and less-wordy if statements. Otherwise when you have two conditions which have any overlap, such as A and B, for the A branch you need to add `and not B` and for the B branch you need to add `and not A`. This can create very long expressions. Having them evaluate in order and only match the first true one makes this unnecessary.



I mean if the checks are expensive and it's on hot path, then that's wasteful.It might also require then to use more nesting of IFs which isn't necessarily nicer.



It's possible to write some pretty unreadable code with Clojure, just like it's possible in any programming language.

I can tell you that this code is very easy to read if you are familiar with Clojure. In fact, this example is lovely! Seeing this code really makes me wanting to try this library! Clojure has this terse, yet readable aesthetic that I like a lot.

But I completely understand you because at some point Clojure code also looked alien to me. You are not broken for having familiarity with some style of code. Familiarity is something you can acquire at any time, and then this code will be easy to read.

True hard-to-read code is one that is hard to understand even if you master the language it is written in.



>> I find it extremely hard to read. Even small snippets, say line 56 to 74 which define this "color”

I think you make a great point, a point that once someone has gotten used to lisp, is harder to fully appreciate. I’m at the stage now in my lisp journey that i didn’t find those hard to read but it wasn’t that long ago that i felt almost nerd sniped by this weird language. I think it’s worth pointing out that in a more advanced example, I’d still have been comfortable because of the repl - I could navigate between each sub expression with a keystroke and I can send each to the repl with a keystroke and see what they do. Lisp really makes it easy to do this kind of bottom-up assembly - both when you’re writing and when you’re understanding someone else’s code.

A corollary to that, and which was key to me falling in love with lisps, is that the signal-to-noise ratio is off the charts. Whatever you want to implement, probably doesn’t require a lot of code. Wordle in 189 lines is pretty decent. There’s just less to fit in your head and what’s there tends to be solving the problem at hand, not boiler plate.



Just don't mention Electric Clojure, because that might cause some head explosions. (Fully reactive multi-tier programs where an entire web UI is 60 lines of code and implements infinite scroll with search and dynamic viewport resizing.)

If you know Clojure, the code presented in the example seems fairly straightforward. Parentheses demarcate the syntax tree; and the last expression in any tree is the result carried forward.



It's just a matter of familiarity. If you showed me an article written in Italian I would struggle to read it, but that's not because Italian is inherently an unreadable language.



As an experienced Clojure programmer, I found that code easy to read. It uses quite a few idioms that are specific to Clojure or at least Lisp.

Examples include cond, let [{:keys ...}], for being a list comprehension rather than a loop, #(%) function literals, and @ deref.



Let's see the features used in that snippet:

* The cond macro which works similarly to C switch

* Hashmap functions like merge and merge-with

* Destructuring

* The for macro which is similar to the "for each in" statements

None of these are something unfamiliar to common programming languages so that code will not be hard understand once you go over the initial syntax and idiom hump. The syntax makes things much easier once you get to used to it, I think all Clojure programmers like it.



This one's pretty clean for Clojure code, due to the simplicity of the data model, in the most conventional sense, as the state of the program is just the word, the guesses, and the grid of colored characters for the guesses.

External dependencies you manage like in most other applications nowadays, you don't hit external services in the "guts" of your code unless you really need to, for performance, testability and to keep the less reliable parts of your code isolated, you keep the interactions with external services as close to the "main" of the application as you can.

When things break down is with more complex data models of the application, not even as much because of the language itself but because Clojure programmers actively reject using record types and interfaces, and just pass dictionaries around. You wind up with some code that, bafflingly, gives the impression of being very simple and neat, but you can't tell what it's actually doing.



Clojure is a lisp. Lisp languages represent code as trees. That's why you have so many parentheses. The trees contain language constructs (if, cond, let, defn, ...), data (numbers, strings,...) and names (function names, names of value bindings). There is also some more advanced syntax for quoting and macros.

When reading lisp code, you navigate it like a tree. Indention matters and clean lisp code has the same indention level for all sibling nodes (with minor deviations for special constructs). Most code follows the pattern of defining "variable" bindings (e.g. via `let`) and then it has one final expression that uses all these bindings to calculate a value.

  (defn name-of-a-function-that-i-define [first-argument second-argument]
    (let [sum-of-some-numbers (+ 1 2 3)
          product-of-some-numbers (* 1 2 3)]
      (+ first-argument
         second-argument
         sum-of-some-numbers
         product-of-some-numbers)))


(i'll just make it clear that indentation matters to users as a strongly recommended convention for ease of reading. to the interpreter, you can write everything on a single line)



I'll add that the related 'power' many Lisp acolytes talk about stems from the fact that everything is a list of lists. Due to this, you can write programs that take syntax (a list of lists) and modify that syntax to do something else (another list of lists).

Imagine a language that has a built in parser and code generation library.



It's readable, your (justified) problem is with his names. There's no language where "colors" and "field" will be descriptive function names that make it clear what's going on.



I use Clojure professionally, but it's readable to me. I would personally encode the color merging rules differently since it looks too obscured as-is. But I think what doesnt help is the lack of types (or schemas) and the unhelpful function names, as described by another commenter.

Also,

  (apply merge-with {} ...)
is pretty "evil" in the sense that it's a very roundabout data transformation and would likely not pass code review at my company.


> I find it extremely hard to read. Even small snippets,

And unfortunately, you won't get much compiler assistance either with Clojure, beyond basic things. So it's easy to have bugs that will take a while to track down in a complex codebase.



As someone who’s written a lot of Clojure and have been using it on and off since 2009, this looks like decent quality code to me.

I think it’s just a familiarity thing. Clojure is different from most languages in that it’s a lisp and it’s immutable-first functional. That gives it a bit of a learning curve compared to other languages, but I find other simpler languages quite dificulte to read until I’m familiar with them, too.



I've tried to learn Clojure a few times and just bounced right off every time. I found it impossible to read and frustrating and tedious to write. Everyone else who tries it seems to fall in love, but I really don't get it.



not going to say you're wrong or right, but learning lisps/clojure fairly deeply you can find worse examples. Also when people learn it their mind tends to find it a very consistent langauge overall visually. I've moved on after a long stint in clojure to elixir and while I like it, most other language pale in language consistency.



If you haven't used a Lisp-inspired language, yeah, it's going to seem different than all those imperative Algol-derived languages that have been popular for so long.

I don't use Clojure professionally, but I've spent years using the language personally. It might be hard to believe, but it really is beautiful once you learn it, and extremely powerful as well.



I've done a bunch of Clojure development professionally and don't find that code extremely hard to read.

One thing to add to what others have said, when you're met with code like this in the wild and you need to modify/add/remove something but don't have a 100% understanding yet, the common workflow is that you explore this code with your "evaluator" (basically a REPL connected to your editor).

So if you come across snippets of code you don't understand very well, you place your cursor at the various forms and execute them. So you'll start at the inner forms, and slowly work your way outwards, and after that you've verified assumptions both about the function's internal workings and how you'll use it from the outside.



> I find it extremely hard to read.

I avoided Clojure for nearly 15 years because I thought so too.

Turned out I spoke English and couldn't read Russian. But that didn't mean Russian was unreadable—I just didn't know how. It had nothing to do with whether or not it was "readable" or not, it was easy to read (and understand) once I learned how.

After about two weeks, I found reading Clojure to be just as easy as any other code. I did that at 46, so I don't think age is a major barrier. (I've written read and written code my entire life.)

I'm now writing Clojure code every day and am much happier as a developer. (That's why I made the effort initially, and it definitely paid off.)

One thing that really helped was asking ChatGPT or Claude to explain a piece of Clojure code to me, when I had questions. Especially early on, that was invaluable.

Also, learning structured code editing made a big difference—I consider it to be essential. It was extremely frustrating until I spent an afternoon doing that.

Clojure code is "read" differently than, say, Python or JavaScript or C and that's reflected in how you navigate and edit the code.

YMMV



I think they mean when you learn the shortcuts for selecting and manipulating entire blocks between matching parentheses in an editor that helps balance them and so on, making it rather easy to test things out and refactor Lisp-like code.



> I find it extremely hard to read.

Having a bit of Lisp experience (really not a lot), I find it very easy and elegant to read.

> is it more natural read for people familiar with writing functional programs? (am I permanently "broken" due to my familiarity with imperative programing?)

No, most people who say something like this are simply unwilling to invest an evening into a language they're not already familiar with.



The readme says it is aiming for a “web look”, with no intention to make it look — and, presumably, behave — native. As a user, that’s not what I expect and hope for from a desktop application.



Following the author for some time and his main point is that “electron” won already, even despite the fact that the author himself doesn’t like it. And he’s not wrong. Majority of desktop users probably don’t care already if it’s native look or not (don’t cite me on that). The goal of the project to provide a way creating quite performant desktop apps with a DX of Clojure. And it’s a nice goal.



There's no native app, even on desktops. There are a bazillion of different UI frameworks with different look & feel on Windows alone, even within Microsoft products. On Linux or macOS, the situation is no better.

Native is what doesn't run in an emulator, in this case everything non-Electron fits the definition.



There are native apps, but appa are native to a desktop environment rather than to an operating system.

Unfortunately desktop environments on some proprietary operating systems are themselves comprised of apps written with different toolkits and bearing different looks and feels. But that's just a problem specific to them. KDE apps are all maybe to Plasma, GNOME apps are all native to GNOME.



WinUI 3 aims to be native, but of course Windows is a tapestry of many eras of Microsoft UI styles. If Microsoft doesn't again change their mind on how Windows should look, then WinUI 3 is indeed the look and behaviour that people will be expecting on a Windows machine.



I can relate (I think). I mean, I don't care what the general look of the app is, even if gimmicky of what native desktop looks, as long as the design, general aesthetic, and cohesion are kept well defined, structured and organized. I do not like Electron, I hate to have "little chromes" just so I can do X and Y. I crave true native apps, even if they still look kind of web'ish.



At this point it feels like this argument is dead an buried. So many non-native apps on every platform, most platforms even have multiple official GUI toolkits/widget styles so even first party apps are inconsistent.



The most consistently-looking desktop I have runs under Linux. With a few settings and a right theme, all GTK2, GTK3, Qt, and Java apps look and feel pretty much the same, in a pleasant way.

MacOS is a close second, with a few native apps that can't decide exactly what a checkbox or a button should look like.

And Win10 on my wife's machine is a salad, reminding me of Linux desktop experience from 1998.



> And Win10 on my wife's machine is a salad, reminding me of Linux desktop experience from 1998.

This is pretty funny, because if you just use Gnome apps + desktop environment, you have a consistent experience. But if you only use Microsoft/Windows GUIs, panels and applications, it nowhere near as consistent.

So even the Gnome team can build better UI and UX than Windows themselves can, pretty telling.



> even the Gnome team

People like to hate on them, but their design is actually really good, innovative and the applications running on GTK are incredibly fast and stable.



I'm not a fan of some of their UX design decisions, but I must admit that they seemingly know what they're doing, and their execution / implementation is pretty good.

I also hope that, unlike MS, they have no infighting between departments, and no stack ranking.



> People like to hate on them, but their design is actually really good

I'm not complaining/hating, Gnome is my desktop environment of choice since some time ago.

Was more a nod to how awful Microsoft seems to (still) be at UI and UX.



Professional software (think Clip Studio Art, 3DS Max, Autodesk Fusion and alike) are almost exclusively disconnected from "native" looks, behavior and theming, which is perfectly fine, better than having a different experience depending on your OS.

I feel like it's mostly consumers who ask for native look, and particular users on macOS, as almost all other professional-oriented software doesn't offer that. But yet it comes up for every GUI toolkit that lands on the HN frontpage.



I doubt most consumers ask for a native look. It's more like an HN meme.

I don't even think native macOS UI is so great cross-plat programs should target it. It's full of its own weird conventions like a "New item" button being a tiny "+" at the bottom of the left sidebar, the last place I always look.

Safari is an example of UX that has stuck to hard macOS conventions and was always worse off for it. Not until recently did it begin relenting, and now it's bearable to use as a daily driver. Xcode is another classic example of hostile native macOS UX conventions. Finder.app is another.

I'd rather software ask "what's the UX that makes the most sense?" rather than "how can I make my UI look native?" On HN people seem to think by solving the latter, you solve the former. But that isn't the case.



> I doubt most consumers ask for a native look. It's more like an HN meme.

The preference for native look was once about the impact of familiarity on usability. When 95% of people's interactions with computers was a single OS and native apps, they would expect controls to look a particular way. They could figure out other variants, sure, but from a UX design perspective, there's little reason to add that minor cognitive overhead needlessly.

Today, people's experiences are less likely to be monoculture like they once were, which dilutes one of the values of native controls. That's not to say designing with familiarity of controls in mind doesn't have value, just that it's less about, for example, buttons looking like buttons native to the OS, and more about visually reading as "this is a button" more generally.



>I doubt most consumers ask for a native look. It's more like an HN meme.

So you're ok with a mp3 player that takes 6 seconds to start up, is janky when it starts, takes 300MB of RAM, every row item is 100px high and every interaction with every UI element takes a noticeable delay on the order of 100x milliseconds?

And you're gonna tolerate the same story with the file explorer app, the archive/zip app, the WiFi SSID selection dialog, etc?



This comment responds to the idea of native look being important with a list of performance issues. Whether software should be efficient and responsive is separate from whether it should look native to the OS it's running on.



Even if that is true in the general case (it isn't necessarily - there are many factors), it’s a matter of what’s acceptable, not a race to 1000fps. If you build a webview based app (using eg tauri) I can assure you that it can be extremely snappy,

As an example, look at typical popular iOS apps: they’re often 100-500 Mb, even though they have absolutely no reason to be. LinkedIn is 400Mb, random airline app is 300Mb. Banking app? 350Mb.

Is it bad to bundle Chrome and NodeJS? Yes, undoubtedly (but that’s already changing). Is that the only way to deploy web-based apps to desktop? No. Is native UI gonna fix it? Temporarily at best, while the platform’s native ecosystem is simply too small to cause that level of bloat.



Not really. VS Code does have some performance optimizations where even the web browser optimization wouldn't suffice, for example it implements its own scroll bar instead of using the web native scroll bar. But for the most part the browser render optimizations is the crucial factor. After years of optimization you can't easily beat a web browser.

Native app is just another set of layers of abstractions. As a comparison, SwiftUI doesn't render 500 items quickly enough (https://www.reddit.com/r/swift/comments/18dlgv0/improving_pe...), which is a tiny number for web.



Unless you think native UI runs on magic - it's not that hard to outperform native rendering - you have to be way less general with a bespoke framework (up to a certain point of complexity).



that is precisely what people in this thread are talking about - users want native performance and memory footprint, they aren't concerned with native look and feel.



That’s not accurate, there are cross-platform toolkits that achieve at least a close-to-native look&feel. This is very different from giving up on it entirely and going web-style UI.



If they use native widgets, they usually look really bad If they just “imitate” look and feel, they usually fall very short of the real thing

Either way, it’s bad experience for the end user



That’s two perfect examples! Racket seems to try to use native widgets, and looks horrible as a result, at least on macOS

JavaFX uses the same approach as Humble UI: they draw all the widgets themselves and have custom cross-platform look and feel.

We aim to be better quality version of JavaFX



Do they? I can usually tell... Most cross-platform GUI stacks I've looked at, the app maybe tweaks the style slightly, but the behavior and look is mostly whatever its own interpretation is, or whatever the developer bothered to do.



Really could use a link to the API docs in the README.md, it is a bit hard to judge when the "documentation" such as they have so far is sparse. But it is nice to see a newish UI project.

I will say I've found Clojure to be a success story for doing GUI work. Projects like Dave Ray's seesaw (https://github.com/clj-commons/seesaw) are an amazing demo of how one man can rearchitect an API like Swing into something that is deceptively fun to use. High hopes that this project goes somewhere that is similarly enjoyable.



I found this dimension of the analysis:

> People prefer native apps to web apps

> Java has “UI curse”: Looked bad

to be at odds with this aspect of the design:

> No goal to look native

> Leverage Skia



"People prefer native apps to web apps" is talking about literally using an app on your desktop, in the dock, with keyboard shortcuts, rather than having a website in your browser. This is sort of shown by the amount of Electron apps people use — you could use slack, spotify, or vscode in the browser, but most people prefer to use the app.

"Java has UI curse" is referring to how when Java tries to imitate native UI (note the difference to "native app", which is in contrast to a web app), it fails and hits the uncanny valley. No-one likes it.

Given that, it's not a contradiction to have a native app, that does not try to use the native GUI toolkit of the host platform, using Skia directly to draw UI elements.



I suppose it’s just to clarify that those choices are deliberate, with the trade-offs in mind.

The README also suggests that the reason why people prefer native apps isn’t just the UI’s aesthetics, but:

> Normal shortcuts, icon, its own window, file system access, notifications, OS integrations



Question about native integration. Does the framework support documents on a native level? Can I define a file type that opens the app when double clicked, maintaining the windows and data, etc?



may I ask what this sentiment comes from?

I sincerely want to know what I am missing, because the fact that Clojure is hosted on the JVM (mainly) seems like a plus to me.

I don't much like the build tools in the jvm environment such as maven or gradle, and the error messages could be better for sure. Is there more ugliness that I should look into?



where did the myth that people prefer apps that look native to the platform come from?

There are two types of apps: 1. the ones that professionals use and 2. the ones that consumers use.

for 1. they don't care if it looks native, as long as it works and is performant e.g. DAWs, Video Editing tools, Trading, etc.

2. likewise I don't think it matters that much.

my guess is the myth came from OS makers.



Native look&feel makes for a consistent UX across apps. Users learn one set of conventions and UI controls that uniformly applies to all applications. In addition, all applications benefit from enhancements made to the native UI toolkit and integration with the OS (input methods, file dialogs, keyboard navigation, automations, …).

Moreover, web UIs tend to be less sophisticated and less power user friendly, due to HTML/CSS and browser API limitations. This unfortunately often carries over even to non-browser-based applications that however use a web-like UI.



There's a slightly deeper part to this which is that if I see a native UI toolkit in use, I can be at least relatively confident that the accessibility affordances I expect to be there haven't been half-arsed in some custom widget set implementation. That's part of the "one set of conventions" expectation you mention, but it's an important one. There's a lot of embedded knowledge in native widgets.



I don't personally believe it's ever been true that users want the same UI styling across apps. When given the option to customize the colors or layout of an app, users will do that. People want their applications to follow common UI patterns, but applications should have some kind of personality to them, otherwise they just look like Microsoft or Apple products



When apps have native look and feel, they have consistent behaviour, affordances and accessibility:

- buttons are labeled and placed correctly, and respond to expected input (including secondary focus and secondary action on MacOS, for example)

- dropdowns/selects behave correctly, and respond to expected input (for example, you can type to select in MacOS dropdowns).

- windows have OS-defined areas for drag/resize, for titles, for toolbars etc. They also appear correctly in the OS's window management tools (app switchers etc.)

- text inputs use the OS-default shortcuts and have access to OS-provided tools (e.g. spell checker)

- controls and windows respond correctly to keyboard and mouse. E.g. for a while Apple's own Catalyst apps didn't have the standard Cmd+Q to close the app. Many custom modals do not dismiss the modal on Escape

- context menus are standard in the places where you expect standard context menus. Well, app menus, too.

And the list just goes on and on.



All good points, all true. But what’s also true is that current trend is to come up with arbitrary-looking controls even on apps made by Apple themselves. Nobody knows what native is supposed to look like. I’m not saying it’s good, it’s just what is happening.



It comes from macOS users, really. On windows nothing looks native because nobody can make sense of what native looks like in current-year. On Linux, lol. Lmao. On macOS? Your app better is native because it will stick out like a sore thumb if it isn’t and I won’t use it.



I’ve gone over the readme, what part would you say is them dunking?

Like, honest question, I do agree with most of their points and don’t think they’re presenting them in a too harsh way

联系我们 contact @ memedata.com