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

What a mind blowing achievement. Wow!


I think this is also getting at the difference between pub/sub and state synchronization. While one might think they want the former, what they really want is the latter. Get some state and receive updates continuously rather than deal with unreliable stream of updates


On HTTP, pub/sub is eventually guaranteed to drop some messages because TCP/IP itself is not a guaranteed networking protocol (it just makes some promises about failures being uncommon and probably detectable).

If what you want is guaranteed state synchronization, pub/sub alone can't give it to you.


I believe anti trust is triggered when it negatively affects consumers, with Amazon’s aggressive competition consumers usually win. At least short term...


This pattern is called Composition (https://en.wikipedia.org/wiki/Composition_over_inheritance). What makes it much more practical in Go than in say Java is struct embedding and implicit interface implementations


Yes! I find embedded structs to be a really elegant way of doing composition.


Exporting structs doesn't seem like composition to me. It seems much more like multiple inheritance.


It is exactly composition; the compiler just generates the methods to automatically delegate to the anonymous elements. It's just syntax sugar that probably creates more confusion than it alleviates. It's not inheritance of any kind because the outer struct cannot be passed into a function that takes the inner element type (e.g., if you have `type B int` and `type A struct {B}` and `func foo(B) {}`, you can't pass an instance of `A` into `foo()`--`foo(A{B: 0})` is a compiler error.

As it is just composition, it is strictly better than inheritance, but still probably unnecessarily confusing versus just writing out the delegation methods yourself.


>It's not inheritance of any kind because the outer struct cannot be passed into a function that takes the inner element type

My mistake. I was mislead by the blog post.

From the article:

> The new type would be interchangeable with the existing client which would minimize the need for changes to existing code.

So with go exported structs it is not fair to say they can be used interchangeably if at any point that instance is used as a parameter, field, or variable that defines the type?

In the examples given in the article, the thing that is used as parameters is the interface Client not the concrete type HTTPClient. Would that not allow CachedHTTPClient to passed around as if it was a Client and would that not show the same issues as inheritance?


Both types implement the `Client` interface. So either type can be passed into a function that accepts the `Client` interface, but a `CachedHTTPClient` cannot be passed into a function that accepts an `HTTPClient` (you would have to pass the `CachedHTTPClient.HTTPClient`) and of course not vice versa either. You can do the same thing in Java (forgive my syntax):

    public interface Client {
        ArrayList<String> getUsers();
        void createUser(String name);
    }

    public class HTTPClient implements Client {
        public ArrayList<String> getUsers() { /* ... */ }
        public void createUser(String name) { /* ... */ }
    }

    public class CachedHTTPClient implements Client {
        private HTTPClient httpClient;

        public ArrayList<String> getUsers() { /* ... */ }

        // In Go via "struct embedding", this method would be generated
        // automatically; in Java, we have to write it out. NBD.
        public void createUser(String name) { this.httpClient.createUser(name); }
    }


Makes sense. I guess I just don't see how exported types save you from any of the pitfalls of inheritance. In my mind composition is the use of existing types without being forced into a type contract.


Mind you, I don’t advocate for struct embedding, but it doesn’t force you into a type contract. The outer struct retains its type—it is not a subtype of the nested type so it can’t be used in places that take the inner type.

Literally all it does is automatically create methods on the outer struct that delegate to the anonymous member.

Unlike inheritance, there is no fragile base class problem and methods on the inner anonymous member can’t dispatch to methods on the outer struct. Also, the “parent” member is just another field in your struct. You can modify it or replace it at runtime, unlike the parent in OOP languages.


This was my initial idea. However, consider this scenario. I need to boot a web stack (db master, pool of db slaves, webservers and a load balancer). I boot a master, job succeeds, then I boot slaves, job succeeds. I boot webservers, but by this time master is shut down or becomes unavailable. Because of a job-based approach, this will never be detected and fixed by the controller. The chosen approach would detect the state of the environment and determine that a master is missing and proceed to correct the situation or abort the process altogether. Hope this makes sense!


Fundamentally, each of the tasks is a separate job. Why not just order the jobs in an array and start them in order? So if a job at some index needed to be restarted/started for some reason, you would first go through and start everything before it.

More generally, looks like you just form a DAG to map out the dependencies and use it to figure out what to do. The daemon could then periodically traverse the DAG starting from the root to each leaf starting jobs as required. Could you explain why this kind of approach was unfeasible in your scenario?


Well, success of a job is transient and not permanent in this case. Like I mentioned before, successful boot of a dependency doesn't mean that dependency exists by the time we get to boot a host. You need to continuously check the status of your group to determine actions that can be taken for current state. A stateful system that marks a job as complete upon successful execution wouldn't work. DAG computation does happen, but inside MoreHostsCanBeBooted condition that is a pre-requisite for BootMoreHosts action. If what you're proposing is to re-run the same job until target state transition has been achieved and code job in idempotent way, then this is essentially what's being done with the current approach, except there are no jobs, and idempotency is a side-effect of not tracking progress. I hope my explanations make sense :)


Thanks for feedback. Indeed, complex emergent behaviors are not demonstrated in the provided example. But they are possible when changes in environment affect other control loops. Which might result in conflicts, at which point control loop for conflict resolution can be added, this is why MAPE-K tower is a useful abstraction.


You are right, however C bindings in other languages usually look quite ugly and non-idiomatic, but ZeroMQ did great job in that sense and their higher level language bindings are written with language specifics in mind


Haha, I know you don't like coffeescript, so I wrote clone client library for demo in pure JS - https://github.com/progrium/nullmq/blob/master/demos/presenc...


it just looks like js generated with coffeescript.. not really the same thing


heh, best I can do yet


it looks like idiomatic javascript to me


NullMQ multiplexing protocol is built on top of STOMP. The main advantage of NullMQ is same socket primitives as ZeroMQ, so same patterns and solutions can be built in the browser.


I'm new to ZeroMQ. Would you be willing to provide a quick example scenario where this might be useful?


I feel the example I built for our demo is a good one. Here I implemented presence and chat servers to build online chatroom. Servers and clients were initially built in Ruby, to be used in a private network behind firewall. I was then able to re-use client code with minimal changes and port it into JavaScript. This client code gave presence and chat to the browser. So effectively we solved an interesting networking problem once and were able to re-use the solution in two vastly different environments - private networks and the browser, where different authentication, authorization, performance and guarantees requirements apply.


Exactly, I'm very happy that message went through!


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

Search: