Hacker Newsnew | past | comments | ask | show | jobs | submit | valzam's commentslogin

Except of course rollout will not be atomic anyway and making changes in a single commit might lead Devs to make changes without thinking about backwards compat


Even if the rollout was atomic to the servers, you will still have old clients with cached old front ends talking to updated front ends. Depending on the importance of the changes in question, you can sometimes accept breakage or force a full UI refresh. But that should be a conscious decision. It’s better to support old clients as the same time as new clients and deprecate the old behavior and remove it over time. Likewise, if there’s a critical change where you can’t risk new front ends breaking when talking to old front ends (what if you had to rollback), you can often deploy support for new changes, and activate the UI changes in a subsequent release or with a feature flag.

I think it’s better to always ask your devs to be concerned about backwards compatibility, and sometimes forwards compatibility, and to add test suites if possible to monitor for unexpected incompatible changes.


This is a systems problem that can and should be fixed in the system IMO, not by relying on devs executing processes in some correct order.


This is where unit testing / integration testing should be implemented as guard rails in my eyes.


Rollout should be within a minute. Let's say you ship one thing a day and 1/3 things involve a backwards-incompatible api change. That's 1 minute of breakage per 3 days. Aka it's broken 0.02% of the time. Life is too short to worry about such things


> Rollout should be within a minute

And if it's not, it breaks everything. This is an assumption you can't make.


You might have old clients for several hours, days or forever(mobile). This has to be taken into account, for example by aggressively forcing updates which can be annoying for users, especially if their hardware doesn't support updating.


Do you have a pixel? On Samsung you cannot share WiFi, Hotspot only works with mobile connections. I learners above that this is possible with pixel phones, makes me want to get one...


Yes, Pixels can definitely do that (I use Graphene). It’s incredible that iPhones are so expensive and yet so limited (can’t share WiFi, terrible file browser…)


Same with iPhone, you can only share mobile connection.


Id argue that this isn't so much a fault of the MCP spec but how 95% of AI 'engineers' have no engineering background. MCP is just an OpenAPI spec. It's the same as any other API. If you are exposing sensitive data without any authz/n that's on the developer.


I mean given the computing devices most people use are you suggesting a large majority of the population switches to ethernet adapter's for their tablets and phones?


No, not remotely? I don’t know why folks jump to that (wrongest) conclusion whenever someone mentions ethernet being made a requirement in construction or use.

Can tablets and phones use ethernet? Yes! Should they? Perhaps for a fixed installation, but otherwise no, because that’s not their primary role? Same goes for laptops: if it’s stationary, plug it in; if not, WiFi is fine.

The goal is to shift traffic where reasonable and practical onto wired networks. Desktops, laptops, set top boxes, streaming rigs, control panels, SBCs, game consoles, the list goes on. The only “Wi-Fi required” devices are really just laptops, phones, tablets, watches, and similarly high-mobility devices.

Otherwise, ethernet should be the norm.


Having to blast wifi through an entire building is part of the problem. If transceivers only need enough power to go a foot or three from an ethernet port with a wifi dongle on it, the problem is solved.

See also: cell phones having to boost power for more distant towers.

As things are, every device has to scream to be heard.


Wireless ethernet adapters


I assume this is similar to Ray?


The code example is very similar to Ray.

Monarch:

  class Example(Actor):
     @endpoint
     def say_hello(self, txt):
         return f"hello {txt}"

  procs = this_host().spawn_procs({"gpus": 8})
  actors = procs.spawn("actors", Example)
  hello_future = actors.say_hello.call("world")
  hello_future.get()
Ray:

  @ray.remote(num_gpus=1)
  class Example:
      def say_hello(self, txt):
          return f"hello {txt}"

  actors = [Example.remote() for _ in range(8)]
  hello_object_refs = [a.say_hello.remote("world") for a in actors]
  ray.get(hello_object_refs)


I'm also curious what's the use case of this over Ray. Tighter integration with PyTorch/tensors abstractions?


That.

Also, it has RDMA. Last I checked, Ray did not support RDMA.

There are probably other differences as well, but the lack of RDMA immediately splits the world into things you can do with ray and things you cannot do with ray


Not currently, but it is being worked on https://github.com/ray-project/ray/issues/53976.


There's also Dask, which can do distributed pandas and numpy operations etc. However it was originally developed for traditional HPC systems and has only limited support for GPU computing. https://www.dask.org/


I had the same thought, especially because of their recent collaboration.

https://pytorch.org/blog/pytorch-foundation-welcomes-ray-to-...


Great list of why one can love and hate Go. I really did enjoy writing it but you never get the sense that you can be truly certain your code is robust because of subtle behaviour around nil.


As a Go learner, the best explanation that has made sense to me is that interface types essentially just compose two pointers:

P1: The type and its method vtable

P2: The value

Once I understood that I could intuit how a nil Foo was not a nil Bar and not an untyped nil either


ah yes of course - key semantics of `nil` should totally depend on deep implementation details in my language's runtime.

willem-dafoe-head-tap.gif


