The article name describes Tailwind exactly for me.
I personally am a fan of schematic html/css. I remember the days off CSS Zen Garden, with well marked up html you can change the visual look completely by swapping out the style sheet. There’s a nice decoupling layer, it’s flexible, it’s conceptually simple, it works.
Despite all that I find myself using Tailwind. I’m not a frontend/designer expert, Tailwind goes against what I believe makes good HTML, Tailwind is ugly to me, polluting classes with markup. It’s equivalent to the embedding inline styles anti pattern. However in an imperfect world it works surprisingly well for visual styling on large projects, with many teams and components and just as well in small single page sites. The perfectionist in me says it’s horrible, the I can’t be bothered with frontend design in me says it’s so much less effort and avoids styling conflicts from multiple style sheets/components and I don’t care if it’s ugly or against the ethos of good html.
The discomfort is because html and css were misabstracted. They were designed for the old world of documents, where the idea of restyling a bunch of documents for a new letterhead (etc.) makes a lot of sense.
They've been adapted for the world of interface design, but the separation of concerns doesn't make sense in that axis. It makes sense for the content of a document to be separate from it's style. It doesn't make as much sense to separate the structure of an interface from it's style. (In practice they are almost always tightly coupled.)
Tailwind is flattening these back down into roughly one layer from the author's perspective, where they make sense for the design work.
So what really what we want is to bring back presentation attributes full-force, a la SVG, for contexts where the page is not expected to be printed? Do I have that right?
I don't mean to prescribe anything that specific (lest anyone reject the diagnosis because they don't like the prescription).
I think people are using Tailwind in roughly a presentation-attribute way in order to claw back some of the combinatorial complexity that comes from letting conceptually-distinct components share a namespace.
I don't mean that stylesheets are a bad/wrong way to express style for interfaces, nor that we don't want a separate DSL for expressing style. Web components are a meaningful gesture at better ways to manage the problem, but you still need a decent chunk of JS to take advantage.
(If you must, imagining how native HTML + CSS could support expressing components with well-controlled encapsulation/boundaries might give you a better sense of where I'd try to start if this was suddenly my problem to solve.)
I would strongly disagree with this, for two reasons.
1. Interfaces aren't special, the majority of application interfaces on my computer are just interactive documents, they're just styled to look like they're not. Outside of some specific examples (games, Blender, Krita, maps), I think very often if you can't sit down and describe an interface as pure text, something has gone wrong with your UX. And in fact, if you're interested in building genuinely accessible apps for low-vision users, it is a prerequisite that you be able to describe your interface using just text.
Most native apps are just interactive documents and forms.
2. The need to change presentation depending on context has gone up over time, not down. There's this theory that documents used to need to be flexible, but now we're all using interfaces where the data we're displaying should be tightly coupled to the interface and it just doesn't make sense given that screen sizes are far more diverse today (HDPI scaling is still a problem on Linux), phone sizes are more diverse, we have people using apps in hands-free settings, they're getting tied into personal assistants, we have more awareness now of accessibility concerns, devices like the Steam Deck exist.
Building polymorphic interfaces is more important today than it was 20 years ago when you could make 3 interfaces and just call it a day and assume you were supporting every device/control scheme. You didn't have people asking whether they could control your reader app with a gamecube controller.
And there are only two ways to build good polymorphic interfaces -- redesign multiple versions of the same interface, which doesn't scale and is guaranteed to leave uncommon and under-represented devices behind, or dive really hard into semantic[0] interfaces where you describe more precisely what data is rather than just what things look like.
The tight coupling of interfaces to presentation is usually bad for the end user and is usually unnecessary (in my opinion, based on the native desktop applications I commonly use). I often think that user interfaces would improve dramatically for everyone and our interfaces would be a lot easier to adapt to new computing interfaces and control schemes if we forced developers to build them with their monitors turned off, and then handed off the finished project to a separate team to make them look pretty.
----
I do agree with you on one point though:
> HTML wasn't designed for my ~modern assumption about what the document is. It was designed to be the document
HTML is at its best when it is not treated as a way to author interfaces, but rather as a render target in and of itself. A lot of design problems on the web stem from the fact that app developers view the pixels on the screen as their primary UX rather than as a secondary side-effect of their UX, which is HTML.
And I guess also to be fair, there is a valid critique here about the HTML "color" representing a mix of concerns. In some ways, HTML is kind of a flawed example of what we're trying to do. HTML was one iteration towards this idea of having user-facing data-driven interfaces. It's not necessarily perfect, it's just that it hasn't been supplanted (yet).
I think you would be strongly disagreeing with something I didn't say.
> Interfaces aren't special... if you can't sit down and describe an interface as pure text, something has gone wrong with your UX.
I'm not sure how this disagrees with anything I wrote. I am not even saying that defining an interface with xml is bad. I'm saying the interface of a website and the documents it contains are muddled.
> There's this theory that documents used to need to be flexible, but now we're all using interfaces where the data we're displaying should be tightly coupled to the interface and it just doesn't make sense given that screen sizes are far more diverse today (HDPI scaling is still a problem on Linux), phone sizes are more diverse, we have people using apps in hands-free settings, they're getting tied into personal assistants, we have more awareness now of accessibility concerns, devices like the Steam Deck exist.
I said literally nothing about tossing aside responsive/adaptive interfaces or designs.
I said that interface-html and interface-css are tightly coupled. This is already true. They already almost always evolve together. It is already exceedingly rare to see a web site/app fully redesign without changing html.
I don't think we're in disagreement.
I am talking about the document and interface's style and structure being entwined together because the tools were designed for something different than what they are mostly used for. I am saying component-oriented approaches are ~recognizing and trying to rectify this mismatch (and people using Tailwind are reacting to a real deficiency in the core technologies).
Apologies for reading more into your article than it was trying to say. You're probably right that we're talking past each other a little bit. That being said:
> I'm saying the interface of a website and the documents it contains are muddled.
There is some truth to this, but it's overstated. I don't believe that the distinction between a website and a document is particularly clear on a conceptual level. Those things are muddled on the web because they are actually muddled in real life, there isn't a clear distinction between a document and an application -- and often it makes sense to treat them as the same thing.
> I said that interface-html and interface-css are tightly coupled. This is already true. They already almost always evolve together. It is already exceedingly rare to see a web site/app fully redesign without changing html.
I don't think this is particularly strong evidence either. Redesigns are large. I'd say an above-average number of site redesigns that I see involve changing the database layer too, that doesn't mean I'd encourage everyone to stop separating their database from their application logic.
A bigger thing here though is that this feels opposite to me to how I think about HTML. HTML in your app should be more likely to change than your CSS, not the other way around. HTML is your user interface. When you do a site redesign, you change what data you present to the user and how you present it. That's HTML. To me, this is like saying that splitting font display from UTF-8 characters is wrong because most of the time you revise a book it involves changing the characters, not just the font.
Incidentally if you redesign a website you will also often change the style, but... the style is secondary. I love the CSS garden stuff, I love how it got people thinking about separation of concerns, but it also encouraged people to think of HTML as if it's this extremely static interface that we apply a manifold of styles to, and that's usually incorrect.
So sure, of course HTML and CSS often change in parallel, but... so?
----
> I am saying component-oriented approaches are ~recognizing and trying to rectify this mismatch (and people using Tailwind are reacting to a real deficiency in the core technologies).
This is another thing where I feel like there must be something I'm missing because if you said this in isolation without mentioning Tailwind, I think I'd agree with it. I do agree that using semantic tags in CSS is bad for maintainability. I do agree that CSS has downsides, and I do think it should almost always be used in a component-oriented fashion.
But I've used Tailwind for a little while now (maybe not heavily enough, I don't know?) -- I don't think Tailwind is very component-oriented. It's component-oriented in the strictest sense that you put styles on a component. But it doesn't encourage building logical units of style, it doesn't encourage reuse, it doesn't encourage structuring of style, it makes it harder to look at the output and understand where a style is coming from or what part of the code set it.
You can have that stuff with Tailwind, but Tailwind doesn't seem to be helping with it, and most of the time that I see Tailwind it makes it harder to reason about the style of the app in a structured way. Most of the time I see Tailwind it's just attached directly to HTML like an inline style. And if I came to you and said I was going to stop using functions and just inline all of my code, you wouldn't characterize that as "component-based programming".
Honestly, if we're talking about component-based interfaces, Tailwind-based interfaces feel a lot more like early JQuery interfaces than they feel like React or Vue. Forget separation of style and layout, I don't think Tailwind encourages the use of components at all.
At least to me -- again, I know a bunch of people love it, I keep thinking there must be something I'm missing. But in practice, every Tailwind app I hack on makes it harder for me to couple CSS to a JS component.
> Apologies for reading more into your article than it was trying to say.
<3 (Nothing wrong with reading in, but thanks nonetheless.)
> You're probably right that we're talking past each other ... I don't believe that the distinction between a website and a document is particularly clear on a conceptual level. Those things are muddled on the web because they are actually muddled in real life, there isn't a clear distinction between a document and an application -- and often it makes sense to treat them as the same thing.
Part of the trouble here is that document is an overloaded term (there's a reason why the linked post has a full section on what is and isn't the document). You may be disagreeing with where I'm choosing to draw the lines here, and that's... okay. I suspect this is mostly coming down to perspective.
Categorizing isn't my natural mode. The world is a mess of gray, and a single language closing over both interfaces and documents is necessarily so.
(At the risk of projecting...) I get the sense you're seeing this from something like the context of what I called the "html-concrete document". From that perspective it's mostly unclear what bits are an interface and what bits are documents (and whether there's one document or N of them, etc.). They're all already muddled in the concrete document. (If you step up to considering several html-concrete documents on the same site, I guess you could use template induction to work towards understanding.)
The perspective I'm coming at this from is concerned with how we can author marked-up documents to maximize reusability. This perspective is concerned with, as the post said, "the one closest to the document in the eyes of the author" which I called "an abstract-document". I think this is conceptually clear (but it may not be clear to anyone but the author).
> So sure, of course HTML and CSS often change in parallel, but... so?
I didn't say it was a problem that they change in parallel--just that this change is a sign that the interface-html and interface-css are already tightly coupled. I'm not arguing for more or less coupling between them, but pointing out that a fraction of the global html/css/js namespaces are comprised of tightly-coupled code structure/style/behavior that comprise "the interface" (as the interface designer sees it) almost certainly co-mingled with structure/style/behavior for stuff that isn't the interface (where they can all unintentionally clash).
> This is another thing where I feel like there must be something I'm missing because if you said this in isolation without mentioning Tailwind, I think I'd agree with it.
These are separate ideas (hence the aside). I'm not arguing that Tailwind is component oriented. The component folks, and the Tailwind folks, and the BEM folks (and many more folks trying different things!) are all reacting to problems caused by the status quo separation of concerns. The component folks are more directly trying to rectify the mismatch, but they're all still patching around deficiencies in the stack.
> I've used Tailwind for a little while now (maybe not heavily enough, I don't know?) -- I don't think Tailwind is very component-oriented. It's component-oriented in the strictest sense that you put styles on a component. But it doesn't encourage building logical units of style, it doesn't encourage reuse, it doesn't encourage structuring of style, it makes it harder to look at the output and understand where a style is coming from or what part of the code set it.
I could probably clarify that I find the Tailwind style a bit revolting, and set about writing the linked piece in part to dunk on it (among others). In the process of pulling things apart to understand them, though, I felt like I could see the problems it's reacting against. It's a ~reasonable way to make lemonade, even if I don't like it.
> Most of the time I see Tailwind it's just attached directly to HTML like an inline style.
This is both a thing I personally find revolting about Tailwind, and a big part of the value/leverage I think Tailwind users are reaching for.
> And if I came to you and said I was going to stop using functions and just inline all of my code, you wouldn't characterize that as "component-based programming".
Maybe reframing this function/inline analogy a bit will help clarify?
If you showed me a 2000-line function, I'd ask the obvious question about why you didn't abstract it out into multiple units with meaningful names.
But if you responded by explaining that this code was destined for a global namespace where there was a real risk of code written by others also defining/overwriting/wrapping the identifiers you chose, we'd end up having a similar conversation about the ways around. You could hand-namespace all of the identifiers and make human reviewers keep up. You could introduce tooling to namespace identifiers to avoid clashes. You could try to engineer in stronger component boundaries. You could indeed choose to inline as much as possible.
I would say I'm not a huge fan of the inlining approach because it's a mess to read, but if you countered that you were extremely confident that the code was stuffed with implementation quirks so tightly coupled to something in the stack that it would almost certainly not be reusable elsewhere and would almost certainly be faster to rewrite from scratch than understand and refactor... I wouldn't call you crazy.
Thank you for this discussion and article, both were an interesting read!
One tiny criticism regarding the article: I was hoping you would actually color code the HTML code samples visually, I believe it would have aided understanding better. You could have even used a more realistic/concrete sample as well.
In 2021 I prototyped some documentation single-sourcing tools. I made leaps fueled by intuition and years of frustration, so I found it hard to explain to others what I did and why.
In early 2022 I started sketching this post as ~intellectual-groundwork on the ~motivating problems I saw in existing markup languages. What I hoped would be a few weeks stretched into several months of drafts I wasn't happy with.
Trying to write one _coherent_ motivating post made it clear just how many iterative intuitive leaps I'd made along the way, so I started splitting out asides/sections into posts to make incremental progress and show my math. (The linked post is currently the most-recent of 6 on documentation at https://t-ravis.com/room/doc/; the other 5 have seeds in it.)
Color-coding the examples was indeed on the to-do list from early on, but after starting over a few times and still feeling unsure it would communicate, I got frustrated enough (exacerbated by unrelated ~burnout) to just shove it out the door and turn to other fires for a while. (Part of why I haven't made a follow-up post, even though I intend to.) It's been better received than I feared, so it probably makes sense to go back and improve those when I start the next post in the series.
I adopted Tailwind but I did it in I think a way that would make the creator of Tailwind crazy. But it’s for a project only I work on, so meh.
I’ve found that even with components that can do their own scoping, it becomes easier to use a semantic class name. Because I’ll create a component, and then later want to use it in a different way I didn’t originally consider. If you don’t have a semantic class name applying overrides becomes difficult.
What I end up doing is designing things in browser, because it’s so quick. And then I slowly abstract it out into a class with @apply rules, but I have my own way that I like to group them. So like one line will be for typography, one will be for layout. It’s so much less verbose than regular CSS I find it really easy to read and change quickly.
But I also know CSS really well, so I can quickly scan the shorthand and understand exactly what it’s doing. Tailwind is the first time I’ve ever willingly used a CSS framework because it just clicks for me, but I don’t use it the way it’s “meant” to be used. Also the defaults for things like text sizing etc… help keep me standardized somewhat. It reduces the number of options and in a good 70% of cases prevents me from spending hours obsessively changing the first or second decimal point of a number and trying to decide if something looks better being 1 pixel to the left (or sometimes a half or quarter pixel )
I think it’s an interesting question - what should the goal of a CSS “framework” be?
Because in the past, CSS struggled with achieving basic common layouts without using hacks. That’s why Bootstrap and its grid system were so popular.
But that’s not an issue anymore. Tailwind doesn’t hide much behind abstractions. So many times as a programmer, I’ve been forced to adopt tooling that promises to make something easier, only to have issues with the tooling, or it having its own learning curve etc… outweigh any benefit.
Tailwind is just easy, and it’s the first time I’ve encountered something that actually rewards underlying knowledge instead of trying to prevent the user from needing it.
DevOps is similar to agile. Originally they both described a set of principles, an ethos, not a specific role. DevOps was your development team work closely with ops as one team, using software engineering practices, config as code etc etc.
Then, it just came another name for sysadmin and later platform teams and back to where it all started, passing things over the wall from engineering to platforms.
> Originally they both described a set of principles, an ethos, not a specific role.
The way I understood DevOps (back from the first DevOps Days in Ghent) is that clear separation of sysadmin and developer roles harms the process of software delivery and that developers should maintain their code up to production, and learn from the process.
It was, in a way, a critique of the project-driven business where teams ship and jump over the board.
When it first started doing this I found it be to more tear down the moat many developers like to put between them and the rest of the business. Basically get up and go talk to QA, helpdesk, delivery, and marketing. Find out what is failing and fix that. Make sure those groups can use and maintain the code being delivered. THEN work on things that are new or champion those things that are broken to get fixed in the next cycle. That was devops to me.
Then it turned into this guy who can not really do anything. Can not really check in code because the devs do that (separation of duties). So you never get any real experience in the codebase. Can not make any decisions because the marketing/product owners do that. Can not really make better test cases as that is for QA. You can however help on the helpdesk they are short 3 people today. Then the meetings. Endless meetings upon meetings. Because your 'devops' you need to know everything that is going on and better have those statuses on the high priority items to be fixed. Oh and you are 'on call' so you can never really 'go home'. Then if something breaks all you can do is just call in others and make them fix it. Making you little more than tier 3 helpdesk. Useless paper pusher job with zero authority.
The problem is, however, that those two roles require different knowledge, skills, attitudes and mindsets, and so many (most?) developers don't really like sysadminning: you know, messing with VLANs, DNS resolving, packet routing, gluing two networks (one in Sidney, second one in New York) into one via VPN, watching disk quotas and memory limits, working around bugs in Linux scheduler, pinning CPUs, all that mind-bogglingly boring (but needed for smooth operation) stuff.
I enjoy making sure software works for people, the more people the better. If that involves all that sysadminning, I will enjoy that as well.
But most of my peers are oblivious to the fact whether their code will be used at all and are having fun filling their heads with complex abstractions right before spitting them on screen.
Yeah, that was it. And like Agile, it sounds good on paper.
Point is, once developers start doing support, they stopped taking those learnings and going back and developing better. Instead the organization just started having developers do support. But then, why are the support people these highly paid developers, lets change the role definition again to not need to code.
Seems like on-going title shuffle, around, we don't really want to pay to develop, why can't we get by with no-code.
In the UK they are called “breakers” i.e. motor breakers, bike breakers, car breakers etc.
Since the early 2000s I’ve been buying used vehicle parts from these off eBay. One of my local shops closed the physical store and went eBay only in 2000s as that is where most of his business came from so a physical shop was costing to much.
This “new” phenomenon has been happening for 20+ years. Selling used parts has existed way before that also except you’d have to phone around and get the part shipped instead of search online.
A lot of the news I see related to Canadas property issues is related to pension funds owning a large amount of property so using their size to constantly rotate tenants then increasing prices for new tenants.
rotate tenants? looks like another case for weak renter protection. in germany you can't terminate a renters contract unless you evict them. time limited rent contracts are only allowed if the property is not available for rent after the time limit ends.
That’s the thing. A home should not be an “investment”, it should be a “home”, a home to live and give safety/security, not land, bricks and mortar someone purchases to make a capital gain or rental yield.
Why do people want a “home”? It provides a security renting doesn’t, you can make it your home.
Renting can be more flexible if you are nomadic, it can also be a huge pain dealing with leases, rental increases, dodgy landlords, a lack of security so can’t truly settle on a 12 month lease.
I agree buying a home should not be seen as an investment. I just mention that because it feel like everyone I talk to treats it like or talks about it like it’s a good investment.
It’s totally fine to buy a home if you want to own a home. Sure there are plenty of reasons to want to own a home. But because it’s a great investment is rarely one of the reasons.
To use R2 you’d need to host images/assets separately on their own domain rather than just put a CDN infront of your entire site and forget about it. Putting assets on their own domain isn’t uncommon but for some stuff it can be a big inconvenience with build pipelines/software support.
I’m not sure on R2 specifics but I remember when I wanted vanity names on Cloudflare I.e assets.example.com it was not possible unless you give Cloudflare control over your entire domain, dropping your current nameservers or sign up for an enterprise plan for cname support.
I’ve twenty plus years experience building software on the JVM. From EJB’s of early 2000s to original Spring, then the more recent Spring Boot, a plethora of other JVM tooling. Then I’ve used various languages on top of the JVM, Groovy, Clojure, ETA, Scala. I haven’t used Kotlin only because not had a role that needed it. Then I have a list of non JVM languages, frontend stacks and sysadmin/cloud or as they like to call it DevOps
Scala has been my JVM language of choice for the past ten years.
When I was last applying for jobs my experience with Scala seemed like it was a huge negative for the companies I interviewed at. It was “you’re one of them” and things got frosty after mentioning I’m reasonably experienced in Scala and its functional programming libraries and enjoy it as find I have less bugs.
If I removed Scala from my cv and never mentioned it I got a much more positive experience.
Some of the roles I didn’t mind it going frosty. My red flag radar went up aswell and I got the sense of big balls of mud and I’d probably hate it but needed a job. Some it was a huge disappointment, exciting company, exciting projects, perfect fit skills wise but I was seen as a Scala developer not a great fit for Kotlin as excited as I was to use it because of the companies projects.
Not sure what I’m trying to say but this “not good fit” attitude doesn’t seem uncommon if you have used specific languages/tools/things people interviewing you don’t like or didn’t grok. Tech talks a lot about diversity which is mostly virtue signaling and forget diversity of minds is also good.
> It was “you’re one of them” and things got frosty after mentioning I’m reasonably experienced in Scala and its functional programming libraries and enjoy it as find I have less bugs.
You made people feel bad for not questioning their preconcieved notions... that's a nono! :(
I’m increasingly accidentally clicking ads on Google search. When it happens I’m sure I’m in an A/B test with ads in search results at the bottom of the page blended in to look like results.
Searching for products or manufactures is now increasingly impossible. Almost all the hits are ads for online retailers selling the product with the manufacturer’s page increasingly difficult to find in results.
The other one is everything is now “The best”. Every article surfaced is some low quality SEO post starting with “The best”.
Then tech searches bring up sites that have scraped stack overflow/GitHub duplicating content in a worse UI with ads/pop ups/redirects reminiscent of early 2000s filesharing website download link clicks. How these sites rank higher than the sources is a bit confusing.
Sites like medium locking content up so need to join to read it, Facebook groups killing forums have killed a lot of what made the internet/Google good.
It seems Google has less content it can index as content is locked away in private silos, the only freely searchable content is e-commerce sites and Google makes it money off the ads for ecommerce sites so those get pushed to the top of the rankings.
Given the PR recently with Apple calling people back to the office you would think they’d be leading by example and moving back to in person events again.
That could backfire and work against them if a lot of people caught COVID at the convention... which seems likely considering a lot of people just caught COVID at GDC.
Admittedly anecdotal in nature but gamedev twitter has been chock full of "tested positive after GDC, if you were with me get checked" for the past week.
They have a waterfall of multiple API requests by the browser to display a single page. That means the front end has a bunch of logic to aggregate and piece together requests. This in itself isn’t a big deal, if you move to doing it on the backend you still have the same logic and need to make the same sub requests.
Where it does become problematic is it leads to fat API endpoints sending far more data to the client than is needed. GraphQL lets you choose what fields you query but odds are there’s still data available you can ask for that shouldn’t be asked for and sent to a browser.
If your requests/aggregations are done serverside it gives you a better chance of filtering out data that should never be accessible in the browser. You can also make full use of Cache-Control headers and backend caching.
Creating individual endpoints for web apps went out of fashion as it involves more effort and people don’t like effort to do things well. I see it re-invented recently as backend-for-frontend.
> Creating individual endpoints for web apps went out of fashion as it involves more effort and people don’t like effort to do things well. I see it re-invented recently as backend-for-frontend.
Not true, individual endpoints requires more work for client side optimizations but the CRUD query mapping effort is not reduced with graphql. If anything, graphql endpoints require more effort on the backend side to build because of having to wire up the resolvers unless you are using something like Hasura.
I personally am a fan of schematic html/css. I remember the days off CSS Zen Garden, with well marked up html you can change the visual look completely by swapping out the style sheet. There’s a nice decoupling layer, it’s flexible, it’s conceptually simple, it works.
Despite all that I find myself using Tailwind. I’m not a frontend/designer expert, Tailwind goes against what I believe makes good HTML, Tailwind is ugly to me, polluting classes with markup. It’s equivalent to the embedding inline styles anti pattern. However in an imperfect world it works surprisingly well for visual styling on large projects, with many teams and components and just as well in small single page sites. The perfectionist in me says it’s horrible, the I can’t be bothered with frontend design in me says it’s so much less effort and avoids styling conflicts from multiple style sheets/components and I don’t care if it’s ugly or against the ethos of good html.