Simple software things that are actually very complicated
construct.net
construct.net
No, we must go simpler.
left-pad: you need to account for wide characters, such as CJK characters but also emoji, you need to account for things like combining characters, etc. left-pad is not some trivial function.
Of course, the infamous left-pad package was widely mocked "why do you need a whole package for such a simple task" — so simple, indeed, that it failed to handle many of those cases. But don't worry, it's been standardized now as padStart() … and still fails those cases:
> 'e\u0301'.padStart(2)
'é'
Okay, strings aren't simple! But numbers, numbers are fine right?So then, Go issue #4594, "add a Round function [to Go]"[1]. Go maintainer Ross Cox suggests that "it's a one liner" and suggests … a buggy implementation. There are a total of no less than 6 different implementations in the issue, and every single one of them is buggy. The bug is closed, the function is "too simple" to add. Thankfully, the wound gets reopened nearly a half-decade later in #20100. Another buggy implementation is suggested in that thread, and thankfully, Go gets a round function. (A non-buggy one … I think.)
Just to build a key cap for this laptop I'm typing on, very difficult if I actually had to do that. I need to use tools that were ultimately kicked off by stone age men thousands of years ago that progressed by building tools with those tools until we go to the point today where we can create a key cap for a laptop.
Surely it's more complicated than that ;)
I do wonder if we will end up just moving towards more unified formats and doing away with the need for all this complexity. I could be very wrong on this, but it seems like for the smaller to mid scale software projects, I18n is just not worth it. Throwing a bunch of YAML files over the wall to a translation company and then just dropping them in the app does not work and the end result is so bad that native speakers would rather just use the app in correct English than broken native language.
Now you don't have to care about how to wrap or hyphenate a word in an obscure language which doesn't support it, and you don't have to worry about vertical text. Your problem space just got a lot smaller. And if you are building a tool at Google scale then you should have the resources to just make the problem go away anyway.
But colordrops said "supporting every single language, culture, format". So by definition, it's more than English. And as soon as you start looking into non-English writing systems, you realize that it is very much not simple.
Or 'never' :-)
Our software deals with scientific stuff and safety stuff, and even a minor mistranslation there could have a big (and potentially very bad) impact.
So even though technically we could allow translations, we don't, and there's a very good reason for that. Human languages are messy, and every time you switch from one to another, there's a good chance of something getting lost along the way. And sometimes, that kind of loss is just not acceptable. Even if it would be a little more convenient.
Drawing the limits and knowing when to say "no", even to what might seem like a 'simple' thing, is important.
* fluent in both languages (including domain-specific tech lingo)
* intimately familiar with the software
* very thorough (has to ideally check each and every string if it works in the context of the software)
...only then will you get a high quality translation.
HAH! Even if you just say "I only support English", "text handling" is still an infinite black hole of programming time and energy.
Rendering text sucks.
> it seems like for the smaller to mid scale software projects, I18n is just not worth it
If you don't mind reading from right to left and praying towards Mecca, then sure you can disregard all the diversity of human accomplishment. But unless you are willing to have another language and culture imposed on you, suggesting that you imposing your language and culture on others is "worth it" as opposed to wrapping all user-facing strings with some gettext-compatibility layer is disingenuous.I write i18n compatible software, that supports not only multiple languages but also interface directionality and culture-specific features. Not because I have to, but because I respect my users.
Is that actually supported by evidence or did you pull it out from .. somewhere?
This claim probably holds if the user is fluent in English as a second language, but are you sure the billions of people who can't read English would really make that choice?
I think it's the developer's choice whether to only support users that can read English to at least some degree, but claiming that an option for broken i18n is worse than nothing seems to be rather radical to me... (that said, the number of websites that presume my language preferences upon a geoip check is infuriating...)
[0] https://en.wikipedia.org/wiki/List_of_languages_by_number_of...
[1]: https://en.wikipedia.org/wiki/List_of_languages_by_total_num...
I feel like tons of the very basic things that have been core software tasks for ages still have surprising amount of complexity and depth to them when you'd expect them to be simple. Stuff like text (basically anything), math (real numbers), 2d graphics (efficient high-quality vector graphics still seem like a pipedream), sorting (we just had a thread about improving sorting in postgres!), files (infamous fsync issues), color, etc just seem to constantly come up as problems when you'd think we had solved them already 20 years ago.
That is, any adult human being carries around an absolutely massive amount of mental context which they are capable of applying to every situation nearly automatically, without realizing it. All of the things you mention are tasks any sufficiently educated human can do easily - draw a shape? sort some things? do math with fractions or complex numbers? - because you can teach a human a general concept and then assume their brain will do the work of applying it to new situations, breaking it down, etc. 2 + 2 on a TV screen is exactly the same as 2 + 2 in a notebook is exactly the same as two sheep + two sheep in the field.
But until someone invents strong general AI (hehe), computers just aren't gonna have that skillset.
For example, if my text problem were "display these preformatted strings in a single resolution and layout" there would be no requirement on their encoding or processing and I could do whatever I like, even hardcode them or store them as image assets. Games have done this trick since forever because they have a tremendous capacity to soak up more and more static content, and much of the core tech in a game engine is in finding the ideal representations to efficiently load and present that content while carefully minimizing the dynamic behavior that would entail a general-purpose solution.
The problem for software in the larger view of things is always that we've defined the problem with sufficient generality that it has to accommodate all the depth, because we don't know who is using the software or what they want from it. The medium is never "set in stone" so the tools are forever adapting to a new use case. And just when you think you've modelled every possible aspect of the data, some other way of doing it will come up.
And it's not a right thing either to think "OK, I'll just solve the most general thing I can think of now so that I don't deal with it later" because then you just have a wide field of untested edge cases and no coverage of the thing you didn't anticipate.
Like, take image editing software as an example. They all let you draw things freehand. Many support pressure sensitive stylus input. But the way they interpret that input is all over the map: different sensitivity curves, stabilization algorithms, brush behaviors and so on. There's no winning the battle by defining the most general engine for freehand drawing and painting, because what the user craves most of all here is the path to "just works" defaults. Thus in every sufficiently developed editor, an enumeration of possibilities appears again, but as a configuration letting you browse presets.
Text rendering is still a very complex task in modern games unless you're using an engine (and even then the complexity is still there it's just hidden). I'm not aware of any recent releases that stored all their text as hard coded images. Most games will at the very least create a predefined charset, render each character to a bitmap or sdf as part of the loading using something like freetype or stb_truetype, cache the bitmaps or sdfs to a hash map with a lookup ID and all that stuff, upload the images to a texture on the GPU, perform some sort of layout scheme when rendering the text in the game world or HUD (which includes things like figuring out the kerning for different characters, line wrap, and all the other fun stuff).
Like somebody else mentioned, nothing is simple. Even a bitmap font from the 80s was wayyy more complex then it would be today because of all the optimizations you would have to create to make sure it was fast, and the extreme lack of modern rendering utilities that we have today.*
*I wasn't alive in the 80s, so this is just based on the videos I've seen of what we had then and articles/books I've read about what programming was like then.
For example, text is just a null-terminated char array if you only support ASCII, or short or int array to support other languages and more symbols. To render the text, just loop over each char and index into an array to get a bitmap of a monospace font. Your text may look a bit ugly and take up more memory than necessary, but it’s passable, and 40 years ago it’s what we did.
There are some problems like TSP and Chess where there is a simple brute-force solution, but its not “passable” because it takes impossibly long, so you need a more optimal complex solution. And then there’s the iconic “seems simple but actually really hard” problems like generalized image recognition or walking; they are “simple” to humans and animals, but a remotely half-decent solution took a long time even with giant super-computers, and it’s still only half-decent.
And the level at which that occurs has probably got more complex/deep as time's gone on. It's almost tautological, I can't really see that that would ever not be the case for anything.
Kicking a ball is bloody easy, but soccer's played at a high level by extremely trained extremely paid people. (I'm far from a fan, fwiw, but I think it's a clear example.)
Most of these things probably die after a while if they are ever really well-known but if you work for some FANG (or whatever it is now!) company, you might have enough resource to force the new way of thinking onto everyone else so that FOMO kicks in unless you are also using the new best thing.
In so many cases, people get religious about differences that might affect Google or Amazons bandwidth usage but no-one elses (like using a new image format). I wonder how many developers, particularly web developers, actually know for certain which parts of their system are unreasonably slow and actually need to change?
I’m a bit unfair, because some high tech stuff is cheap, we all use tree and hash structures whose development we don’t pay because they are in the standard library, but it’s a few strategic and standardized places. The same as using a ball bearing in mechanics: you get into a very high tolerance world for cheap, the mechanical interface is standard and some unicorn mounted helve make those bearing in a chocolate factory as far as I know they might develop maps and queues on their other half time.
When reading that list, my thoughts turned to whether there is a good open source implementation that could be used / cross compiled into web assembly since surely somebody has done it correctly.
I wonder what Google Docs does on iOS?
ReactNative doesn’t have this problem since the ui is expressed ultimately as native components.
Of course I am using this to print cards with custom software and it doesn't have to be interactive, reflow, or be useful to anyone else.
Regarding your epiphany, (a) Word doesn't turn on kerning by default, but it does indeed kern properly. I don't use Powerpoint, but I'm guessing there might be a similar setting on the second tab of the font modal for turning on kerning. I don't know where you get your claim that Adobe tools don't kern properly, but they very much do. And finally, kerning is just as important for sans-serif type as it is for serifed type. The only arena it doesn't come into play is monospace type. Which, perhaps surprisingly, Japanese type traditionally is.
My go-to type for demonstrating this problem was Trump Mediaeval but sometime in the transition from Type 1 to Opentype, the type gnomes at Linotype saw the obvious issue here and replaced the ugly fi ligature with a logotype with fi without the ligature (the logotype existing more for the sake of documents which might have manually specified fi rather than fi (I’m curious to see whether the difference is visible when this gets translated into its presentation form)).
Not that long ago, typesetting math formulas was extremely expensive, unless you used TeX. It was not very commercial and companies were not interested but certain individuals were.
The same happened when you wanted your Hebrew or Arabic or Japanese just to look right. Japanese uses at least four scripts plus latin words in the same place.
Over time, commercial entities added support for those, most of them just incorporating TeX source code (as it was public domain). They added the visual interfaces and the easiness of use that TeX lacks.
Which four? I can only count to 3. My understanding is that all the characters are "fixed width", even the Latin ones. I imagine that makes typesetting easier, and presumably doesn't require the complexity of the Knuth algorithm.
And when you’re not talking about a book, but an ad or something like that, it’s common to have a bunch of different text sizes or make some of the words in a sentence bigger to emphasize them.
https://docs.google.com/document/d/1vUnn0ePU-ynArE1OdxyEHXR2... feels very weird on an iPad from a quick 10 second look: selection markers are Android styled, scrolling is janky, scroll easing is wrong, no scrollbar. Popups menus are very different and they have Mac keyboard shortcuts! Etcetera etcetera, and that was on a readonly document. (I presume it is the current version of Google Docs from a browser).
Even some non-devs, due to using word-processors that completely "mess-up" everything the minute a single table is added, won't think that text rendering is simple.
The best "simple-is-very-complicated" essay to read is "Reality has a surprising amount of detail" - http://johnsalvatier.org/blog/2017/reality-has-a-surprising-...
This whole discussion reminds me of Joel’s Single Biggest mistake software developers do: https://www.joelonsoftware.com/2000/04/06/things-you-should-...
Namely, rewriting software is hard because the years of subtle complexity aren’t immediately apparent and hard to get right the second time (at least harder than first thought).
Any kind of dynamic page rendering: we want to write code once and re-use everywhere, in the Web browser, mobile, iOS, Android, etc.
This is a fool’s errand 99% of the time. You’ll end up building something super constrained if it is usable at all. Admittedly there are some viable options for this like React Native. Yeah, I just don’t want to work on this type of code.
Client libraries: I want to write my own client, in top of a third party networking library, to send HTTP requests, and handle threading, tcp connections, connection pools, thread pools, etc.
Even when using something as simple as libwebcurl, innocuous things fail in weird, unexpected ways that almost never come up in (my) unit tests, integration tests, and chaos tests.
Server side client code that calls another service can be dangerous. Device code that you ship out to millions of devices is even more dangerous.
Oh… 50% error rate because suddenly the code can’t access an SSL cert on the device. Wait… what??? I can’t even reproduce it?
I’ve been writing code since grade school and am a decade now into my career. I’m an above average programmer on a good day, and terribly average at best on most days. So of course, I might be sounding melodramatic here.
This attitude reminds me of what someone says about the difference between German and Japanese tech. Japanese ones last forever because they overdesign their products to avoid breaking even when misused, because they are customer-focused. Germans are rule-focused, so they design their products according to spec. German products also last forever — if you use the product exactly per instructions. But if you make a mistake... good luck.
(German translations would need about 3x the UI space of Japanese ones, and that’s with a proportional font.)
Contrast with things like interpreters that a are a lot simpler to build and work with than most engineers think they are, and a perfectly reasonable solution to lots of problems.
Brilliant, I've never seen kerning (ker-ning) spelt in a way that illustrates it's importance!
https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-...
(as someone with a long, double barreled surname this is relatable)
The common thread is usually what assumptions you can make about your use case, when are they valid and when do they fail?
⸻
1. It will be published to crates.io sometime in the next month or so, there’s possible optimization work to be done, or at least, an alternate interface to the iterator to see whether the speed penalty I’m paying is an algorithmic problem or just an artifact of the trade-offs I have for my use case. I also ended up writing my own character class code as well and in benchmarking against the current popular crate got a 10x speedup,² so even if my segmentation code is useless to anyone but myself, I think that this code at least will be useful.
2. The other crate has a really inefficient implementation of looking up character classes where it ends up having to do a binary search in the data tables for many characters while I use a two-step table approach which lets me get a character’s class in O(1) time (and the tables are designed to be small enough that they’ll stick around in the CPU cache for lookups in a tight loop).
The trick is to take as much advantage of this command-line and remove all other GUI.
I'm only going to support ASCII which helps a great deal.
Chat bubble / command-line above characters is the only GUI the game will have:
Login: /sign name pass
Register: /join name pass pass
Sensitivity: /sens 0.6
etc.
Although being aware of these considerations is helpful for designing a solution which will be able to address these issues later. Like determining allowed break spots before doing the actual line break. And having that logic extensible.
If you're splitting strings to graphemes for word wrap, you're doing it wrong. Unicode segmentation defines a word segmentation algorithm that should be used for that use case instead.
What is the reason to link to external websites like this: https://www.construct.net/out?u=https%3a%2f%2fen.wikipedia.o...
Why not set a link to wikipedia directly?