I guess as a corollary, Go really rewards writing the dumbest code possible. No advanced type shenanigans, no overuse of interfaces, no complex composition of types. Then you will end up with a very fast, resource light system that just runs forever.


And code with zero ability to do fancy trickery ("expressive" as some people like to say) is easy to read even if the codebase - or even the language - is unfamiliar.

Which is really handy when shit's on fire and you need to find the error yesterday. You can just follow what happens instead of trying to figure out the cool tricks the original programmer put in with their super-expressive language.

Yes, the bug is on line 42, but it does two dozen things on the single line...


I know it's not exclusive to Go or any language, but you can most certainly write incomprehensible code in it. If anything, expressiveness and proper abstractions can save you from this.

I think people often get burnt by bad abstractions in expressive languages, but it's not a problem of the language, but the author's unfamiliarity with the tools at their disposal.

If someone starts being clever with abstractions before understanding the fundamentals, it can lead to badly designed abstractions.

So I guess if there's less things to master, you can start designing good abstractions sooner.

So, in my experience, if we invest time to truly understand the tools at our disposal, expressive languages tend to be a great boon to comprehension and maintenance.

But yes, there's definitely been times early in my career where I abstracted before I understood, or had to deal with other bad abstractions


I like to say this: "Only my code is allowed to be clever"

But, on a serious note, I agree with you. Go lacks a lot of power, especially in its type system, that causes a ton of problems (and downtime) that in other languages is trivial to prevent statically.


Formal proof languages are pretty neat, but nobody really uses them in the real world. Among the languages that people actually use on a normal basis, even those that claim to have extensive type systems, they still rely on testing for most everything, and once you're relying on testing anyway the type system isn't any kind of real saviour.

There is, perhaps, some segment of the developer community who believe that they are infallible and don't need to write tests, but then have the type system exclaim their preconceived notions are wrong, and then come to love the type system for steering them in a better direction, while still remaining oblivious to all the things the incomplete type system is unable to statically assert. But that's a rather bizarre place to be.


Typescript’s type system is a huge leap up from JavaScript.

You still need tests for functionality (this function does what it should) but the type system removes many error cases automatically.


It is a huge boost in developer ergonomics.

But doesn't change the tests you need to write, and those tests are going to incidentally cover anything the type system is also going to catch, so the type system isn't going to somehow make your software more reliable.

A much more expressive type system can get you there, but you won't find that in any language anyone actually uses on a normal basis.


out of curiosity (not meant snidely), do you have an example of a case where the weaker type system resulted in serious problems?


Pretty much any null pointer deference error ever?

But it is hardly ever the weak type system that is at fault, just good use of a stronger type system could have prevented the issue.

Once you start to make "invalid states unpresentable" and enforcing those states at the edges of your type system suddenly a lot of bizarre errors don't happen anymore.


NPEs are also present in a lot of languages with "stronger" type systems though. Is there a specific language you're comparing against?


>it's not a problem of the language, but the author's unfamiliarity with the tools at their disposal.

If you have to share a codebase with a large group of people with varying skill levels, limiting their ability to screw up can definitely be a feature, which a language can have or lack.

As always, it comes with tradeoffs. Would you rather have the ability to use good, expressive abstractions or remove the group’s ability to write bad ones? It probably depends on your situation and goals.


>most certainly write incomprehensible code in it

I've tried my best to make indecipherable go code and failed. Do you have any examples?


> And code with zero ability to do fancy trickery ("expressive" as some people like to say) is easy to read even if the codebase - or even the language - is unfamiliar.

A mate of mine did Comp Sci back in uni when First Years were taught Turbo Pascal showed me some, when I was still doing stuff in ZX Spectrum BASIC and Z80 assembler in high school. It was immediately clear what was going on, even if the syntax was a bit unfamiliar.

By contrast I've had to sit and pick apart things with strings and strings of ternary operators in the same expression, as part of case structures that relied on fallthrough, because someone wanted to show how clever they were.

My Pascal-using mate called stuff like that "Yngwie Malmsteen Programming". It's a phrase that's stuck with me, over 30 years later.

Don't do that "WEEDLYWEEDLYWEEDLY" shit. You're just showing off.


I always reiterate to junior programmers that you write as clever code as you want.

On your own time.

When you're writing code for work, stuff that other people have to eventually read and understand, you be as boring as possible. Skip all the tricks and make code readable, not cute. Someone might have to understand and fix it at 3 in the morning while everything is on fire.

  > Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.


I worked with a guy who hated comments. Twice a week or so he'd be "working from home" for some damn reason or another, and he'd spend the day removing all the comments from a massive and tangled PHP codebase. PHP4, at that, to give you a sense of how long ago.

Anyway his argument was "but the code should be obvious! You shouldn't need comments to explain what the code does!"

Yes Robert, but you need comments to explain what the code expects to do stuff to, and why you want that.

Turns out that removing the "Development Manager" as he styled himself's write access to the Subversion repository causes ripples in the fabric of reality right up to the C suite, but I could back my decision up with solid evidence that he was causing more problems than he was solving.


