Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The particular piece of infrastructure I worked on sat in the middle of the search pipeline, between the front-end that served HTML web pages, and the back-end index. This middle piece would request search results from the back-end, tweak them in a bunch of ways, and forward them on.

These "tweaks" could be just about anything. Like: "You searched for Jaguar, but I don't know if you meant the cat or the car. The index decided that pages about the car rank higher so the first three pages of results are about the car. I'm going to pull some results about the cat from page 4 and put them near the top so just in case that's what you really wanted, you'll find it."

Google Search, at least when I worked on it, was composed of a huge number of such tweaks. People were constantly proposing them, testing if they led to an improvement, and shipping them if they do. For a variety of reasons, our middleman server was a great place to implement certain kinds of tweaks.

But what kinds of information are needed for these "tweaks"? Could be anything! It's a general-purpose platform. Search results were annotated with all kinds of crazy information, and any piece of information might be useful in implementing some sort of middleman tweak at some point.

So you couldn't very well say upfront "OK, we're going to put all the info that is only for the frontend into the special 'frontend blob' that doesn't get parsed by the middleman", because you have no idea what fields are only needed by the frontend. In fact, that set would change over time.

> If this were a programming language I would immediately think of row typing to specify the parts that each stage depends on while being agnostic about the rest of the content

Indeed, perhaps one could develop an elaborate system where in the schemas, we could annotate certain fields as being relevant to certain servers. Anywhere else, those fields would be unavailable (but passed through without modification or validation). If you needed the fields in a new place, you change the annotations.

But that sounds... complicated to design and cumbersome to maintain the annotations. Simply banning required fields solved the problem for us, and everything else just worked.



> Indeed, perhaps one could develop an elaborate system where in the schemas, we could annotate certain fields as being relevant to certain servers. Anywhere else, those fields would be unavailable (but passed through without modification or validation). If you needed the fields in a new place, you change the annotations.

I don't think it has to be elaborate. What I was thinking was something more like, in pseudo-C#:

    // the framework's general channel type from which messages are read
    public interface IChannel
    {
        T Read<T>() where T : interface;
    }

    // clients declare the interface they operate on:
    public interface IClientFields
    {
        public int Foo { get; set; }
        public string? Name { get; set; }
    }
    ...
    // client middleware function
    Task MiddlewareFn(IChannel chan)
    {
        var client = chan.Read<IClientFields>();
        ... // do something with client before resuming at next stage
    }
The client's interface type T must simply be a structural subtype of the underlying message type. As long as the underlying format is somewhat self-descriptive with a name and type map, you can perform the necessary checking that only applies locally to the client. Nothing fancy, and the required fields that client cares about are still there and the rest are ignored because they're never referenced. This could return an interface that contains a series of offsets into the data stream, which I believe is how capnproto already works.


Are you saying that each service would need to declare, separately, the subset of fields they operate on, and make sure that those fields are always a strict subset of the overall set of fields the protocol contains?

This essentially means declaring the same protocol multiple times, which seems like a big pain.


Assuming the service is not operating on the whole format, then it's already implicitly depending on the presence of those fields and also implicitly depending on the fact that they are a strict subset of the overall set of fields in the protocol. I'm not sure why making this fact slightly more explicit by having the client add a single interface would be a big pain.

In principle, this also enables type checking the whole pipeline before deployments since the interfaces can be known upfront rather than latent in the code.


Single interface?

In the search infrastructure example I mentioned up-thread, we had hundreds, maybe thousands of schemas involved.


I said a single interface per client, where I'm using "client" as a stage in the pipeline. Each piece of middleware that plugged into this pipeline already implicitly depends on a schema, so why not describe the schema explicitly as some subset of the underlying message?


Typescript has a types like Partial, Pick and Required which lets you work with subsets of fields of an existing type (https://www.typescriptlang.org/docs/handbook/utility-types.h...). Can something like that be built for Protobuf message processing?




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

Search: