HN user

jamamp

153 karma

meet.hn/city/us-San-Diego

Posts0
Comments50
View on HN
No posts found.

I hope people can ask themselves why the goal is "winning" and "winning big", and not making a product that you are proud of. It shouldn't be about VC funding and making money, shouldn't we all be making software to make the world a little bit better? I realize we live in an unfortunate reality surrounded by capitalism, but giving in to that seems shortsighted and dismissive of actual problems.

I think it's valiant to try to do all of this with semantic HTML elements to achieve the right effects, and try to go for a "classless CSS" paradigm to get a nice looking and functional web app (as a fan of classless CSS myself). But scrolling through the component catalog, it unfortunately feels like it's all over the place and inconsistent with semantic vs basic elements, data tags vs aria attributes, and sprinkling some css classes over some of it.

I do very much like that by introducing aria attributes, the CSS reacts to it and styles it appropriately. As opposed to a full-blown react component library which does all of that for you. It would be a good exercise for developers to think aria-first and let the library just help with styling.

Lastly, I think the best part is that this component library has a native sidebar. So many of these I see and they have a nice web page which showcases all the components and I want to replicate their layout and nav/sidebars but they only focus on smaller re-usable components and not the layout. So that's a nice touch, I think. And, as someone who keeps an eye on but doesn't do a lot of frontend, the fact that a sidebar is an aside > nav > ul next to a main just makes so much sense and doesn't have a lot of cruft around it.

Alchemy 8 months ago

I would argue that the author has no obligation to engage with more counter-arguments, or provide something "new" (to you) to the conversation.

This is a blog. Blog posts are a way to show the voice of the author, share their thoughts on the matter, perhaps work through their own thought processes and come to a nice conclusion for themselves that they choose to share with the public.

I would find the internet and the community incredibly dull if the first person to post a criticism was it and everyone else always referred to their article. There'd be no further discussion whatsoever.

I found this article to be enlightening and a wonderful way to frame my disdain for AI-generated art and other content in a framing that I hadn't thought of so explicitly before. The analogy to alchemy is a welcomed and fresh take. I appreciate this article. Perhaps I'm one of today's lucky 10,000 to have made this connection.

I also appreciate this article because the author put effort into it and voiced their opinion. Voicing opinions don't have to be novel, since this isn't academia necessarily where you have to fight for uniqueness and new takes.

Unfortunately that might also be due to how Instagram shows ads, and not necessarily Anthropic's marketing push. As soon as you click on or even linger on a particular ad, Instagram notices and doubles down on sending you more ads from the same provider as well as related ads. My experience is that Instagram has 2-3 groups of ad types I receive which slowly change over the months as the effectiveness wanes over time.

The fact that you are receiving multiple kinds of ads from Anthropic does signify more of a marketing push, though.

Another drawback is the difficulty of learning Typst. The official documentation is confusingly organized, with information scattered unpredictably among "Tutorial", "Reference", and "Guides" sections.

I would have thought that this method of organizing documentation is preferred, as I assumed The Grand Unified Theory of Documentation[0] was well known and liked.

[0] https://docs.divio.com/documentation-system/

Something I wish SCIM did better was break apart group memberships from the user resource. In the realm of SCIM's schema with the ability to have write-only, read/write, and read-only properties it makes a ton of sense to have a user's group memberships read-only and available to look at easily. But sometimes populating the list of groups a member is in can be taxing depending on your user/group db (or SaaS) solution. Especially because this data is not paginated.

SCIM allows clients to ignore the group membership lists via `?excludeAttributes=groups` (or members on the group resource). But not all clients send that by default. Entra does well to only ask for a list of groups or members on resources when it's really needed in my experience.

Some enterprise customers use SCIM with tons of users. Querying for the users themselves is simple because querying users is paginated and you can constrain the results. But returning a single group with 10,000 users in a single response can be a lot. It only really contains the user's identifier and optionally their display name, but if you have to pull this data from a paginated API it'll take a while to respond. Or it could still be taxing on some databases.

It'd be nice to query `/Users/:id/groups` or `/Groups/:id/members in a paginated fashion similar to `/Users`.

Another point: the SCIM schema can be confusing. The RFCs make it seem like you can define your schema however you like, and it provides a default schema with which it bases examples in other parts of the RFC.

In reality, most systems expect you to have the full default schema present without modifications and might complain when items are missing. Do you provide scim support without passwords (only SSO)? Okta will send a password anyway (random and unused). Does your application not differentiate between username and email? IdPs will complain if they can't set them separately. Do you not store the user's `costCenter`? IdPs will get mad and keep trying to set it because it never sticks.

Some of the time, you'll have to store SCIM attributes on your user objects which have no effect on your system at all.

The other side is making custom schema items. SCIM has you present these in the `/Schema` endpoints. But, no system (that I know of) actually looks at your schema to autopopulate items for mapping. Entra and Okta are great at letting your provide mapping from an IdP user to a SCIM user, and then you map SCIM users back to your app's users. But you typically have to follow app documentation to map things properly if it's not using the default schema entirely.

In primarily throwable languages, it's more idiomatic to not include much error handling throughout the stack but rather only at the ends with a throw and a try/catch. Catching errors in the middle is less idiomatic.

Whereas in Go, the error is visible everywhere. As a developer I see its path more easily since it's always there, and so I have a better mind to handle it right there.

Additionally, it's less easy to group errors together. A try/catch with multiple throwable functions catches an error...which function threw it though? If you want to actually handle an error, I'd prefer handling it from a particular function and not guessing which it came from.

Java with type-checked exceptions is nice. I wish Swift did that a bit better.

I like Go's explicit error handling. In my mind, a function can always succeed (no error), or either succeed or fail. A function that always succeeds is straightforward. If a function fails, then you need to handle its failure, because the outer layer of code can not proceed with failures.

This is where languages diverge. Many languages use exceptions to throw the error until someone explicitly catches it and you have a stack trace of sorts. This might tell you where the error was thrown but doesn't provide a lot of helpful insight all of the time. In Go, I like how I can have some options that I always must choose from when writing code:

1. Ignore the error and proceed onward (`foo, _ := doSomething()`)

2. Handle the error by ending early, but provide no meaningful information (`return nil, err`)

3. Handle the error by returning early with helpful context (return a general wrapped error)

4. Handle the error by interpreting the error we received and branching differently on it. Perhaps our database couldn't find a row to alter, so our service layer must return a not found error which gets reflected in our API as a 404. Perhaps our idempotent deletion function encountered a not found error, and interprets that as a success.

In Go 2, or another language, I think the only changes I'd like to see are a `Result<Value, Failure>` type as opposed to nillable tuples (a la Rust/Swift), along with better-typed and enumerated error types as opposed to always using `error` directly to help with error type discoverability and enumeration.

This would fit well for Go 2 (or a new language) because adding Result types on top of Go 1's entrenched idiomatic tuple returns adds multiple ways to do the same thing, which creates confusion and division on Go 1 code.

I'll also agree with you.

I want to start with the fact that building FlowRipples is a monumental feat of its own. Generic tools that are adaptable to lots of situations is a difficult task, and it's impressive what was built.

But the supporting functionality in any service like this is also so important. It's one thing to have a low friction setup and way to get started, with simple steps and a quick showcase video, so that someone can get to tinkering. It's another thing to fully adopt this as a tool within your team that would be integrated into a published product.

Suddenly, like you say, you have multiple environments (Dev, QA, Staging/Pre-prod, Prod) that you have to move changes into and out of. Replicating the same changes manually will inevitably lead to human error and what worked in QA will no longer work in Staging or Production. Even a simple export + import helps with this.

I think one thing that also needs attention is parallel changes. Two people are wokring on different changes in the dev environment. Promoting the current state of the Dev environment to QA requires that both tasks have to be dev-complete, or else unfinished changes could make its way to QA and cause confusion. This is difficult when the different tasks aren't synchronized in their testing (i.e. start testing one ticket but not necessarily the other). It's almost like you need branching and merging and diffing, a la git, to help resolve this. That's difficult to do in low-code visual programming apps.

I wonder how this compares, conceptually, to Temporal? While Temporal doesn't talk about a single centralized log, I feel the output is the same: your event handlers become durable and can be retried without re-executing certain actions with outside systems. Both Restate and Temporal feel, as a developer coding these event handlers, like a framework where they handle a lot of the "has this action been performed yet?" and such for you.

Though to be fair I've only read Temporal docs, and this Restate blog post, without much experience in either. Temporal may not have as much on the distributed locking (or concept of) side of things that Restate does, in this post.

My experience with `prompt=login` is also mixed. Okta's behavior does not indicate which account you're logging into (no username/email address), and only asks to re-input your password. They have a "Back to sign in" link button, but that loses all OAuth context and does not lead you back into the app you're attempting to OAuth into, unless if you specifically override that button to hit Okta's logout endpoint and with a redirect back to your OAuth authorize endpoint/session.

It's janky. And I would know because we had to implement that at work.

Dear Okta, please include your OIDC profile claims in your ID tokens.

Actually no, that's on the spec for not enforcing they're in the ID token, and only must be available in the userinfo endpoint.

I'd like to add that so many providers do not support either `prompt=select_account` or just natively ask the user which account to login to, mainly for OIDC. Working with IAM systems at work and using different test accounts, it's frustrating when you can't easily log out of the destination IdP for, say, SSO.

  Location: San Diego, United States
  Remote: Yes
  Willing to relocate: No
  Technologies: Senior Software Engineer, backend and cloud, Go, .NET, Swift, AWS, Terraform, Web (HTML + frameworks), Okta/IAM/OAuth/OIDC
  Résumé/CV: https://jamesnl.com/resume.pdf
  Email: james.n.linnell@gmail.com
Sanding UI 2 years ago

I think the article has good sentiments about it. Actually using your application a lot helps polish it down a ton.

However, wouldn't putting the input inside of the label (before the label text) be a better solution than fiddling too much with CSS and flexbox? It's more foolproof to ensure clicks within the label activate the input, and eliminates the need for the "for" reference.

  Location: San Diego, United States
  Remote: Yes
  Willing to relocate: No
  Technologies: Senior Software Engineer, backend and cloud, Go, .NET, Swift, AWS, Terraform, Web (HTML + frameworks), Okta/IAM/OAuth/OIDC
  Résumé/CV: https://jamesnl.com/resume.pdf
  Email: james.n.linnell@gmail.com

I remember during the screenwriters guild strikes in the Movie and TV industry, many writers were advocating _not_ to boycott movies/TV. Mainly in order to show that the people still wanted to watch the media that these people were writing for and creating, so that the strike held more legitimacy: we are needed to produce more content for your business.

I suppose sometimes it makes sense to boycott, but not all the time.

I believe this is because the code `counts[word]++` basically works by:

    1. Hash word, retrieve the value from the counts map
    2. Increment the value
    3. Hash word, store the value into the counts map
By change counts to a map of strings to pointers of ints, you only need to perform #3 once per unique word. Once you've read the int pointer, you need only write to the pointer and not re-hash the word and write that to the map, which can be expensive.

https://github.com/benhoyt/countwords/blob/master/optimized....

Swift's `Codable`[0] system seems very similar to serde in this regard. Structs that you define can be marked with the Codable protocol, and the Swift compiler automatically generates code during compilation that encodes from and decodes to the structs properties, with the option for you to customize it using CodingKeys for different properties names or completely custom coding behavior.

It seems built-in to Swift, as opposed to a dynamically executed crate like with serde. I wonder how it's implemented in Swift and if it leads to any significant slowdowns.

[0] https://developer.apple.com/documentation/foundation/archive...

Not only that but here is some of my output:

    $ otool -L AdventOfCode2022
    AdventOfCode2022:
        /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
        /usr/lib/swift/libswiftCore.dylib (compatibility version 1.0.0, current version 5.7.1)
        /usr/lib/swift/libswiftCoreFoundation.dylib (compatibility version 1.0.0, current version 120.100.0, weak)
        /usr/lib/swift/libswiftDarwin.dylib (compatibility version 1.0.0, current version 0.0.0, weak)
        /usr/lib/swift/libswiftDispatch.dylib (compatibility version 1.0.0, current version 17.0.0, weak)
        /usr/lib/swift/libswiftIOKit.dylib (compatibility version 1.0.0, current version 1.0.0, weak)
        /usr/lib/swift/libswiftObjectiveC.dylib (compatibility version 1.0.0, current version 6.0.0, weak)
        /usr/lib/swift/libswiftXPC.dylib (compatibility version 1.0.0, current version 6.0.0, weak)
        /usr/lib/swift/libswiftFoundation.dylib (compatibility version 1.0.0, current version 1.0.0, weak)
Not only does it say that libswiftcore is 5.7.1, but that /usr/lib/swift folder doesn't have any of those files there. Very very confusing. I don't like any of this.

I appreciate your write-up and research into all of this though! I tried googling for what runtime version of Swift is installed in Monterey and couldn't find anything. This is incredibly opaque.

Ah, I forgot that compiling with an SDK version doesn't necessarily mean you get the runtime with it. Dynamic linking instead of static linking. Sometimes, software development gets too complicated; too many things to keep in mind.

I'm confused. The post mentioned that this was fixed in Swift 5.7, but I have Swift 5.7.1 on my macOS Monterey and the bug is still present if I modify my AoC solution to exhibit the problem. Is Swift 5.7.1 on Monterey different from the 5.7.1 on Ventura?

    $ swift -v
    Apple Swift version 5.7.1 (swiftlang-5.7.1.135.3 clang-1400.0.29.51)
    Target: arm64-apple-macosx12.0
I love Swift as a language, but the lack of release notes for 5.7.1 (aside from a blog post for 5.7 as a whole), OS-specific releases (especially for SwiftUI), Xcode removing old toolchains when it upgrades (making me re-download tvOS 15.4 runtime for no reason), and all these other little things are starting to weigh on me.