Yeah, so pretty much every large project has concurrency bugs in Go. Because before generics, there was no way to write a parallel for-each loop without shooting yourself in the foot a couple of times.

Go is simple just like assembly is simple.


You could say the same thing about any language. Writing "dumb" code is easier to understand especially in the small. But Go with function that take functions and return functions, channels and generics, can quickly look as complex as other languages.


Oh boi, all my RW mutexes for maps across goroutines would disagree.


Use sync.Map or create simple wrapper to control access.


… the documentation for sync.Map literally says:

> The Map type is specialized. Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.

The documentation basically says that it's optimized for some cases that wouldn't affect the complaint above.


Well, sync.Map is based on atomics which comes with limitations on its own as you have to use specific (potentially conflicting) hash keys for it.

What I wanted to point towards with my earlier comment is that sync.Map doesn't use resource based mutexes, it uses one mutex for everything which will always be the slowest case.

There's no real borrowing concept in Go, as there would be in Rust for that case, and if you argue that simplicity should be preferred then normal map[] should be threadsafe by default, which, in return, likely will require compile time expansion because of generics.

The core value of Go's "we want simplicity" approach always feels like it's a facade, because there is so many exceptions and footguns along the way. These footguns almost always were conscious decisions where they could have made a decision to break legacy behavior for better simplicity but decided that this is not what they want, which is weird as it's not fitting the initial language design promise.


If you want to be pedantic, you can use https://github.com/puzpuzpuz/xsync which has generics and is faster than native sync.Map


To be fair, checking if an interface is nil is very dumb code, and the fact that it doesn't work is one of my biggest gripes with the language. In this case it's clearly the language (creators) who's dumb


Interface is just behavior. That is the main difference from other languages. Go is about "what", not "who". So when you are checking for nil, you are essentially asking whether the variable has any logic it can perform. And that can happen only if some behavior was provided, ie. it is not nil.


> Go really rewards writing the dumbest code possible

Simplicity is hard. You may see it as dumb, other see it as priceless attribute of the language.


And during downtime you could sell space on your train car. Maybe even have an app for it, like uber for trains. Or as commonly know, regular trains.


I very much agree with all of this but do you find your friends reciprocate? Also mid 30s, I keep in touch with a few friends but arguably only 1 or 2 consistently reach out on their own.


There were periods of time - sometimes years - where they didn't. And there were moments I thought I wouldn't be able to keep it going. But they were people I valued enough and had so much shared history with that I just kept trying, and over the years they came to value it more and reciprocated much more. Sometimes people just go through phases in their lives and they don't have the mental space for it. I'm lucky to have always had a lot of mental space and very little stress, which is why it's easier for me personally.

There were cases where the lack of reciprocation was their way of telling me they were done with the friendship, and so it ended. That happens. Happened to me about 5 times.

But there were a lot of others who were just bad at it or distracted and just needed time and needed me to be patient and not hold it against them, and who came back strongly later on.

There was one who I could tell would never change, who just didn't care and didn't know how to be a good friend, and in their case I slowly stopped reciprocating myself and replied less and less until eventually it was just dead by natural causes, me having accepted the loss of the person I wished they were.

And lastly there was one who was going through such a bad time that they kept pushing everyone away during that period, and in the end they overdosed and died. I wish I had done more, even though I tried actively - I could have tried even harder.

I think it just takes life experience to tell the different cases apart without the benefit of hindsight. Life experience and charitable assumptions.


IMO, this doesn't matter much. Ultimately, the only question that matters is "Do I get enough enjoyment/fulfillment spending time with this person to eclipse the work of organizing?" One of my best friends is a horrendous organizer. But when I invite him to things, I never have to ask twice. It's either an immediate "absolutely" or a "that day doesn't work for me, how about this day". And then it's a commitment. No flaking, no repeated rescheduling.


I used to be the one who reached out to everyone. Lack of reciprocity and a general frustration led me to stop keeping in touch with most everyone, which had the obvious outcome.

OTOH, when I see these people after years, it's like no time has passed. OTOOH, in order to be friendly, I have to overcome my general annoyance with their lack of effort.


That's just how it is. Most people are socially passive. Better to just accept that you'll need to take responsibility for sustaining the connections you care about.


For me, It does bother me that some of my friendships I make most, or nearly all of the initiative, but I get so much from the friendship when we do talk / meet up, it's worth it for me to swallow my pride and ignore it. In 99% of cases they aren't deliberately ignoring you, they just got busy, etc.

The friends that make 0 effort however I cut out. You gotta give me something to work with...


Isn't MCP just an OpenAPI spec that everyone agrees on? I don't really get the confusion around it


To be more precise, it's JSON-RPC with service discovery and cli support (CMIIW)


It’s originally an Anthropic spec.


"OpenAPI", not "OpenAI".


Ah, indeed I misread.


I can highly recommend gp.nvim, it has a few features but by default it's just a chat window with a yank-to-chat function. It also supports a context file that gets pasted into every chat automatically (for telling the AI about the tools you use etc)


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: